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