xref: /titanic_50/usr/src/cmd/sgs/rtld/common/dlfcns.c (revision 3db3491215579980a91e230cf21b20608fbb8259)
1 /*
2  * CDDL HEADER START
3  *
4  * The contents of this file are subject to the terms of the
5  * Common Development and Distribution License (the "License").
6  * You may not use this file except in compliance with the License.
7  *
8  * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
9  * or http://www.opensolaris.org/os/licensing.
10  * See the License for the specific language governing permissions
11  * and limitations under the License.
12  *
13  * When distributing Covered Code, include this CDDL HEADER in each
14  * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
15  * If applicable, add the following below this CDDL HEADER, with the
16  * fields enclosed by brackets "[]" replaced with your own identifying
17  * information: Portions Copyright [yyyy] [name of copyright owner]
18  *
19  * CDDL HEADER END
20  */
21 
22 /*
23  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
24  * Use is subject to license terms.
25  */
26 
27 /*
28  *	Copyright (c) 1988 AT&T
29  *	  All Rights Reserved
30  */
31 
32 /*
33  * Programmatic interface to the run_time linker.
34  */
35 
36 #include	<sys/debug.h>
37 #include	<stdio.h>
38 #include	<string.h>
39 #include	<dlfcn.h>
40 #include	<synch.h>
41 #include	<limits.h>
42 #include	<debug.h>
43 #include	"_rtld.h"
44 #include	"_audit.h"
45 #include	"_elf.h"
46 #include	"msg.h"
47 
48 /*
49  * Determine who called us - given a pc determine in which object it resides.
50  *
51  * For dlopen() the link map of the caller must be passed to load_so() so that
52  * the appropriate search rules (4.x or 5.0) are used to locate any
53  * dependencies.  Also, if we've been called from a 4.x module it may be
54  * necessary to fix the specified pathname so that it conforms with the 5.0 elf
55  * rules.
56  *
57  * For dlsym() the link map of the caller is used to determine RTLD_NEXT
58  * requests, together with requests based off of a dlopen(0).
59  * For dladdr() this routines provides a generic means of scanning all loaded
60  * segments.
61  */
62 Rt_map *
63 _caller(caddr_t cpc, int flags)
64 {
65 	Lm_list *	lml;
66 	Listnode *	lnp;
67 
68 	for (LIST_TRAVERSE(&dynlm_list, lnp, lml)) {
69 		Aliste	idx;
70 		Lm_cntl	*lmc;
71 
72 		for (ALIST_TRAVERSE(lml->lm_lists, idx, lmc)) {
73 			Rt_map	*lmp;
74 
75 			for (lmp = lmc->lc_head; lmp;
76 			    lmp = NEXT_RT_MAP(lmp)) {
77 				Mmap	*mmap;
78 
79 				/*
80 				 * Traverse this objects mappings testing
81 				 * whether the pc falls within its range.
82 				 */
83 				for (mmap = MMAPS(lmp); mmap->m_vaddr; mmap++) {
84 					if ((cpc >= mmap->m_vaddr) && (cpc <
85 					    (mmap->m_vaddr + mmap->m_msize)))
86 						return (lmp);
87 				}
88 			}
89 		}
90 	}
91 
92 	/*
93 	 * No mapping can be determined.  If asked for a default, assume this
94 	 * is from the executable.
95 	 */
96 	if (flags & CL_EXECDEF)
97 		return ((Rt_map *)lml_main.lm_head);
98 
99 	return (0);
100 }
101 
102 #pragma weak _dlerror = dlerror
103 
104 /*
105  * External entry for dlerror(3dl).  Returns a pointer to the string describing
106  * the last occurring error.  The last occurring error is cleared.
107  */
108 char *
109 dlerror()
110 {
111 	char	*error;
112 	Rt_map	*clmp;
113 	int	entry;
114 
115 	entry = enter(0);
116 
117 	clmp = _caller(caller(), CL_EXECDEF);
118 
119 	error = lasterr;
120 	lasterr = (char *)0;
121 
122 	if (entry)
123 		leave(LIST(clmp), 0);
124 	return (error);
125 }
126 
127 /*
128  * Add a dependency as a group descriptor to a group handle.  Returns 0 on
129  * failure, ALE_EXISTS if the dependency already exists, or ALE_CREATE if it
130  * is newly created.
131  */
132 int
133 hdl_add(Grp_hdl *ghp, Rt_map *lmp, uint_t flags)
134 {
135 	Grp_desc	*gdp;
136 	Aliste		idx;
137 	int		found = ALE_CREATE;
138 	uint_t		oflags;
139 
140 	/*
141 	 * Make sure this dependency hasn't already been recorded.
142 	 */
143 	for (ALIST_TRAVERSE(ghp->gh_depends, idx, gdp)) {
144 		if (gdp->gd_depend == lmp) {
145 			found = ALE_EXISTS;
146 			break;
147 		}
148 	}
149 
150 	if (found == ALE_CREATE) {
151 		Grp_desc	gd;
152 
153 		/*
154 		 * Create a new handle descriptor.
155 		 */
156 		gd.gd_depend = lmp;
157 		gd.gd_flags = 0;
158 
159 		/*
160 		 * Indicate this object is a part of this handles group.
161 		 */
162 		if (aplist_append(&GROUPS(lmp), ghp,
163 		    AL_CNT_GROUPS) == 0)
164 			return (0);
165 
166 		/*
167 		 * Append the new dependency to this handle.
168 		 */
169 		if ((gdp = alist_append(&ghp->gh_depends, &gd,
170 		    sizeof (Grp_desc), AL_CNT_DEPENDS)) == 0)
171 			return (0);
172 	}
173 
174 	oflags = gdp->gd_flags;
175 	gdp->gd_flags |= flags;
176 
177 	if (DBG_ENABLED) {
178 		if (found == ALE_CREATE)
179 			DBG_CALL(Dbg_file_hdl_action(ghp, lmp, DBG_DEP_ADD,
180 			    gdp->gd_flags));
181 		else if (gdp->gd_flags != oflags)
182 			DBG_CALL(Dbg_file_hdl_action(ghp, lmp, DBG_DEP_UPDATE,
183 			    gdp->gd_flags));
184 	}
185 	return (found);
186 }
187 
188 /*
189  * Allocate a handle and record its existence on the handle list for future
190  * verification.
191  */
192 Grp_hdl *
193 hdl_alloc()
194 {
195 	Grp_hdl	*ghp;
196 	uint_t	ndx;
197 
198 	if ((ghp = calloc(sizeof (Grp_hdl), 1)) == 0)
199 		return (0);
200 
201 	/* LINTED */
202 	ndx = (uintptr_t)ghp % HDLIST_SZ;
203 
204 	if (list_append(&hdl_list[ndx], ghp) == 0) {
205 		free(ghp);
206 		return (0);
207 	}
208 	return (ghp);
209 }
210 
211 /*
212  * Create a handle.
213  */
214 Grp_hdl *
215 hdl_create(Lm_list *lml, Rt_map *nlmp, Rt_map *clmp, uint_t hflags,
216     uint_t ndflags, uint_t cdflags)
217 {
218 	Grp_hdl	*ghp = 0, *_ghp;
219 	APlist	**alpp;
220 	Aliste	idx;
221 
222 	/*
223 	 * For dlopen(0) the handle is maintained as part of the link-map list,
224 	 * otherwise it is associated with the referenced link-map.
225 	 */
226 	if (hflags & GPH_ZERO)
227 		alpp = &(lml->lm_handle);
228 	else
229 		alpp = &(HANDLES(nlmp));
230 
231 	/*
232 	 * Objects can contain multiple handles depending on the handle flags
233 	 * supplied.  Most RTLD flags pertain to the object itself and the
234 	 * bindings that it can achieve.  Multiple handles for these flags
235 	 * don't make sense.  But if the flag determines how the handle might
236 	 * be used, then multiple handles may exist.  Presently this only makes
237 	 * sense for RTLD_FIRST.  Determine if an appropriate handle already
238 	 * exists.
239 	 */
240 	for (APLIST_TRAVERSE(*alpp, idx, _ghp)) {
241 		if ((_ghp->gh_flags & GPH_FIRST) == (hflags & GPH_FIRST)) {
242 			ghp = _ghp;
243 			break;
244 		}
245 	}
246 
247 	if (ghp == 0) {
248 		DBG_CALL(Dbg_file_hdl_title(DBG_HDL_CREATE));
249 
250 		/*
251 		 * If this is the first dlopen() request for this handle
252 		 * allocate and initialize a new handle.
253 		 */
254 		if ((ghp = hdl_alloc()) == 0)
255 			return (0);
256 
257 		if (aplist_append(alpp, ghp, AL_CNT_GROUPS) == 0)
258 			return (0);
259 
260 		ghp->gh_refcnt = 1;
261 		ghp->gh_flags = hflags;
262 
263 		/*
264 		 * A dlopen(0) handle is identified by the GPH_ZERO flag, the
265 		 * head of the link-map list is defined as the owner.  There is
266 		 * no need to maintain a list of dependencies, for when this
267 		 * handle is used (for dlsym()) a dynamic search through the
268 		 * entire link-map list provides for searching all objects with
269 		 * GLOBAL visibility.
270 		 */
271 		if (hflags & GPH_ZERO) {
272 			ghp->gh_ownlmp = lml->lm_head;
273 			ghp->gh_ownlml = lml;
274 		} else {
275 			ghp->gh_ownlmp = nlmp;
276 			ghp->gh_ownlml = LIST(nlmp);
277 
278 			if (hdl_add(ghp, nlmp, ndflags) == 0)
279 				return (0);
280 
281 			/*
282 			 * Indicate that a local group now exists.  This state
283 			 * allows singleton searches to be optimized.
284 			 */
285 			if ((hflags & GPH_LDSO) == 0)
286 				LIST(nlmp)->lm_flags |= LML_FLG_GROUPSEXIST;
287 		}
288 	} else {
289 		/*
290 		 * If a handle already exists, bump its reference count.
291 		 *
292 		 * If the previous reference count was 0, then this is a handle
293 		 * that an earlier call to dlclose() was unable to remove.  Such
294 		 * handles are put on the orphan list.  As this handle is back
295 		 * in use, it must be removed from the orphan list.
296 		 *
297 		 * Note, handles associated with a link-map list itself (i.e.
298 		 * dlopen(0)) can have a reference count of 0.  However, these
299 		 * handles are never deleted, and therefore are never moved to
300 		 * the orphan list.
301 		 */
302 		if ((ghp->gh_refcnt++ == 0) &&
303 		    ((ghp->gh_flags & GPH_ZERO) == 0)) {
304 			uint_t	ndx;
305 
306 			/* LINTED */
307 			ndx = (uintptr_t)ghp % HDLIST_SZ;
308 
309 			list_delete(&hdl_list[HDLIST_ORP], ghp);
310 			(void) list_append(&hdl_list[ndx], ghp);
311 
312 			if (DBG_ENABLED) {
313 				Aliste		idx;
314 				Grp_desc	*gdp;
315 
316 				DBG_CALL(Dbg_file_hdl_title(DBG_HDL_REINST));
317 				for (ALIST_TRAVERSE(ghp->gh_depends, idx, gdp))
318 					DBG_CALL(Dbg_file_hdl_action(ghp,
319 					    gdp->gd_depend, DBG_DEP_REINST, 0));
320 			}
321 		}
322 	}
323 
324 	/*
325 	 * Keep track of the parent (caller).  As this object could be opened
326 	 * by different parents, this processing is carried out every time a
327 	 * handle is requested.
328 	 */
329 	if (clmp && (hdl_add(ghp, clmp, cdflags) == 0))
330 		return (0);
331 
332 	return (ghp);
333 }
334 
335 /*
336  * Initialize a handle that has been created for an object that is already
337  * loaded.  The handle is initialized with the present dependencies of that
338  * object.  Once this initialization has occurred, any new objects that might
339  * be loaded as dependencies (lazy-loading) are added to the handle as each new
340  * object is loaded.
341  */
342 int
343 hdl_initialize(Grp_hdl *ghp, Rt_map *nlmp, int mode, int promote)
344 {
345 	Aliste		idx;
346 	Grp_desc	*gdp;
347 
348 	/*
349 	 * If the handle has already been initialized, and the initial object's
350 	 * mode hasn't been promoted, there's no need to recompute the modes of
351 	 * any dependencies.  If the object we've added has just been opened,
352 	 * the objects dependencies will not yet have been processed.  These
353 	 * dependencies will be added on later calls to load_one().  Otherwise,
354 	 * this object already exists, so add all of its dependencies to the
355 	 * handle were operating on.
356 	 */
357 	if (((ghp->gh_flags & GPH_INITIAL) && (promote == 0)) ||
358 	    ((FLAGS(nlmp) & FLG_RT_ANALYZED) == 0)) {
359 		ghp->gh_flags |= GPH_INITIAL;
360 		return (1);
361 	}
362 
363 	DBG_CALL(Dbg_file_hdl_title(DBG_HDL_ADD));
364 	for (ALIST_TRAVERSE(ghp->gh_depends, idx, gdp)) {
365 		Rt_map *	lmp = gdp->gd_depend;
366 		Aliste		idx1;
367 		Bnd_desc	*bdp;
368 
369 		/*
370 		 * If this dependency doesn't indicate that its dependencies
371 		 * should be added to a handle, ignore it.  This case identifies
372 		 * a parent of a dlopen(RTLD_PARENT) request.
373 		 */
374 		if ((gdp->gd_flags & GPD_ADDEPS) == 0)
375 			continue;
376 
377 		for (APLIST_TRAVERSE(DEPENDS(lmp), idx1, bdp)) {
378 			Rt_map		*dlmp = bdp->b_depend;
379 
380 			if ((bdp->b_flags & BND_NEEDED) == 0)
381 				continue;
382 
383 			if (hdl_add(ghp, dlmp,
384 			    (GPD_DLSYM | GPD_RELOC | GPD_ADDEPS)) == 0)
385 				return (0);
386 
387 			(void) update_mode(dlmp, MODE(dlmp), mode);
388 		}
389 	}
390 	ghp->gh_flags |= GPH_INITIAL;
391 	return (1);
392 }
393 
394 /*
395  * Sanity check a program-provided handle.
396  */
397 static int
398 hdl_validate(Grp_hdl *ghp)
399 {
400 	Listnode	*lnp;
401 	Grp_hdl		*lghp;
402 	uint_t		ndx;
403 
404 	/* LINTED */
405 	ndx = (uintptr_t)ghp % HDLIST_SZ;
406 
407 	for (LIST_TRAVERSE(&hdl_list[ndx], lnp, lghp)) {
408 		if ((lghp == ghp) && (ghp->gh_refcnt != 0))
409 			return (1);
410 	}
411 	return (0);
412 }
413 
414 /*
415  * Core dlclose activity.
416  */
417 int
418 dlclose_core(Grp_hdl *ghp, Rt_map *clmp, Lm_list *lml)
419 {
420 	int	error;
421 
422 	/*
423 	 * If we're already at atexit() there's no point processing further,
424 	 * all objects have already been tsorted for fini processing.
425 	 */
426 	if ((rtld_flags & RT_FL_ATEXIT) != 0)
427 		return (0);
428 
429 	/*
430 	 * Diagnose what we're up to.
431 	 */
432 	if (ghp->gh_flags & GPH_ZERO) {
433 		DBG_CALL(Dbg_file_dlclose(LIST(clmp), MSG_ORIG(MSG_STR_ZERO),
434 		    DBG_DLCLOSE_IGNORE));
435 	} else {
436 		DBG_CALL(Dbg_file_dlclose(LIST(clmp), NAME(ghp->gh_ownlmp),
437 		    DBG_DLCLOSE_NULL));
438 	}
439 
440 
441 	/*
442 	 * Decrement reference count of this object.
443 	 */
444 	if (--(ghp->gh_refcnt))
445 		return (0);
446 
447 	/*
448 	 * If this handle is special (dlopen(0)), then leave it around - it
449 	 * has little overhead.
450 	 */
451 	if (ghp->gh_flags & GPH_ZERO)
452 		return (0);
453 
454 	/*
455 	 * This handle is no longer being referenced, remove it.  If this handle
456 	 * is part of an alternative link-map list, determine if the whole list
457 	 * can be removed also.
458 	 */
459 	error = remove_hdl(ghp, clmp, 0);
460 
461 	if ((lml->lm_flags & (LML_FLG_BASELM | LML_FLG_RTLDLM)) == 0)
462 		remove_lml(lml);
463 
464 	return (error);
465 }
466 
467 /*
468  * Internal dlclose activity.  Called from user level or directly for internal
469  * error cleanup.
470  */
471 int
472 dlclose_intn(Grp_hdl *ghp, Rt_map *clmp)
473 {
474 	Rt_map	*nlmp = 0;
475 	Lm_list	*olml = 0;
476 	int	error;
477 
478 	/*
479 	 * Although we're deleting object(s) it's quite possible that additional
480 	 * objects get loaded from running the .fini section(s) of the objects
481 	 * being deleted.  These objects will have been added to the same
482 	 * link-map list as those objects being deleted.  Remember this list
483 	 * for later investigation.
484 	 */
485 	olml = ghp->gh_ownlml;
486 
487 	error = dlclose_core(ghp, clmp, olml);
488 
489 	/*
490 	 * Determine whether the original link-map list still exists.  In the
491 	 * case of a dlclose of an alternative (dlmopen) link-map the whole
492 	 * list may have been removed.
493 	 */
494 	if (olml) {
495 		Listnode	*lnp;
496 		Lm_list		*lml;
497 
498 		for (LIST_TRAVERSE(&dynlm_list, lnp, lml)) {
499 			if (olml == lml) {
500 				nlmp = olml->lm_head;
501 				break;
502 			}
503 		}
504 	}
505 	load_completion(nlmp);
506 	return (error);
507 }
508 
509 /*
510  * Argument checking for dlclose.  Only called via external entry.
511  */
512 static int
513 dlclose_check(void *handle, Rt_map *clmp)
514 {
515 	Grp_hdl	*ghp = (Grp_hdl *)handle;
516 
517 	if (hdl_validate(ghp) == 0) {
518 		eprintf(LIST(clmp), ERR_FATAL, MSG_INTL(MSG_ARG_INVHNDL));
519 		return (1);
520 	}
521 	return (dlclose_intn(ghp, clmp));
522 }
523 
524 #pragma weak _dlclose = dlclose
525 
526 /*
527  * External entry for dlclose(3dl).  Returns 0 for success, non-zero otherwise.
528  */
529 int
530 dlclose(void *handle)
531 {
532 	int		error, entry;
533 	Rt_map		*clmp;
534 
535 	entry = enter(0);
536 
537 	clmp = _caller(caller(), CL_EXECDEF);
538 
539 	error = dlclose_check(handle, clmp);
540 
541 	if (entry)
542 		leave(LIST(clmp), 0);
543 	return (error);
544 }
545 
546 static uint_t	lmid = 0;
547 
548 /*
549  * The addition of new link-map lists is assumed to be in small quantities.
550  * Here, we assign a unique link-map id for diagnostic use.  Simply update the
551  * running link-map count until we max out.
552  */
553 int
554 newlmid(Lm_list *lml)
555 {
556 	char	buffer[MSG_LMID_ALT_SIZE + 12];
557 
558 	if (lmid == UINT_MAX) {
559 		lml->lm_lmid = UINT_MAX;
560 		(void) strncpy(buffer, MSG_ORIG(MSG_LMID_MAXED),
561 		    MSG_LMID_ALT_SIZE + 12);
562 	} else {
563 		lml->lm_lmid = lmid++;
564 		(void) snprintf(buffer, MSG_LMID_ALT_SIZE + 12,
565 		    MSG_ORIG(MSG_LMID_FMT), MSG_ORIG(MSG_LMID_ALT),
566 		    lml->lm_lmid);
567 	}
568 	if ((lml->lm_lmidstr = strdup(buffer)) == 0)
569 		return (0);
570 
571 	return (1);
572 }
573 
574 /*
575  * Core dlopen activity.
576  */
577 static Grp_hdl *
578 dlmopen_core(Lm_list *lml, const char *path, int mode, Rt_map *clmp,
579     uint_t flags, uint_t orig, int *in_nfavl)
580 {
581 	Rt_map	*nlmp;
582 	Grp_hdl	*ghp;
583 	Pnode	*pnp;
584 	Aliste	olmco, nlmco;
585 	Lm_cntl	*lmc;
586 
587 	DBG_CALL(Dbg_file_dlopen(clmp,
588 	    (path ? path : MSG_ORIG(MSG_STR_ZERO)), in_nfavl, mode));
589 
590 	/*
591 	 * Having diagnosed the originally defined modes, assign any defaults
592 	 * or corrections.
593 	 */
594 	if (((mode & (RTLD_GROUP | RTLD_WORLD)) == 0) &&
595 	    ((mode & RTLD_NOLOAD) == 0))
596 		mode |= (RTLD_GROUP | RTLD_WORLD);
597 	if ((mode & RTLD_NOW) && (rtld_flags2 & RT_FL2_BINDLAZY)) {
598 		mode &= ~RTLD_NOW;
599 		mode |= RTLD_LAZY;
600 	}
601 
602 	/*
603 	 * If the path specified is null then we're operating on global
604 	 * objects.  Associate a dummy handle with the link-map list.
605 	 */
606 	if (path == 0) {
607 		Grp_hdl *ghp;
608 		uint_t	hflags = GPH_ZERO, cdflags = GPD_PARENT;
609 		int	promote = 0;
610 
611 		/*
612 		 * Establish any flags for the handle (Grp_hdl).
613 		 *
614 		 *  .	This is a dummy handle (0) that provides for a dynamic
615 		 *	search of all global objects within the process.
616 		 *
617 		 *  .   Use of the RTLD_FIRST flag indicates that only the first
618 		 *	dependency on the handle (the new object) can be used
619 		 *	to satisfy dlsym() requests.
620 		 */
621 		if (mode & RTLD_FIRST)
622 			hflags |= GPH_FIRST;
623 
624 		/*
625 		 * Establish the flags for this callers dependency descriptor
626 		 * (Grp_desc).
627 		 *
628 		 *  .	The explicit creation of a handle creates a descriptor
629 		 *	for the new object and the parent (caller),
630 		 *
631 		 *  .	Use of the RTLD_PARENT flag indicates that the parent
632 		 *	can be relocated against.
633 		 */
634 		if (mode & RTLD_PARENT)
635 			cdflags |= GPD_RELOC;
636 
637 		if ((ghp = hdl_create(lml, 0, clmp, hflags,
638 		    (GPD_DLSYM | GPD_RELOC | GPD_ADDEPS), cdflags)) == 0)
639 			return (0);
640 
641 		/*
642 		 * Traverse the main link-map control list, updating the mode
643 		 * of any objects as necessary.  Call the relocation engine if
644 		 * this mode promotes the existing state of any relocations.
645 		 * crle()'s first pass loads all objects necessary for building
646 		 * a configuration file, however none of them are relocated.
647 		 * crle()'s second pass relocates objects in preparation for
648 		 * dldump()'ing using dlopen(0, RTLD_NOW).
649 		 */
650 		if ((mode & (RTLD_NOW | RTLD_CONFGEN)) == RTLD_CONFGEN)
651 			return (ghp);
652 
653 		for (nlmp = lml->lm_head; nlmp; nlmp = NEXT_RT_MAP(nlmp)) {
654 			if (((MODE(nlmp) & RTLD_GLOBAL) == 0) ||
655 			    (FLAGS(nlmp) & FLG_RT_DELETE))
656 				continue;
657 
658 			if (update_mode(nlmp, MODE(nlmp), mode))
659 				promote = 1;
660 		}
661 		if (promote)
662 			(void) relocate_lmc(lml, ALIST_OFF_DATA, clmp,
663 			    lml->lm_head, in_nfavl);
664 
665 		return (ghp);
666 	}
667 
668 	/*
669 	 * Fix the pathname.  If this object expands to multiple paths (ie.
670 	 * $ISALIST or $HWCAP have been used), then make sure the user has also
671 	 * furnished the RTLD_FIRST flag.  As yet, we don't support opening
672 	 * more than one object at a time, so enforcing the RTLD_FIRST flag
673 	 * provides flexibility should we be able to support dlopening more
674 	 * than one object in the future.
675 	 */
676 	if ((pnp = LM_FIX_NAME(clmp)(path, clmp, orig)) == 0)
677 		return (0);
678 
679 	if (((pnp->p_orig & (PN_TKN_ISALIST | PN_TKN_HWCAP)) || pnp->p_next) &&
680 	    ((mode & RTLD_FIRST) == 0)) {
681 		remove_pnode(pnp);
682 		eprintf(lml, ERR_FATAL, MSG_INTL(MSG_ARG_ILLMODE_5));
683 		return (0);
684 	}
685 
686 	/*
687 	 * Create a new link-map control list for this request, and load the
688 	 * associated object.
689 	 */
690 	if ((lmc = alist_append(&lml->lm_lists, 0, sizeof (Lm_cntl),
691 	    AL_CNT_LMLISTS)) == 0) {
692 		remove_pnode(pnp);
693 		return (0);
694 	}
695 	olmco = nlmco = (Aliste)((char *)lmc - (char *)lml->lm_lists);
696 
697 	nlmp = load_one(lml, nlmco, pnp, clmp, mode,
698 	    (flags | FLG_RT_HANDLE), &ghp, in_nfavl);
699 
700 	/*
701 	 * Remove any expanded pathname infrastructure, and if the dependency
702 	 * couldn't be loaded, cleanup.
703 	 */
704 	remove_pnode(pnp);
705 	if (nlmp == 0) {
706 		remove_cntl(lml, olmco);
707 		return (0);
708 	}
709 
710 	/*
711 	 * If loading an auditor was requested, and the auditor already existed,
712 	 * then the link-map returned will be to the original auditor.  The new
713 	 * link-map list that was initially created, and the associated link-map
714 	 * control list are no longer needed.  As the auditor is already loaded,
715 	 * we're probably done, but fall through in case additional relocations
716 	 * would be triggered by the mode of the caller.
717 	 */
718 	if ((flags & FLG_RT_AUDIT) && (LIST(nlmp) != lml)) {
719 		remove_cntl(lml, olmco);
720 		lml = LIST(nlmp);
721 		olmco = 0;
722 		nlmco = ALIST_OFF_DATA;
723 	}
724 
725 	/*
726 	 * Finish processing the objects associated with this request.
727 	 */
728 	if ((analyze_lmc(lml, nlmco, nlmp, in_nfavl) == 0) ||
729 	    (relocate_lmc(lml, nlmco, clmp, nlmp, in_nfavl) == 0)) {
730 		ghp = 0;
731 		nlmp = 0;
732 	}
733 
734 	/*
735 	 * If this lazyload has failed, and we've created a new link-map
736 	 * control list to which this request has added objects, then remove
737 	 * all the objects that have been associated to this request.
738 	 */
739 	if ((nlmp == 0) && olmco && lmc->lc_head)
740 		remove_lmc(lml, clmp, lmc, olmco, path);
741 
742 	/*
743 	 * Finally, remove any link-map control list that was created.
744 	 */
745 	if (olmco)
746 		remove_cntl(lml, olmco);
747 
748 	return (ghp);
749 }
750 
751 /*
752  * dlopen() and dlsym() operations are the means by which a process can
753  * test for the existence of required dependencies.  If the necessary
754  * dependencies don't exist, then associated functionality can't be used.
755  * However, the lack of dependencies can be fixed, and the dlopen() and
756  * dlsym() requests can be repeated.  As we use a "not-found" AVL tree to
757  * cache any failed full path loads, secondary dlopen() and dlsym() requests
758  * will fail, even if the dependencies have been installed.
759  *
760  * dlopen() and dlsym() retry any failures by removing the "not-found" AVL
761  * tree.  Should any dependencies be found, their names are added to the
762  * FullPath AVL tree.  This routine removes any new "not-found" AVL tree,
763  * so that the dlopen() or dlsym() can replace the original "not-found" tree.
764  */
765 inline static void
766 nfavl_remove(avl_tree_t *avlt)
767 {
768 	PathNode	*pnp;
769 	void		*cookie = NULL;
770 
771 	if (avlt) {
772 		while ((pnp = avl_destroy_nodes(avlt, &cookie)) != NULL) {
773 			free((void *)pnp->pn_name);
774 			free(pnp);
775 		}
776 		avl_destroy(avlt);
777 		free(avlt);
778 	}
779 }
780 
781 /*
782  * Internal dlopen() activity.  Called from user level or directly for internal
783  * opens that require a handle.
784  */
785 Grp_hdl *
786 dlmopen_intn(Lm_list *lml, const char *path, int mode, Rt_map *clmp,
787     uint_t flags, uint_t orig)
788 {
789 	Rt_map	*dlmp = 0;
790 	Grp_hdl	*ghp;
791 	int	in_nfavl = 0;
792 
793 	/*
794 	 * Check for magic link-map list values:
795 	 *
796 	 *  LM_ID_BASE:		Operate on the PRIMARY (executables) link map
797 	 *  LM_ID_LDSO:		Operation on ld.so.1's link map
798 	 *  LM_ID_NEWLM: 	Create a new link-map.
799 	 */
800 	if (lml == (Lm_list *)LM_ID_NEWLM) {
801 		if ((lml = calloc(sizeof (Lm_list), 1)) == 0)
802 			return (0);
803 
804 		/*
805 		 * Establish the new link-map flags from the callers and those
806 		 * explicitly provided.
807 		 */
808 		lml->lm_tflags = LIST(clmp)->lm_tflags;
809 		if (flags & FLG_RT_AUDIT) {
810 			/*
811 			 * Unset any auditing flags - an auditor shouldn't be
812 			 * audited.  Insure all audit dependencies are loaded.
813 			 */
814 			lml->lm_tflags &= ~LML_TFLG_AUD_MASK;
815 			lml->lm_tflags |=
816 			    (LML_TFLG_NOLAZYLD | LML_TFLG_LOADFLTR);
817 			lml->lm_flags |= LML_FLG_NOAUDIT;
818 		}
819 
820 		if (list_append(&dynlm_list, lml) == 0) {
821 			free(lml);
822 			return (0);
823 		}
824 		if (newlmid(lml) == 0) {
825 			list_delete(&dynlm_list, lml);
826 			free(lml);
827 			return (0);
828 		}
829 	} else if ((uintptr_t)lml < LM_ID_NUM) {
830 		if ((uintptr_t)lml == LM_ID_BASE)
831 			lml = &lml_main;
832 		else if ((uintptr_t)lml == LM_ID_LDSO)
833 			lml = &lml_rtld;
834 	}
835 
836 	/*
837 	 * Open the required object on the associated link-map list.
838 	 */
839 	ghp = dlmopen_core(lml, path, mode, clmp, flags, orig, &in_nfavl);
840 
841 	/*
842 	 * If the object could not be found it is possible that the "not-found"
843 	 * AVL tree had indicated that the file does not exist.  In case the
844 	 * file system has changes since this "not-found" recording was made,
845 	 * retry the dlopen() with a clean "not-found" AVL tree.
846 	 */
847 	if ((ghp == 0) && in_nfavl) {
848 		avl_tree_t	*oavlt = nfavl;
849 
850 		nfavl = NULL;
851 		ghp = dlmopen_core(lml, path, mode, clmp, flags, orig, NULL);
852 
853 		/*
854 		 * If the file is found, then its full path name will have been
855 		 * registered in the FullPath AVL tree.  Remove any new
856 		 * "not-found" AVL information, and restore the former AVL tree.
857 		 */
858 		nfavl_remove(nfavl);
859 		nfavl = oavlt;
860 	}
861 
862 	/*
863 	 * Establish the new link-map from which .init processing will begin.
864 	 * Ignore .init firing when constructing a configuration file (crle(1)).
865 	 */
866 	if (ghp && ((mode & RTLD_CONFGEN) == 0))
867 		dlmp = ghp->gh_ownlmp;
868 
869 	/*
870 	 * If loading an auditor was requested, and the auditor already existed,
871 	 * then the link-map returned will be to the original auditor.  Remove
872 	 * the link-map control list that was created for this request.
873 	 */
874 	if (dlmp && (flags & FLG_RT_AUDIT) && (LIST(dlmp) != lml)) {
875 		remove_lml(lml);
876 		lml = LIST(dlmp);
877 	}
878 
879 	/*
880 	 * If this load failed, remove any alternative link-map list.
881 	 */
882 	if ((ghp == 0) &&
883 	    ((lml->lm_flags & (LML_FLG_BASELM | LML_FLG_RTLDLM)) == 0)) {
884 		remove_lml(lml);
885 		lml = 0;
886 	}
887 
888 	/*
889 	 * Finish this load request.  If objects were loaded, .init processing
890 	 * is computed.  Finally, the debuggers are informed of the link-map
891 	 * lists being stable.
892 	 */
893 	load_completion(dlmp);
894 
895 	return (ghp);
896 }
897 
898 /*
899  * Argument checking for dlopen.  Only called via external entry.
900  */
901 static Grp_hdl *
902 dlmopen_check(Lm_list *lml, const char *path, int mode, Rt_map *clmp)
903 {
904 	/*
905 	 * Verify that a valid pathname has been supplied.
906 	 */
907 	if (path && (*path == '\0')) {
908 		eprintf(lml, ERR_FATAL, MSG_INTL(MSG_ARG_ILLPATH));
909 		return (0);
910 	}
911 
912 	/*
913 	 * Historically we've always verified the mode is either RTLD_NOW or
914 	 * RTLD_LAZY.  RTLD_NOLOAD is valid by itself.  Use of LM_ID_NEWLM
915 	 * requires a specific pathname, and use of RTLD_PARENT is meaningless.
916 	 */
917 	if ((mode & (RTLD_NOW | RTLD_LAZY | RTLD_NOLOAD)) == 0) {
918 		eprintf(lml, ERR_FATAL, MSG_INTL(MSG_ARG_ILLMODE_1));
919 		return (0);
920 	}
921 	if ((mode & (RTLD_NOW | RTLD_LAZY)) == (RTLD_NOW | RTLD_LAZY)) {
922 		eprintf(lml, ERR_FATAL, MSG_INTL(MSG_ARG_ILLMODE_2));
923 		return (0);
924 	}
925 	if ((lml == (Lm_list *)LM_ID_NEWLM) && (path == 0)) {
926 		eprintf(lml, ERR_FATAL, MSG_INTL(MSG_ARG_ILLMODE_3));
927 		return (0);
928 	}
929 	if ((lml == (Lm_list *)LM_ID_NEWLM) && (mode & RTLD_PARENT)) {
930 		eprintf(lml, ERR_FATAL, MSG_INTL(MSG_ARG_ILLMODE_4));
931 		return (0);
932 	}
933 
934 	return (dlmopen_intn(lml, path, mode, clmp, 0, 0));
935 }
936 
937 #pragma weak _dlopen = dlopen
938 
939 /*
940  * External entry for dlopen(3dl).  On success, returns a pointer (handle) to
941  * the structure containing information about the newly added object, ie. can
942  * be used by dlsym(). On failure, returns a null pointer.
943  */
944 void *
945 dlopen(const char *path, int mode)
946 {
947 	int	entry;
948 	Rt_map	*clmp;
949 	Grp_hdl	*ghp;
950 	Lm_list	*lml;
951 
952 	entry = enter(0);
953 
954 	clmp = _caller(caller(), CL_EXECDEF);
955 	lml = LIST(clmp);
956 
957 	ghp = dlmopen_check(lml, path, mode, clmp);
958 
959 	if (entry)
960 		leave(lml, 0);
961 	return ((void *)ghp);
962 }
963 
964 #pragma weak _dlmopen = dlmopen
965 
966 /*
967  * External entry for dlmopen(3dl).
968  */
969 void *
970 dlmopen(Lmid_t lmid, const char *path, int mode)
971 {
972 	int	entry;
973 	Rt_map	*clmp;
974 	Grp_hdl	*ghp;
975 
976 	entry = enter(0);
977 
978 	clmp = _caller(caller(), CL_EXECDEF);
979 
980 	ghp = dlmopen_check((Lm_list *)lmid, path, mode, clmp);
981 
982 	if (entry)
983 		leave(LIST(clmp), 0);
984 	return ((void *)ghp);
985 }
986 
987 /*
988  * Handle processing for dlsym.
989  */
990 Sym *
991 dlsym_handle(Grp_hdl *ghp, Slookup *slp, Rt_map **_lmp, uint_t *binfo,
992     int *in_nfavl)
993 {
994 	Rt_map		*nlmp, * lmp = ghp->gh_ownlmp;
995 	Rt_map		*clmp = slp->sl_cmap;
996 	const char	*name = slp->sl_name;
997 	Sym		*sym = 0;
998 	Slookup		sl = *slp;
999 
1000 	sl.sl_flags = (LKUP_FIRST | LKUP_SPEC);
1001 
1002 	/*
1003 	 * Continue processing a dlsym request.  Lookup the required symbol in
1004 	 * each link-map specified by the handle.
1005 	 *
1006 	 * To leverage off of lazy loading, dlsym() requests can result in two
1007 	 * passes.  The first descends the link-maps of any objects already in
1008 	 * the address space.  If the symbol isn't located, and lazy
1009 	 * dependencies still exist, then a second pass is made to load these
1010 	 * dependencies if applicable.  This model means that in the case where
1011 	 * a symbols exists in more than one object, the one located may not be
1012 	 * constant - this is the standard issue with lazy loading. In addition,
1013 	 * attempting to locate a symbol that doesn't exist will result in the
1014 	 * loading of all lazy dependencies on the given handle, which can
1015 	 * defeat some of the advantages of lazy loading (look out JVM).
1016 	 */
1017 	if (ghp->gh_flags & GPH_ZERO) {
1018 		Lm_list	*lml;
1019 
1020 		/*
1021 		 * If this symbol lookup is triggered from a dlopen(0) handle,
1022 		 * traverse the present link-map list looking for promiscuous
1023 		 * entries.
1024 		 */
1025 		for (nlmp = lmp; nlmp; nlmp = NEXT_RT_MAP(nlmp)) {
1026 
1027 			/*
1028 			 * If this handle indicates we're only to look in the
1029 			 * first object check whether we're done.
1030 			 */
1031 			if ((nlmp != lmp) && (ghp->gh_flags & GPH_FIRST))
1032 				return ((Sym *)0);
1033 
1034 			if (!(MODE(nlmp) & RTLD_GLOBAL))
1035 				continue;
1036 			if ((FLAGS(nlmp) & FLG_RT_DELETE) &&
1037 			    ((FLAGS(clmp) & FLG_RT_DELETE) == 0))
1038 				continue;
1039 
1040 			sl.sl_imap = nlmp;
1041 			if (sym = LM_LOOKUP_SYM(clmp)(&sl, _lmp, binfo,
1042 			    in_nfavl))
1043 				return (sym);
1044 		}
1045 
1046 		/*
1047 		 * If we're unable to locate the symbol and this link-map still
1048 		 * has pending lazy dependencies, start loading them in an
1049 		 * attempt to exhaust the search.  Note that as we're already
1050 		 * traversing a dynamic linked list of link-maps there's no
1051 		 * need for elf_lazy_find_sym() to descend the link-maps itself.
1052 		 */
1053 		lml = LIST(lmp);
1054 		if ((lml->lm_lazy) &&
1055 		    ((lml->lm_flags & LML_FLG_NOPENDGLBLAZY) == 0)) {
1056 			int	lazy = 0;
1057 
1058 			DBG_CALL(Dbg_syms_lazy_rescan(lml, name));
1059 
1060 			sl.sl_flags |= LKUP_NODESCENT;
1061 
1062 			for (nlmp = lmp; nlmp; nlmp = NEXT_RT_MAP(nlmp)) {
1063 
1064 				if (!(MODE(nlmp) & RTLD_GLOBAL) || !LAZY(nlmp))
1065 					continue;
1066 				if ((FLAGS(nlmp) & FLG_RT_DELETE) &&
1067 				    ((FLAGS(clmp) & FLG_RT_DELETE) == 0))
1068 					continue;
1069 
1070 				lazy = 1;
1071 				sl.sl_imap = nlmp;
1072 				if (sym = elf_lazy_find_sym(&sl, _lmp, binfo,
1073 				    in_nfavl))
1074 					return (sym);
1075 			}
1076 
1077 			/*
1078 			 * If no global, lazy loadable dependencies are found,
1079 			 * then none exist for this link-map list.  Pending lazy
1080 			 * loadable objects may still exist for non-local
1081 			 * objects that are associated with this link-map list,
1082 			 * which is why we entered this fallback.  Tag this
1083 			 * link-map list to prevent further searching for lazy
1084 			 * dependencies.
1085 			 */
1086 			if (lazy == 0)
1087 				lml->lm_flags |= LML_FLG_NOPENDGLBLAZY;
1088 		}
1089 	} else {
1090 		/*
1091 		 * Traverse the dlopen() handle for the presently loaded
1092 		 * link-maps.
1093 		 */
1094 		Grp_desc	*gdp;
1095 		Aliste		idx;
1096 
1097 		for (ALIST_TRAVERSE(ghp->gh_depends, idx, gdp)) {
1098 			if ((gdp->gd_flags & GPD_DLSYM) == 0)
1099 				continue;
1100 
1101 			sl.sl_imap = gdp->gd_depend;
1102 			if (sym = LM_LOOKUP_SYM(clmp)(&sl, _lmp, binfo,
1103 			    in_nfavl))
1104 				return (sym);
1105 
1106 			if (ghp->gh_flags & GPH_FIRST)
1107 				return ((Sym *)0);
1108 		}
1109 
1110 		/*
1111 		 * If we're unable to locate the symbol and this link-map still
1112 		 * has pending lazy dependencies, start loading them in an
1113 		 * attempt to exhaust the search.
1114 		 */
1115 		if ((LIST(lmp)->lm_lazy) &&
1116 		    ((ghp->gh_flags & GPH_NOPENDLAZY) == 0)) {
1117 			int	lazy = 0;
1118 
1119 			DBG_CALL(Dbg_syms_lazy_rescan(LIST(lmp), name));
1120 
1121 			for (ALIST_TRAVERSE(ghp->gh_depends, idx, gdp)) {
1122 				nlmp = gdp->gd_depend;
1123 
1124 				if (((gdp->gd_flags & GPD_DLSYM) == 0) ||
1125 				    (LAZY(nlmp) == 0))
1126 					continue;
1127 
1128 				lazy = 1;
1129 				sl.sl_imap = nlmp;
1130 				if (sym = elf_lazy_find_sym(&sl, _lmp,
1131 				    binfo, in_nfavl))
1132 					return (sym);
1133 			}
1134 
1135 			/*
1136 			 * If no lazy loadable dependencies are found, then
1137 			 * none exist for this handle.  Pending lazy loadable
1138 			 * objects may still exist for the associated link-map
1139 			 * list, which is why we entered this fallback.  Tag
1140 			 * this handle to prevent further searching for lazy
1141 			 * dependencies.
1142 			 */
1143 			if (lazy == 0)
1144 				ghp->gh_flags |= GPH_NOPENDLAZY;
1145 		}
1146 	}
1147 	return ((Sym *)0);
1148 }
1149 
1150 /*
1151  * Core dlsym activity.  Selects symbol lookup method from handle.
1152  */
1153 void *
1154 dlsym_core(void *handle, const char *name, Rt_map *clmp, Rt_map **dlmp,
1155     int *in_nfavl)
1156 {
1157 	Sym		*sym = NULL;
1158 	Syminfo		*sip;
1159 	Slookup		sl;
1160 	uint_t		binfo;
1161 
1162 	/*
1163 	 * Initialize the symbol lookup data structure.
1164 	 *
1165 	 * Standard relocations are evaluated using the symbol index of the
1166 	 * associated relocation symbol.  This index provides for loading
1167 	 * any lazy dependency and establishing a direct binding if necessary.
1168 	 * If a dlsym() operation originates from an object that contains a
1169 	 * symbol table entry for the same name, then we need to establish the
1170 	 * symbol index so that any dependency requirements can be triggered.
1171 	 *
1172 	 * Therefore, the first symbol lookup that is carried out is for the
1173 	 * symbol name within the calling object.  If this symbol exists, the
1174 	 * symbols index is computed, added to the Slookup data, and thus used
1175 	 * to seed the real symbol lookup.
1176 	 */
1177 	SLOOKUP_INIT(sl, name, clmp, clmp, ld_entry_cnt, elf_hash(name),
1178 	    0, 0, 0, LKUP_SYMNDX);
1179 
1180 	if ((FCT(clmp) == &elf_fct) &&
1181 	    ((sym = SYMINTP(clmp)(&sl, 0, 0, NULL)) != NULL)) {
1182 		sl.sl_rsymndx = (((ulong_t)sym -
1183 		    (ulong_t)SYMTAB(clmp)) / SYMENT(clmp));
1184 		sl.sl_rsym = sym;
1185 	}
1186 
1187 	if (sym && (ELF_ST_VISIBILITY(sym->st_other) == STV_SINGLETON)) {
1188 		Rt_map	*hlmp = LIST(clmp)->lm_head;
1189 
1190 		/*
1191 		 * If a symbol reference is known, and that reference indicates
1192 		 * that the symbol is a singleton, then the search for the
1193 		 * symbol must follow the default search path.
1194 		 */
1195 		DBG_CALL(Dbg_syms_dlsym(clmp, name, in_nfavl, 0,
1196 		    DBG_DLSYM_SINGLETON));
1197 
1198 		sl.sl_imap = hlmp;
1199 		sl.sl_flags = LKUP_SPEC;
1200 		if (handle == RTLD_PROBE)
1201 			sl.sl_flags |= LKUP_NOFALLBACK;
1202 		sym = LM_LOOKUP_SYM(clmp)(&sl, dlmp, &binfo, in_nfavl);
1203 
1204 	} else if (handle == RTLD_NEXT) {
1205 		Rt_map	*nlmp;
1206 
1207 		/*
1208 		 * If this handle is RTLD_NEXT determine whether a lazy load
1209 		 * from the caller might provide the next object.  This mimics
1210 		 * the lazy loading initialization normally carried out by
1211 		 * lookup_sym(), however here, we must do this up-front, as
1212 		 * lookup_sym() will be used to inspect the next object.
1213 		 */
1214 		if ((sl.sl_rsymndx) && ((sip = SYMINFO(clmp)) != 0)) {
1215 			/* LINTED */
1216 			sip = (Syminfo *)((char *)sip +
1217 			    (sl.sl_rsymndx * SYMINENT(clmp)));
1218 
1219 			if ((sip->si_flags & SYMINFO_FLG_DIRECT) &&
1220 			    (sip->si_boundto < SYMINFO_BT_LOWRESERVE))
1221 				(void) elf_lazy_load(clmp, &sl,
1222 				    sip->si_boundto, name, in_nfavl);
1223 
1224 			/*
1225 			 * Clear the symbol index, so as not to confuse
1226 			 * lookup_sym() of the next object.
1227 			 */
1228 			sl.sl_rsymndx = 0;
1229 			sl.sl_rsym = 0;
1230 		}
1231 
1232 		/*
1233 		 * If the handle is RTLD_NEXT start searching in the next link
1234 		 * map from the callers.  Determine permissions from the
1235 		 * present link map.  Indicate to lookup_sym() that we're on an
1236 		 * RTLD_NEXT request so that it will use the callers link map to
1237 		 * start any possible lazy dependency loading.
1238 		 */
1239 		sl.sl_imap = nlmp = NEXT_RT_MAP(clmp);
1240 
1241 		DBG_CALL(Dbg_syms_dlsym(clmp, name, in_nfavl,
1242 		    (nlmp ? NAME(nlmp) : MSG_INTL(MSG_STR_NULL)),
1243 		    DBG_DLSYM_NEXT));
1244 
1245 		if (nlmp == 0)
1246 			return (0);
1247 
1248 		sl.sl_flags = LKUP_NEXT;
1249 		sym = LM_LOOKUP_SYM(clmp)(&sl, dlmp, &binfo, in_nfavl);
1250 
1251 	} else if (handle == RTLD_SELF) {
1252 		/*
1253 		 * If the handle is RTLD_SELF start searching from the caller.
1254 		 */
1255 		DBG_CALL(Dbg_syms_dlsym(clmp, name, in_nfavl, NAME(clmp),
1256 		    DBG_DLSYM_SELF));
1257 
1258 		sl.sl_imap = clmp;
1259 		sl.sl_flags = (LKUP_SPEC | LKUP_SELF);
1260 		sym = LM_LOOKUP_SYM(clmp)(&sl, dlmp, &binfo, in_nfavl);
1261 
1262 	} else if (handle == RTLD_DEFAULT) {
1263 		Rt_map	*hlmp = LIST(clmp)->lm_head;
1264 
1265 		/*
1266 		 * If the handle is RTLD_DEFAULT mimic the standard symbol
1267 		 * lookup as would be triggered by a relocation.
1268 		 */
1269 		DBG_CALL(Dbg_syms_dlsym(clmp, name, in_nfavl, 0,
1270 		    DBG_DLSYM_DEFAULT));
1271 
1272 		sl.sl_imap = hlmp;
1273 		sl.sl_flags = LKUP_SPEC;
1274 		sym = LM_LOOKUP_SYM(clmp)(&sl, dlmp, &binfo, in_nfavl);
1275 
1276 	} else if (handle == RTLD_PROBE) {
1277 		Rt_map	*hlmp = LIST(clmp)->lm_head;
1278 
1279 		/*
1280 		 * If the handle is RTLD_PROBE, mimic the standard symbol
1281 		 * lookup as would be triggered by a relocation, however do
1282 		 * not fall back to a lazy loading rescan if the symbol can't be
1283 		 * found within the currently loaded objects.  Note, a lazy
1284 		 * loaded dependency required by the caller might still get
1285 		 * loaded to satisfy this request, but no exhaustive lazy load
1286 		 * rescan is carried out.
1287 		 */
1288 		DBG_CALL(Dbg_syms_dlsym(clmp, name, in_nfavl, 0,
1289 		    DBG_DLSYM_PROBE));
1290 
1291 		sl.sl_imap = hlmp;
1292 		sl.sl_flags = (LKUP_SPEC | LKUP_NOFALLBACK);
1293 		sym = LM_LOOKUP_SYM(clmp)(&sl, dlmp, &binfo, in_nfavl);
1294 
1295 	} else {
1296 		Grp_hdl *ghp = (Grp_hdl *)handle;
1297 
1298 		/*
1299 		 * Look in the shared object specified by the handle and in all
1300 		 * of its dependencies.
1301 		 */
1302 		DBG_CALL(Dbg_syms_dlsym(clmp, name, in_nfavl,
1303 		    NAME(ghp->gh_ownlmp), DBG_DLSYM_DEF));
1304 
1305 		sym = LM_DLSYM(clmp)(ghp, &sl, dlmp, &binfo, in_nfavl);
1306 	}
1307 
1308 	if (sym) {
1309 		Lm_list	*lml = LIST(clmp);
1310 		Addr	addr = sym->st_value;
1311 
1312 		if (!(FLAGS(*dlmp) & FLG_RT_FIXED))
1313 			addr += ADDR(*dlmp);
1314 
1315 		/*
1316 		 * Indicate that the defining object is now used.
1317 		 */
1318 		if (*dlmp != clmp)
1319 			FLAGS1(*dlmp) |= FL1_RT_USED;
1320 
1321 		DBG_CALL(Dbg_bind_global(clmp, 0, 0, (Xword)-1, PLT_T_NONE,
1322 		    *dlmp, addr, sym->st_value, name, binfo));
1323 
1324 		if ((lml->lm_tflags | FLAGS1(clmp)) & LML_TFLG_AUD_SYMBIND) {
1325 			uint_t	sb_flags = LA_SYMB_DLSYM;
1326 			/* LINTED */
1327 			uint_t	symndx = (uint_t)(((Xword)sym -
1328 			    (Xword)SYMTAB(*dlmp)) / SYMENT(*dlmp));
1329 			addr = audit_symbind(clmp, *dlmp, sym, symndx, addr,
1330 			    &sb_flags);
1331 		}
1332 		return ((void *)addr);
1333 	} else
1334 		return (0);
1335 }
1336 
1337 /*
1338  * Internal dlsym activity.  Called from user level or directly for internal
1339  * symbol lookup.
1340  */
1341 void *
1342 dlsym_intn(void *handle, const char *name, Rt_map *clmp, Rt_map **dlmp)
1343 {
1344 	Rt_map		*llmp = 0;
1345 	void		*error;
1346 	Aliste		idx;
1347 	Grp_desc	*gdp;
1348 	int		in_nfavl = 0;
1349 
1350 	/*
1351 	 * While looking for symbols it's quite possible that additional objects
1352 	 * get loaded from lazy loading.  These objects will have been added to
1353 	 * the same link-map list as those objects on the handle.  Remember this
1354 	 * list for later investigation.
1355 	 */
1356 	if ((handle == RTLD_NEXT) || (handle == RTLD_DEFAULT) ||
1357 	    (handle == RTLD_SELF) || (handle == RTLD_PROBE))
1358 		llmp = LIST(clmp)->lm_tail;
1359 	else {
1360 		Grp_hdl	*ghp = (Grp_hdl *)handle;
1361 
1362 		if (ghp->gh_ownlmp)
1363 			llmp = LIST(ghp->gh_ownlmp)->lm_tail;
1364 		else {
1365 			for (ALIST_TRAVERSE(ghp->gh_depends, idx, gdp)) {
1366 				if ((llmp = LIST(gdp->gd_depend)->lm_tail) != 0)
1367 					break;
1368 			}
1369 		}
1370 	}
1371 
1372 	error = dlsym_core(handle, name, clmp, dlmp, &in_nfavl);
1373 
1374 	/*
1375 	 * If the symbol could not be found it is possible that the "not-found"
1376 	 * AVL tree had indicated that a required file does not exist.  In case
1377 	 * the file system has changed since this "not-found" recording was
1378 	 * made, retry the dlsym() with a clean "not-found" AVL tree.
1379 	 */
1380 	if ((error == 0) && in_nfavl) {
1381 		avl_tree_t	*oavlt = nfavl;
1382 
1383 		nfavl = NULL;
1384 		error = dlsym_core(handle, name, clmp, dlmp, NULL);
1385 
1386 		/*
1387 		 * If the symbol is found, then any file that was loaded will
1388 		 * have had its full path name registered in the FullPath AVL
1389 		 * tree.  Remove any new "not-found" AVL information, and
1390 		 * restore the former AVL tree.
1391 		 */
1392 		nfavl_remove(nfavl);
1393 		nfavl = oavlt;
1394 	}
1395 
1396 	if (error == 0) {
1397 		/*
1398 		 * Cache the error message, as Java tends to fall through this
1399 		 * code many times.
1400 		 */
1401 		if (nosym_str == 0)
1402 			nosym_str = MSG_INTL(MSG_GEN_NOSYM);
1403 		eprintf(LIST(clmp), ERR_FATAL, nosym_str, name);
1404 	}
1405 
1406 	load_completion(llmp);
1407 	return (error);
1408 }
1409 
1410 /*
1411  * Argument checking for dlsym.  Only called via external entry.
1412  */
1413 static void *
1414 dlsym_check(void *handle, const char *name, Rt_map *clmp, Rt_map **dlmp)
1415 {
1416 	/*
1417 	 * Verify the arguments.
1418 	 */
1419 	if (name == 0) {
1420 		eprintf(LIST(clmp), ERR_FATAL, MSG_INTL(MSG_ARG_ILLSYM));
1421 		return (0);
1422 	}
1423 	if ((handle != RTLD_NEXT) && (handle != RTLD_DEFAULT) &&
1424 	    (handle != RTLD_SELF) && (handle != RTLD_PROBE) &&
1425 	    (hdl_validate((Grp_hdl *)handle) == 0)) {
1426 		eprintf(LIST(clmp), ERR_FATAL, MSG_INTL(MSG_ARG_INVHNDL));
1427 		return (0);
1428 	}
1429 	return (dlsym_intn(handle, name, clmp, dlmp));
1430 }
1431 
1432 
1433 #pragma weak _dlsym = dlsym
1434 
1435 /*
1436  * External entry for dlsym().  On success, returns the address of the specified
1437  * symbol.  On error returns a null.
1438  */
1439 void *
1440 dlsym(void *handle, const char *name)
1441 {
1442 	int	entry;
1443 	Rt_map	*clmp, *dlmp = 0;
1444 	void	*addr;
1445 
1446 	entry = enter(0);
1447 
1448 	clmp = _caller(caller(), CL_EXECDEF);
1449 
1450 	addr = dlsym_check(handle, name, clmp, &dlmp);
1451 
1452 	if (dlmp)
1453 		is_dep_ready(dlmp, clmp, DBG_WAIT_SYMBOL);
1454 
1455 	if (entry && dlmp)
1456 		is_dep_init(dlmp, clmp);
1457 
1458 	if (entry)
1459 		leave(LIST(clmp), 0);
1460 	return (addr);
1461 }
1462 
1463 /*
1464  * Core dladdr activity.
1465  */
1466 static void
1467 dladdr_core(Rt_map *clmp, void *addr, Dl_info *dlip, void **info, int flags)
1468 {
1469 	/*
1470 	 * Set up generic information and any defaults.
1471 	 */
1472 	dlip->dli_fname = PATHNAME(clmp);
1473 
1474 	dlip->dli_fbase = (void *)ADDR(clmp);
1475 	dlip->dli_sname = 0;
1476 	dlip->dli_saddr = 0;
1477 
1478 	/*
1479 	 * Determine the nearest symbol to this address.
1480 	 */
1481 	LM_DLADDR(clmp)((ulong_t)addr, clmp, dlip, info, flags);
1482 }
1483 
1484 #pragma weak _dladdr = dladdr
1485 
1486 /*
1487  * External entry for dladdr(3dl) and dladdr1(3dl).  Returns an information
1488  * structure that reflects the symbol closest to the address specified.
1489  */
1490 int
1491 dladdr(void *addr, Dl_info *dlip)
1492 {
1493 	int	entry, error;
1494 	Rt_map	*clmp;
1495 
1496 	entry = enter(0);
1497 
1498 	/*
1499 	 * Use our calling technique to determine what object is associated
1500 	 * with the supplied address.  If a caller can't be determined,
1501 	 * indicate the failure.
1502 	 */
1503 	if ((clmp = _caller((caddr_t)addr, CL_NONE)) == 0) {
1504 		eprintf(0, ERR_FATAL, MSG_INTL(MSG_ARG_INVADDR),
1505 		    EC_NATPTR(addr));
1506 		error = 0;
1507 	} else {
1508 		dladdr_core(clmp, addr, dlip, 0, 0);
1509 		error = 1;
1510 	}
1511 
1512 	if (entry)
1513 		leave(0, 0);
1514 	return (error);
1515 }
1516 
1517 #pragma weak _dladdr1 = dladdr1
1518 
1519 int
1520 dladdr1(void *addr, Dl_info *dlip, void **info, int flags)
1521 {
1522 	int	entry, error = 0;
1523 	Rt_map	*clmp;
1524 
1525 	/*
1526 	 * Validate any flags.
1527 	 */
1528 	if (flags) {
1529 		int	request;
1530 
1531 		if (((request = (flags & RTLD_DL_MASK)) != RTLD_DL_SYMENT) &&
1532 		    (request != RTLD_DL_LINKMAP)) {
1533 			eprintf(0, ERR_FATAL, MSG_INTL(MSG_ARG_ILLFLAGS),
1534 			    flags);
1535 			return (0);
1536 		}
1537 		if (info == 0) {
1538 			eprintf(0, ERR_FATAL, MSG_INTL(MSG_ARG_ILLINFO), flags);
1539 			return (0);
1540 		}
1541 	}
1542 
1543 	entry = enter(0);
1544 
1545 	/*
1546 	 * Use our calling technique to determine what object is associated
1547 	 * with the supplied address.  If a caller can't be determined,
1548 	 * indicate the failure.
1549 	 */
1550 	if ((clmp = _caller((caddr_t)addr, CL_NONE)) == 0) {
1551 		eprintf(0, ERR_FATAL, MSG_INTL(MSG_ARG_INVADDR),
1552 		    EC_NATPTR(addr));
1553 		error = 0;
1554 	} else {
1555 		dladdr_core(clmp, addr, dlip, info, flags);
1556 		error = 1;
1557 	}
1558 
1559 	if (entry)
1560 		leave(0, 0);
1561 	return (error);
1562 }
1563 
1564 /*
1565  * Core dldump activity.
1566  */
1567 static int
1568 dldump_core(Lm_list *lml, const char *ipath, const char *opath, int flags)
1569 {
1570 	Addr	addr = 0;
1571 	Rt_map	*lmp;
1572 
1573 	/*
1574 	 * Verify any arguments first.
1575 	 */
1576 	if ((!opath || (*opath == '\0')) || (ipath && (*ipath == '\0'))) {
1577 		eprintf(lml, ERR_FATAL, MSG_INTL(MSG_ARG_ILLPATH));
1578 		return (1);
1579 	}
1580 
1581 	/*
1582 	 * If an input file is specified make sure its one of our dependencies
1583 	 * on the main link-map list.  Note, this has really all evolved for
1584 	 * crle(), which uses libcrle.so on an alternative link-map to trigger
1585 	 * dumping objects from the main link-map list.   If we ever want to
1586 	 * dump objects from alternative link-maps, this model is going to
1587 	 * have to be revisited.
1588 	 */
1589 	if (ipath) {
1590 		if ((lmp = is_so_loaded(&lml_main, ipath, NULL)) == 0) {
1591 			eprintf(lml, ERR_FATAL, MSG_INTL(MSG_GEN_NOFILE),
1592 			    ipath);
1593 			return (1);
1594 		}
1595 		if (FLAGS(lmp) & FLG_RT_ALTER) {
1596 			eprintf(lml, ERR_FATAL, MSG_INTL(MSG_GEN_ALTER), ipath);
1597 			return (1);
1598 		}
1599 		if (FLAGS(lmp) & FLG_RT_NODUMP) {
1600 			eprintf(lml, ERR_FATAL, MSG_INTL(MSG_GEN_NODUMP),
1601 			    ipath);
1602 			return (1);
1603 		}
1604 	} else
1605 		lmp = lml_main.lm_head;
1606 
1607 
1608 	DBG_CALL(Dbg_file_dldump(lmp, opath, flags));
1609 
1610 	/*
1611 	 * If the object being dump'ed isn't fixed identify its mapping.
1612 	 */
1613 	if (!(FLAGS(lmp) & FLG_RT_FIXED))
1614 		addr = ADDR(lmp);
1615 
1616 	/*
1617 	 * As rt_dldump() will effectively lazy load the necessary support
1618 	 * libraries, make sure ld.so.1 is initialized for plt relocations.
1619 	 */
1620 	if (elf_rtld_load() == 0)
1621 		return (0);
1622 
1623 	/*
1624 	 * Dump the required image.
1625 	 */
1626 	return (rt_dldump(lmp, opath, flags, addr));
1627 }
1628 
1629 #pragma weak _dldump = dldump
1630 
1631 /*
1632  * External entry for dldump(3c).  Returns 0 on success, non-zero otherwise.
1633  */
1634 int
1635 dldump(const char *ipath, const char *opath, int flags)
1636 {
1637 	int	error, entry;
1638 	Rt_map	*clmp;
1639 
1640 	entry = enter(0);
1641 
1642 	clmp = _caller(caller(), CL_EXECDEF);
1643 
1644 	error = dldump_core(LIST(clmp), ipath, opath, flags);
1645 
1646 	if (entry)
1647 		leave(LIST(clmp), 0);
1648 	return (error);
1649 }
1650 
1651 /*
1652  * get_linkmap_id() translates Lm_list * pointers to the Link_map id as used by
1653  * the rtld_db and dlmopen() interfaces.  It checks to see if the Link_map is
1654  * one of the primary ones and if so returns it's special token:
1655  *		LM_ID_BASE
1656  *		LM_ID_LDSO
1657  *
1658  * If it's not one of the primary link_map id's it will instead returns a
1659  * pointer to the Lm_list structure which uniquely identifies the Link_map.
1660  */
1661 Lmid_t
1662 get_linkmap_id(Lm_list *lml)
1663 {
1664 	if (lml->lm_flags & LML_FLG_BASELM)
1665 		return (LM_ID_BASE);
1666 	if (lml->lm_flags & LML_FLG_RTLDLM)
1667 		return (LM_ID_LDSO);
1668 
1669 	return ((Lmid_t)lml);
1670 }
1671 
1672 /*
1673  * Extract information for a dlopen() handle.
1674  */
1675 static int
1676 dlinfo_core(void *handle, int request, void *p, Rt_map *clmp)
1677 {
1678 	Lm_list	*lml = LIST(clmp);
1679 	Rt_map	*lmp;
1680 
1681 	if ((request > RTLD_DI_MAX) || (p == 0)) {
1682 		eprintf(lml, ERR_FATAL, MSG_INTL(MSG_ARG_ILLVAL));
1683 		return (-1);
1684 	}
1685 
1686 	/*
1687 	 * Return configuration cache name and address.
1688 	 */
1689 	if (request == RTLD_DI_CONFIGADDR) {
1690 		Dl_info	*dlip = (Dl_info *)p;
1691 
1692 		if ((config->c_name == 0) || (config->c_bgn == 0) ||
1693 		    (config->c_end == 0)) {
1694 			eprintf(lml, ERR_FATAL, MSG_INTL(MSG_ARG_NOCONFIG));
1695 			return (-1);
1696 		}
1697 		dlip->dli_fname = config->c_name;
1698 		dlip->dli_fbase = (void *)config->c_bgn;
1699 		return (0);
1700 	}
1701 
1702 	/*
1703 	 * Return profiled object name (used by ldprof audit library).
1704 	 */
1705 	if (request == RTLD_DI_PROFILENAME) {
1706 		if (profile_name == 0) {
1707 			eprintf(lml, ERR_FATAL, MSG_INTL(MSG_ARG_NOPROFNAME));
1708 			return (-1);
1709 		}
1710 
1711 		*(const char **)p = profile_name;
1712 		return (0);
1713 	}
1714 	if (request == RTLD_DI_PROFILEOUT) {
1715 		/*
1716 		 * If a profile destination directory hasn't been specified
1717 		 * provide a default.
1718 		 */
1719 		if (profile_out == 0)
1720 			profile_out = MSG_ORIG(MSG_PTH_VARTMP);
1721 
1722 		*(const char **)p = profile_out;
1723 		return (0);
1724 	}
1725 
1726 	/*
1727 	 * Obtain or establish a termination signal.
1728 	 */
1729 	if (request == RTLD_DI_GETSIGNAL) {
1730 		*(int *)p = killsig;
1731 		return (0);
1732 	}
1733 
1734 	if (request == RTLD_DI_SETSIGNAL) {
1735 		sigset_t	set;
1736 		int		sig = *(int *)p;
1737 
1738 		/*
1739 		 * Determine whether the signal is in range.
1740 		 */
1741 		(void) sigfillset(&set);
1742 		if (sigismember(&set, sig) != 1) {
1743 			eprintf(lml, ERR_FATAL, MSG_INTL(MSG_ARG_INVSIG), sig);
1744 			return (-1);
1745 		}
1746 
1747 		killsig = sig;
1748 		return (0);
1749 	}
1750 
1751 	/*
1752 	 * For any other request a link-map is required.  Verify the handle.
1753 	 */
1754 	if (handle == RTLD_SELF)
1755 		lmp = clmp;
1756 	else {
1757 		Grp_hdl	*ghp = (Grp_hdl *)handle;
1758 
1759 		if (!hdl_validate(ghp)) {
1760 			eprintf(lml, ERR_FATAL, MSG_INTL(MSG_ARG_INVHNDL));
1761 			return (-1);
1762 		}
1763 		lmp = ghp->gh_ownlmp;
1764 	}
1765 
1766 	/*
1767 	 * Obtain the process arguments, environment and auxv.  Note, as the
1768 	 * environment can be modified by the user (putenv(3c)), reinitialize
1769 	 * the environment pointer on each request.
1770 	 */
1771 	if (request == RTLD_DI_ARGSINFO) {
1772 		Dl_argsinfo	*aip = (Dl_argsinfo *)p;
1773 		Lm_list		*lml = LIST(lmp);
1774 
1775 		*aip = argsinfo;
1776 		if (lml->lm_flags & LML_FLG_ENVIRON)
1777 			aip->dla_envp = *(lml->lm_environ);
1778 
1779 		return (0);
1780 	}
1781 
1782 	/*
1783 	 * Return Lmid_t of the Link-Map list that the specified object is
1784 	 * loaded on.
1785 	 */
1786 	if (request == RTLD_DI_LMID) {
1787 		*(Lmid_t *)p = get_linkmap_id(LIST(lmp));
1788 		return (0);
1789 	}
1790 
1791 	/*
1792 	 * Return a pointer to the Link-Map structure associated with the
1793 	 * specified object.
1794 	 */
1795 	if (request == RTLD_DI_LINKMAP) {
1796 		*(Link_map **)p = (Link_map *)lmp;
1797 		return (0);
1798 	}
1799 
1800 	/*
1801 	 * Return search path information, or the size of the buffer required
1802 	 * to store the information.
1803 	 */
1804 	if ((request == RTLD_DI_SERINFO) || (request == RTLD_DI_SERINFOSIZE)) {
1805 		Pnode		*dir, *dirlist = (Pnode *)0;
1806 		Dl_serinfo	*info;
1807 		Dl_serpath	*path;
1808 		char		*strs;
1809 		size_t		size = sizeof (Dl_serinfo);
1810 		uint_t		cnt = 0;
1811 
1812 		info = (Dl_serinfo *)p;
1813 		path = &info->dls_serpath[0];
1814 		strs = (char *)&info->dls_serpath[info->dls_cnt];
1815 
1816 		/*
1817 		 * Traverse search path entries for this object.
1818 		 */
1819 		while ((dir = get_next_dir(&dirlist, lmp, 0)) != 0) {
1820 			size_t	_size;
1821 
1822 			if (dir->p_name == 0)
1823 				continue;
1824 
1825 			/*
1826 			 * If configuration information exists, it's possible
1827 			 * this path has been identified as non-existent, if so
1828 			 * ignore it.
1829 			 */
1830 			if (dir->p_info) {
1831 				Rtc_obj	*dobj = (Rtc_obj *)dir->p_info;
1832 				if (dobj->co_flags & RTC_OBJ_NOEXIST)
1833 					continue;
1834 			}
1835 
1836 			/*
1837 			 * Keep track of search path count and total info size.
1838 			 */
1839 			if (cnt++)
1840 				size += sizeof (Dl_serpath);
1841 			_size = strlen(dir->p_name) + 1;
1842 			size += _size;
1843 
1844 			if (request == RTLD_DI_SERINFOSIZE)
1845 				continue;
1846 
1847 			/*
1848 			 * If we're filling in search path information, confirm
1849 			 * there's sufficient space.
1850 			 */
1851 			if (size > info->dls_size) {
1852 				eprintf(lml, ERR_FATAL,
1853 				    MSG_INTL(MSG_ARG_SERSIZE),
1854 				    EC_OFF(info->dls_size));
1855 				return (-1);
1856 			}
1857 			if (cnt > info->dls_cnt) {
1858 				eprintf(lml, ERR_FATAL,
1859 				    MSG_INTL(MSG_ARG_SERCNT), info->dls_cnt);
1860 				return (-1);
1861 			}
1862 
1863 			/*
1864 			 * Append the path to the information buffer.
1865 			 */
1866 			(void) strcpy(strs, dir->p_name);
1867 			path->dls_name = strs;
1868 			path->dls_flags = dir->p_orig;
1869 
1870 			strs = strs + _size;
1871 			path++;
1872 		}
1873 
1874 		/*
1875 		 * If we're here to size the search buffer fill it in.
1876 		 */
1877 		if (request == RTLD_DI_SERINFOSIZE) {
1878 			info->dls_size = size;
1879 			info->dls_cnt = cnt;
1880 		}
1881 	}
1882 
1883 	/*
1884 	 * Return the origin of the object associated with this link-map.
1885 	 * Basically return the dirname(1) of the objects fullpath.
1886 	 */
1887 	if (request == RTLD_DI_ORIGIN) {
1888 		char	*str = (char *)p;
1889 
1890 		if (DIRSZ(lmp) == 0)
1891 			(void) fullpath(lmp, 0);
1892 
1893 		(void) strncpy(str, ORIGNAME(lmp), DIRSZ(lmp));
1894 		str += DIRSZ(lmp);
1895 		*str = '\0';
1896 
1897 		return (0);
1898 	}
1899 
1900 	return (0);
1901 }
1902 
1903 #pragma weak _dlinfo = dlinfo
1904 
1905 /*
1906  * External entry for dlinfo(3dl).
1907  */
1908 int
1909 dlinfo(void *handle, int request, void *p)
1910 {
1911 	int	error, entry;
1912 	Rt_map	*clmp;
1913 
1914 	entry = enter(0);
1915 
1916 	clmp = _caller(caller(), CL_EXECDEF);
1917 
1918 	error = dlinfo_core(handle, request, p, clmp);
1919 
1920 	if (entry)
1921 		leave(LIST(clmp), 0);
1922 	return (error);
1923 }
1924