xref: /titanic_44/usr/src/cmd/sgs/rtld/common/remove.c (revision a60349c89adffc0902b2353230891d8e7f2b24d9)
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) 1998, 2010, Oracle and/or its affiliates. All rights reserved.
24  */
25 
26 /*
27  * Remove objects.  Objects need removal from a process as part of:
28  *
29  *  -	a dlclose() request
30  *
31  *  -	tearing down a dlopen(), lazy-load, or filter hierarchy that failed to
32  *	completely load
33  *
34  * Any other failure condition will result in process exit (in which case all
35  * we have to do is execute the fini's - tear down is unnecessary).
36  *
37  * Any removal of objects is therefore associated with a dlopen() handle.  There
38  * is a small window between creation of the first dlopen() object and creating
39  * its handle (in which case remove_so() can get rid of the new link-map if
40  * necessary), but other than this all object removal is driven by inspecting
41  * the components of a handle.
42  *
43  * Things to note.  The creation of a link-map, and its addition to the link-map
44  * list occurs in {elf|aout}_new_lm(), if this returns success the link-map is
45  * valid and added, otherwise any steps (allocations) in the process of creating
46  * the link-map would have been undone.  If a failure occurs between creating
47  * the link-map and adding it to a handle, remove_so() is called to remove the
48  * link-map.  If a failures occurs after a handle have been created,
49  * remove_hdl() is called to remove the handle and the link-map.
50  */
51 
52 #include	<string.h>
53 #include	<stdio.h>
54 #include	<unistd.h>
55 #include	<dlfcn.h>
56 #include	<sys/debug.h>
57 #include	<sys/avl.h>
58 #include	<libc_int.h>
59 #include	<debug.h>
60 #include	"_rtld.h"
61 #include	"_audit.h"
62 #include	"_elf.h"
63 #include	"msg.h"
64 
65 /*
66  * Atexit callback provided by libc.  As part of dlclose() determine the address
67  * ranges of all objects that are to be deleted.  Pass this information to
68  * libc's pre-atexit routine.  Libc will purge any registered atexit() calls
69  * related to those objects about to be deleted.
70  */
71 static int
72 purge_exit_handlers(Lm_list *lml, Rt_map **tobj)
73 {
74 	uint_t			num;
75 	Rt_map			**_tobj;
76 	Lc_addr_range_t		*addr, *_addr;
77 	int			error;
78 	int			(*fptr)(Lc_addr_range_t *, uint_t);
79 
80 	/*
81 	 * Has a callback been established?
82 	 */
83 	if ((fptr = lml->lm_lcs[CI_ATEXIT].lc_un.lc_func) == NULL)
84 		return (0);
85 
86 	/*
87 	 * Determine the total number of mapped segments that will be unloaded.
88 	 */
89 	for (num = 0, _tobj = tobj; *_tobj != NULL; _tobj++) {
90 		Rt_map	*lmp = *_tobj;
91 
92 		num += MMAPCNT(lmp);
93 	}
94 
95 	/*
96 	 * Account for a null entry at the end of the address range array.
97 	 */
98 	if (num++ == 0)
99 		return (0);
100 
101 	/*
102 	 * Allocate an array for the address range.
103 	 */
104 	if ((addr = malloc(num * sizeof (Lc_addr_range_t))) == NULL)
105 		return (1);
106 
107 	/*
108 	 * Fill the address range with each loadable segments size and address.
109 	 */
110 	for (_tobj = tobj, _addr = addr; *_tobj != NULL; _tobj++) {
111 		Rt_map			*lmp = *_tobj;
112 		mmapobj_result_t	*mpp = MMAPS(lmp);
113 		uint_t			ndx;
114 
115 		for (ndx = 0; ndx < MMAPCNT(lmp); ndx++, mpp++) {
116 			_addr->lb = (void *)(uintptr_t)(mpp->mr_addr +
117 			    mpp->mr_offset);
118 			_addr->ub = (void *)(uintptr_t)(mpp->mr_addr +
119 			    mpp->mr_msize);
120 			_addr++;
121 		}
122 	}
123 	_addr->lb = _addr->ub = 0;
124 
125 	leave(LIST(*tobj), 0);
126 	error = (*fptr)(addr, (num - 1));
127 	(void) enter(0);
128 
129 	/*
130 	 * If we fail to converse with libc, generate an error message to
131 	 * satisfy any dlerror() usage.
132 	 */
133 	if (error)
134 		eprintf(lml, ERR_FATAL, MSG_INTL(MSG_ARG_ATEXIT), error);
135 
136 	free(addr);
137 	return (error);
138 }
139 
140 /*
141  * Break down an Alist containing pathname descriptors.  In most instances, the
142  * Alist is removed completely.  However, in some instances the alist is cleaned
143  * of all entries, but retained for later use.
144  */
145 void
146 remove_alist(Alist **alpp, int complete)
147 {
148 	Alist	*alp = *alpp;
149 
150 	if (alp) {
151 		if (complete) {
152 			free((void *)alp);
153 			*alpp = NULL;
154 		} else {
155 			alist_reset(alp);
156 		}
157 	}
158 }
159 
160 /*
161  * Remove a link-map list descriptor.  This is called to finalize the removal
162  * of an entire link-map list, after all link-maps have been removed, or none
163  * got added.  As load_one() can process a list of potential candidate objects,
164  * the link-map descriptor must be maintained as each object is processed.  Only
165  * after all objects have been processed can a failure condition finally tear
166  * down the link-map list descriptor.
167  */
168 void
169 remove_lml(Lm_list *lml)
170 {
171 	if (lml && (lml->lm_head == NULL)) {
172 		if (lml->lm_lmidstr)
173 			free(lml->lm_lmidstr);
174 		if (lml->lm_alp)
175 			free(lml->lm_alp);
176 		if (lml->lm_lists)
177 			free(lml->lm_lists);
178 		if (lml->lm_aud_cookies)
179 			free(lml->lm_aud_cookies);
180 
181 		/*
182 		 * Cleanup any pending RTLDINFO in the case where it was
183 		 * allocated but not called (see _relocate_lmc()).
184 		 */
185 		if (lml->lm_rti)
186 			free(lml->lm_rti);
187 		if (lml->lm_fpavl) {
188 			/*
189 			 * As we are freeing the link-map list, all nodes must
190 			 * have previously been removed.
191 			 */
192 			ASSERT(avl_numnodes(lml->lm_fpavl) == 0);
193 			free(lml->lm_fpavl);
194 		}
195 		(void) aplist_delete_value(dynlm_list, lml);
196 		free(lml);
197 	}
198 }
199 
200 /*
201  * Remove a link-map.  This removes a link-map from its associated list and
202  * free's up the link-map itself.  Note, all components that are freed are local
203  * to the link-map, no inter-link-map lists are operated on as these are all
204  * broken down by dlclose() while all objects are still mapped.
205  *
206  * This routine is called from dlclose() to zap individual link-maps after their
207  * interdependencies (DEPENDS(), CALLER(), handles, etc.) have been removed.
208  * This routine is also called from the bowels of load_one() in the case of a
209  * link-map creation failure.
210  */
211 void
212 remove_so(Lm_list *lml, Rt_map *lmp, Rt_map *clmp)
213 {
214 	Dyninfo	*dip;
215 
216 	if (lmp == NULL)
217 		return;
218 
219 	/*
220 	 * Unlink the link map from the link-map list.
221 	 */
222 	if (lml && lmp)
223 		lm_delete(lml, lmp, clmp);
224 
225 	/*
226 	 * If this object contributed any local external vectors for the current
227 	 * link-map list, remove the vectors.  If this object contributed any
228 	 * global external vectors we should find some new candidates, or leave
229 	 * this object lying around.
230 	 */
231 	if (lml) {
232 		int	tag;
233 
234 		for (tag = 0; tag < CI_MAX; tag++) {
235 			if (lml->lm_lcs[tag].lc_lmp == lmp) {
236 				lml->lm_lcs[tag].lc_lmp = NULL;
237 				lml->lm_lcs[tag].lc_un.lc_val = 0;
238 			}
239 			if (glcs[tag].lc_lmp == lmp) {
240 				ASSERT(glcs[tag].lc_lmp != NULL);
241 				glcs[tag].lc_lmp = NULL;
242 				glcs[tag].lc_un.lc_val = 0;
243 			}
244 		}
245 	}
246 
247 	DBG_CALL(Dbg_file_delete(lmp));
248 
249 	/*
250 	 * If this object is an auditor, determine whether any link-map lists
251 	 * are maintaining cookies to represent this auditor.  These cookies
252 	 * are established for local auditing preinit and activity events.
253 	 */
254 	if (FLAGS(lmp) & FLG_RT_AUDIT) {
255 		Lm_list	*nlml;
256 		Aliste	idx1;
257 
258 		for (APLIST_TRAVERSE(dynlm_list, idx1, nlml)) {
259 			Rt_map  	*hlmp = nlml->lm_head;
260 			Audit_client	*acp;
261 			Aliste		idx2;
262 
263 			if ((hlmp == NULL) || (FLAGS(hlmp) & FLG_RT_AUDIT))
264 				continue;
265 
266 			for (ALIST_TRAVERSE(nlml->lm_aud_cookies, idx2, acp)) {
267 				if (acp->ac_lmp != lmp) {
268 					alist_delete(nlml->lm_aud_cookies,
269 					    &idx2);
270 					break;
271 				}
272 			}
273 		}
274 	}
275 
276 	/*
277 	 * If this is a temporary link-map, put in place to facilitate the
278 	 * link-edit or a relocatable object, then the link-map contains no
279 	 * information that needs to be cleaned up.
280 	 */
281 	if (FLAGS(lmp) & FLG_RT_OBJECT)
282 		return;
283 
284 	/*
285 	 * Remove any FullpathNode AVL names if they still exist.
286 	 */
287 	if (FPNODE(lmp))
288 		fpavl_remove(lmp);
289 
290 	/*
291 	 * Remove any alias names.
292 	 */
293 	if (ALIAS(lmp))
294 		free(ALIAS(lmp));
295 
296 	/*
297 	 * Remove any of this objects filtee infrastructure.  The filtees them-
298 	 * selves have already been removed.
299 	 */
300 	if (((dip = DYNINFO(lmp)) != NULL) && (FLAGS1(lmp) & MSK_RT_FILTER)) {
301 		uint_t	cnt, max = DYNINFOCNT(lmp);
302 
303 		for (cnt = 0; cnt < max; cnt++, dip++) {
304 			if ((dip->di_info == NULL) ||
305 			    ((dip->di_flags & MSK_DI_FILTER) == 0))
306 				continue;
307 
308 			remove_alist((Alist **)&(dip->di_info), 1);
309 		}
310 	}
311 
312 	/*
313 	 * Deallocate any remaining cruft and free the link-map.
314 	 */
315 	if (RLIST(lmp))
316 		remove_alist(&RLIST(lmp), 1);
317 
318 	if (AUDITORS(lmp))
319 		audit_desc_cleanup(lmp);
320 	if (AUDINFO(lmp))
321 		audit_info_cleanup(lmp);
322 
323 	/*
324 	 * Note that COPY_R() and COPY_S() reference the same memory
325 	 * location, and that we want to release the memory referenced
326 	 * without regard to which list it logically belongs to. We can
327 	 * use either pointer to do this.
328 	 */
329 	if (COPY_R(lmp))
330 		free(COPY_R(lmp));
331 
332 	/*
333 	 * During a dlclose() any groups this object was a part of will have
334 	 * been torn down.  However, we can get here to remove an object that
335 	 * has failed to load, perhaps because its addition to a handle failed.
336 	 * Therefore if this object indicates that its part of a group tear
337 	 * these associations down.
338 	 */
339 	if (GROUPS(lmp) != NULL) {
340 		Aliste	idx1;
341 		Grp_hdl	*ghp;
342 
343 		for (APLIST_TRAVERSE(GROUPS(lmp), idx1, ghp)) {
344 			Grp_desc	*gdp;
345 			Aliste		idx2;
346 
347 			for (ALIST_TRAVERSE(ghp->gh_depends, idx2, gdp)) {
348 				if (gdp->gd_depend != lmp)
349 					continue;
350 
351 				alist_delete(ghp->gh_depends, &idx2);
352 				break;
353 			}
354 		}
355 		free(GROUPS(lmp));
356 	}
357 	if (HANDLES(lmp))
358 		free(HANDLES(lmp));
359 
360 	/*
361 	 * Clean up reglist if needed
362 	 */
363 	if (reglist) {
364 		Reglist	*cur, *prv, *del;
365 
366 		cur = prv = reglist;
367 		while (cur) {
368 			if (cur->rl_lmp == lmp) {
369 				del = cur;
370 				if (cur == reglist) {
371 					reglist = cur->rl_next;
372 					cur = prv = reglist;
373 				} else {
374 					prv->rl_next = cur->rl_next;
375 					cur = cur->rl_next;
376 				}
377 				free(del);
378 			} else {
379 				prv = cur;
380 				cur = cur->rl_next;
381 			}
382 		}
383 	}
384 
385 	/*
386 	 * If this link map represents a relocatable object concatenation, then
387 	 * the image was simply generated in allocated memory.  Free the memory.
388 	 * Note: memory maps were fabricated for the relocatable object, and
389 	 * the mapping infrastructure must be free'd, but there are no address
390 	 * mappings that must be unmapped.
391 	 *
392 	 * Otherwise, unmap the object.
393 	 */
394 	if (FLAGS(lmp) & FLG_RT_IMGALLOC)
395 		free((void *)ADDR(lmp));
396 
397 	if (CAPCHAIN(lmp))
398 		free((void *)CAPCHAIN(lmp));
399 
400 	if (MMAPS(lmp)) {
401 		if ((FLAGS(lmp) & FLG_RT_IMGALLOC) == 0)
402 			unmap_obj(MMAPS(lmp), MMAPCNT(lmp));
403 		free(MMAPS(lmp));
404 	}
405 
406 	free(lmp);
407 }
408 
409 /*
410  * Traverse an objects dependency list removing callers and dependencies.
411  * There's a chicken and egg problem with tearing down link-maps.  Any
412  * relationship between link-maps is maintained on a DEPENDS list, and an
413  * associated CALLERS list.  These lists can't be broken down at the time a
414  * single link-map is removed, as any related link-map may have already been
415  * removed.  Thus, lists between link-maps must be broken down before the
416  * individual link-maps themselves.
417  */
418 static void
419 remove_lists(Rt_map *lmp, int lazy)
420 {
421 	Aliste		idx1;
422 	Bnd_desc	*bdp;
423 
424 	/*
425 	 * First, traverse this objects dependencies.
426 	 */
427 	for (APLIST_TRAVERSE(DEPENDS(lmp), idx1, bdp)) {
428 		Rt_map		*dlmp = bdp->b_depend;
429 
430 		/*
431 		 * Remove this object from the dependencies callers.
432 		 */
433 		(void) aplist_delete_value(CALLERS(dlmp), bdp);
434 		free(bdp);
435 	}
436 	if (DEPENDS(lmp)) {
437 		free(DEPENDS(lmp));
438 		DEPENDS(lmp) = NULL;
439 	}
440 
441 	/*
442 	 * Second, traverse this objects callers.
443 	 */
444 	for (APLIST_TRAVERSE(CALLERS(lmp), idx1,  bdp)) {
445 		Rt_map		*clmp = bdp->b_caller;
446 		Dyninfo		*dip;
447 
448 		/*
449 		 * If we're removing an object that was triggered by a lazyload,
450 		 * remove the callers DYNINFO() entry and bump the lazy counts.
451 		 * This reinitialization of the lazy information allows a lazy
452 		 * object to be reloaded again later.  Although we may be
453 		 * breaking down a group of lazyloaded objects because one has
454 		 * failed to relocate, it's possible that one or more of the
455 		 * individual objects can be reloaded without a problem.
456 		 */
457 		if (lazy && ((dip = DYNINFO(clmp)) != NULL)) {
458 			uint_t	cnt, max = DYNINFOCNT(clmp);
459 
460 			for (cnt = 0; cnt < max; cnt++, dip++) {
461 				if ((dip->di_flags & FLG_DI_LAZY) == 0)
462 					continue;
463 
464 				if (dip->di_info == (void *)lmp) {
465 					dip->di_info = NULL;
466 
467 					if (LAZY(clmp)++ == 0)
468 						LIST(clmp)->lm_lazy++;
469 				}
470 			}
471 		}
472 
473 		(void) aplist_delete_value(DEPENDS(clmp), bdp);
474 		free(bdp);
475 	}
476 	if (CALLERS(lmp)) {
477 		free(CALLERS(lmp));
478 		CALLERS(lmp) = NULL;
479 	}
480 }
481 
482 /*
483  * Delete any temporary link-map control list.
484  */
485 void
486 remove_cntl(Lm_list *lml, Aliste lmco)
487 {
488 	Aliste	_lmco = lmco;
489 #if	DEBUG
490 	Lm_cntl	*lmc;
491 
492 	lmc = (Lm_cntl *)alist_item_by_offset(lml->lm_lists, lmco);
493 
494 	/*
495 	 * This element should be empty.
496 	 */
497 	ASSERT(lmc->lc_head == NULL);
498 #endif
499 	alist_delete_by_offset(lml->lm_lists, &_lmco);
500 }
501 
502 /*
503  * If a lazy loaded object, or filtee fails to load, possibly because it, or
504  * one of its dependencies can't be relocated, then tear down any objects
505  * that are apart of this link-map control list.
506  */
507 static void
508 remove_incomplete(Lm_list *lml, Aliste lmco, Rt_map *clmp)
509 {
510 	Rt_map	*lmp;
511 	Lm_cntl	*lmc;
512 
513 	/* LINTED */
514 	lmc = (Lm_cntl *)alist_item_by_offset(lml->lm_lists, lmco);
515 
516 	/*
517 	 * If auditing is in effect, the loading of these objects might have
518 	 * resulted in la_objopen() events being posted.  Normally, an
519 	 * la_objclose() event is posted after an object's .fini is executed,
520 	 * just before the objects are unloaded.  These failed objects do not
521 	 * have their .fini's executed, but an la_objclose() event should still
522 	 * be posted to any auditors.
523 	 */
524 	if ((lml->lm_tflags | AFLAGS(clmp)) & LML_TFLG_AUD_OBJCLOSE) {
525 		for (lmp = lmc->lc_head; lmp; lmp = NEXT_RT_MAP(lmp))
526 			audit_objclose(lmp, clmp);
527 	}
528 
529 	/*
530 	 * Remove any lists that may point between objects.
531 	 */
532 	for (lmp = lmc->lc_head; lmp; lmp = NEXT_RT_MAP(lmp))
533 		remove_lists(lmp, 1);
534 
535 	/*
536 	 * Finally, remove each object.  remove_so() calls lm_delete(), thus
537 	 * effectively the link-map control head gets updated to point to the
538 	 * next link-map.
539 	 */
540 	while ((lmp = lmc->lc_head) != NULL)
541 		remove_so(lml, lmp, clmp);
542 
543 	lmc->lc_head = lmc->lc_tail = NULL;
544 }
545 
546 /*
547  * Determine whether an object is deletable.
548  */
549 static int
550 is_deletable(APlist **lmalp, APlist **ghalp, Rt_map *lmp)
551 {
552 	Aliste		idx;
553 	Bnd_desc	*bdp;
554 	Grp_hdl		*ghp;
555 
556 	/*
557 	 * If the object hasn't yet been relocated take this as a sign that
558 	 * it's loading failed, thus we're here to cleanup.  If the object is
559 	 * relocated it will only be retained if it was marked non-deletable,
560 	 * and exists on the main link-map control list.
561 	 */
562 	if ((FLAGS(lmp) & FLG_RT_RELOCED) &&
563 	    (MODE(lmp) & RTLD_NODELETE) && (CNTL(lmp) == ALIST_OFF_DATA))
564 		return (0);
565 
566 	/*
567 	 * If this object is the head of a handle that has not been captured as
568 	 * a candidate for deletion, then this object is in use from a dlopen()
569 	 * outside of the scope of this dlclose() family.  Dlopen'ed objects,
570 	 * and filtees, have group descriptors for their callers.  Typically
571 	 * this parent will have callers that are not apart of this dlclose()
572 	 * family, and thus would be caught by the CALLERS test below.  However,
573 	 * if the caller had itself been dlopen'ed, it may not have any explicit
574 	 * callers registered for itself.  Thus, by looking for objects with
575 	 * handles we can ferret out these outsiders.
576 	 */
577 	for (APLIST_TRAVERSE(HANDLES(lmp), idx, ghp)) {
578 		/*
579 		 * If this is a private handle, then the handle isn't referenced
580 		 * from outside of the group of objects being deleted, and can
581 		 * be ignored when evaluating objects for deletion.
582 		 */
583 		if (ghp->gh_flags & GPH_PRIVATE)
584 			continue;
585 		if (aplist_test(ghalp, ghp, 0) != ALE_EXISTS)
586 			return (0);
587 	}
588 
589 	/*
590 	 * If this object is called by any object outside of the family of
591 	 * objects selected for deletion, it can't be deleted.
592 	 */
593 	for (APLIST_TRAVERSE(CALLERS(lmp), idx, bdp)) {
594 		if (aplist_test(lmalp, bdp->b_caller, 0) != ALE_EXISTS)
595 			return (0);
596 	}
597 
598 	/*
599 	 * This object is a candidate for deletion.
600 	 */
601 	return (1);
602 }
603 
604 /*
605  * Collect the groups (handles) and associated objects that are candidates for
606  * deletion.  The criteria for deleting an object is whether it is only refer-
607  * enced from the objects within the groups that are candidates for deletion.
608  */
609 static int
610 gdp_collect(APlist **ghalpp, APlist **lmalpp, Grp_hdl *ghp1)
611 {
612 	Aliste		idx1;
613 	Grp_desc	*gdp;
614 	int		action;
615 
616 	/*
617 	 * Add this group to our group collection.  If it isn't added either an
618 	 * allocation has failed, or it already exists.
619 	 */
620 	if ((action = aplist_test(ghalpp, ghp1, AL_CNT_GRPCLCT)) !=
621 	    ALE_CREATE)
622 		return (action);
623 
624 	/*
625 	 * Traverse the dependencies of the group and collect the associated
626 	 * objects.
627 	 */
628 	for (ALIST_TRAVERSE(ghp1->gh_depends, idx1, gdp)) {
629 		Rt_map	*lmp = gdp->gd_depend;
630 
631 		/*
632 		 * We only want to process dependencies for deletion.  Although
633 		 * we want to purge group descriptors for parents, we don't want
634 		 * to analyze the parent itself for additional filters or
635 		 * deletion.
636 		 */
637 		if ((gdp->gd_flags & GPD_PARENT) ||
638 		    ((gdp->gd_flags & GPD_ADDEPS) == 0))
639 			continue;
640 
641 		if ((action = aplist_test(lmalpp, lmp, AL_CNT_GRPCLCT)) ==
642 		    ALE_ALLOCFAIL)
643 			return (0);
644 		if (action == ALE_EXISTS)
645 			continue;
646 
647 		/*
648 		 * If this object is a candidate for deletion, determine if the
649 		 * object provides any filtees.  If so, the filter groups are
650 		 * added to the group collection.
651 		 *
652 		 * An object is a candidate for deletion if:
653 		 *
654 		 *  -	the object hasn't yet been relocated, in which case
655 		 *	we're here to clean up a failed load, or
656 		 *  -	the object doesn't reside on the base link-map control
657 		 *	list, in which case a group of objects, typically
658 		 *	lazily loaded, or filtees, need cleaning up, or
659 		 *  -	the object isn't tagged as non-deletable.
660 		 */
661 		if ((((FLAGS(lmp) & FLG_RT_RELOCED) == 0) ||
662 		    (CNTL(lmp) != ALIST_OFF_DATA) ||
663 		    ((MODE(lmp) & RTLD_NODELETE) == 0)) &&
664 		    (FLAGS1(lmp) & MSK_RT_FILTER)) {
665 			Dyninfo	*dip = DYNINFO(lmp);
666 			uint_t	cnt, max = DYNINFOCNT(lmp);
667 
668 			for (cnt = 0; cnt < max; cnt++, dip++) {
669 				Alist	*falp;
670 				Aliste	idx2;
671 				Pdesc	*pdp;
672 
673 				if (((falp = (Alist *)dip->di_info) == NULL) ||
674 				    ((dip->di_flags & MSK_DI_FILTER) == 0))
675 					continue;
676 
677 				for (ALIST_TRAVERSE(falp, idx2, pdp)) {
678 					Grp_hdl	*ghp2;
679 
680 					if ((pdp->pd_plen == 0) || ((ghp2 =
681 					    (Grp_hdl *)pdp->pd_info) == NULL))
682 						continue;
683 
684 					if (gdp_collect(ghalpp, lmalpp,
685 					    ghp2) == 0)
686 						return (0);
687 				}
688 			}
689 		}
690 	}
691 	return (1);
692 }
693 
694 /*
695  * Traverse the list of deletable candidates.  If an object can't be deleted
696  * then neither can its dependencies or filtees.  Any object that is cleared
697  * from being deleted drops the deletion count, plus, if there are no longer
698  * any deletions pending we can discontinue any further processing.
699  */
700 static int
701 remove_rescan(APlist *lmalp, APlist *ghalp, int *delcnt)
702 {
703 	Aliste		idx1;
704 	Rt_map		*lmp;
705 	int		rescan = 0;
706 
707 	for (APLIST_TRAVERSE(lmalp, idx1, lmp)) {
708 		Aliste		idx2;
709 		Bnd_desc	*bdp;
710 		Dyninfo		*dip;
711 		uint_t		cnt, max;
712 
713 		if (FLAGS(lmp) & FLG_RT_DELETE)
714 			continue;
715 
716 		/*
717 		 * As this object can't be deleted, make sure its dependencies
718 		 * aren't deleted either.
719 		 */
720 		for (APLIST_TRAVERSE(DEPENDS(lmp), idx2, bdp)) {
721 			Rt_map	*dlmp = bdp->b_depend;
722 
723 			if (FLAGS(dlmp) & FLG_RT_DELETE) {
724 				FLAGS(dlmp) &= ~FLG_RT_DELETE;
725 				if (--(*delcnt) == 0)
726 					return (0);
727 				rescan = 1;
728 			}
729 		}
730 
731 		/*
732 		 * If this object is a filtee and one of its filters is outside
733 		 * of this dlclose family, then it can't be deleted either.
734 		 */
735 		if ((FLAGS1(lmp) & MSK_RT_FILTER) == 0)
736 			continue;
737 
738 		dip = DYNINFO(lmp);
739 		max = DYNINFOCNT(lmp);
740 
741 		for (cnt = 0; cnt < max; cnt++, dip++) {
742 			Alist	*falp;
743 			Pdesc	*pdp;
744 
745 			if (((falp = (Alist *)dip->di_info) == NULL) ||
746 			    ((dip->di_flags & MSK_DI_FILTER) == 0))
747 				continue;
748 
749 			for (ALIST_TRAVERSE(falp, idx2, pdp)) {
750 				Aliste		idx3;
751 				Grp_hdl		*ghp;
752 				Grp_desc	*gdp;
753 
754 				if ((pdp->pd_plen == 0) ||
755 				    ((ghp = (Grp_hdl *)pdp->pd_info) == NULL))
756 					continue;
757 
758 				if (aplist_test(&ghalp, ghp, 0) ==
759 				    ALE_EXISTS)
760 					continue;
761 
762 				for (ALIST_TRAVERSE(ghp->gh_depends, idx3,
763 				    gdp)) {
764 					Rt_map	*dlmp = gdp->gd_depend;
765 
766 					if (FLAGS(dlmp) & FLG_RT_DELETE) {
767 						FLAGS(dlmp) &= ~FLG_RT_DELETE;
768 						if (--(*delcnt) == 0)
769 							return (0);
770 						rescan = 1;
771 					}
772 				}
773 
774 				/*
775 				 * Remove this group handle from our dynamic
776 				 * deletion list.
777 				 */
778 				(void) aplist_delete_value(ghalp, ghp);
779 			}
780 		}
781 	}
782 	return (rescan);
783 }
784 
785 /*
786  * Cleanup any collection alists we've created.
787  */
788 static void
789 remove_collect(APlist *ghalp, APlist *lmalp)
790 {
791 	if (ghalp)
792 		free(ghalp);
793 	if (lmalp)
794 		free(lmalp);
795 }
796 
797 /*
798  * Remove a handle, leaving the associated objects intact.
799  */
800 void
801 free_hdl(Grp_hdl *ghp)
802 {
803 	if (--(ghp->gh_refcnt) == 0) {
804 		Grp_desc	*gdp;
805 		Aliste		idx;
806 		uintptr_t	ndx;
807 
808 		for (ALIST_TRAVERSE(ghp->gh_depends, idx, gdp)) {
809 			Rt_map	*lmp = gdp->gd_depend;
810 
811 			if (ghp->gh_ownlmp == lmp)
812 				(void) aplist_delete_value(HANDLES(lmp), ghp);
813 			(void) aplist_delete_value(GROUPS(lmp), ghp);
814 		}
815 		(void) free(ghp->gh_depends);
816 
817 		/* LINTED */
818 		ndx = (uintptr_t)ghp % HDLIST_SZ;
819 		(void) aplist_delete_value(hdl_alp[ndx], ghp);
820 
821 		(void) free(ghp);
822 	}
823 }
824 
825 /*
826  * If a load operation, using a new link-map control list, has failed, then
827  * forcibly remove the failed objects.  This failure can occur as a result
828  * of a lazy load, a dlopen(), or a filtee load, once the application is
829  * running.  If the link-map control list has not yet started relocation, then
830  * cleanup is simply a process of removing all the objects from the control
831  * list.  If relocation has begun, then other loads may have been triggered to
832  * satisfy the relocations, and thus we need to break down the control list
833  * using handles.
834  *
835  * The objects associated with this load must be part of a unique handle.  In
836  * the case of a dlopen() or filtee request, a handle will have been created.
837  * For a lazyload request, a handle must be generated so that the remove
838  * process can use the handle.
839  *
840  * During the course of processing these objects, other objects (handles) may
841  * have been loaded to satisfy relocation requirements.  After these families
842  * have successfully loaded, they will have been propagated to the same link-map
843  * control list.  The failed objects need to be removed from this list, while
844  * any successfully loaded families can be left alone, and propagated to the
845  * previous link-map control list.  By associating each load request with a
846  * handle, we can isolate the failed objects while not interfering with any
847  * successfully loaded families.
848  */
849 void
850 remove_lmc(Lm_list *lml, Rt_map *clmp, Aliste lmco, const char *name)
851 {
852 	Grp_hdl		*ghp;
853 	Grp_desc	*gdp;
854 	Aliste		idx;
855 	Lm_cntl		*lmc;
856 	Rt_map		*lmp;
857 
858 	/*
859 	 * Determine the link-map control list, and whether any object has been
860 	 * added to this list.
861 	 */
862 	/* LINTED */
863 	lmc = (Lm_cntl *)alist_item_by_offset(lml->lm_lists, lmco);
864 	if (lmc->lc_head == NULL)
865 		return;
866 
867 	DBG_CALL(Dbg_file_cleanup(lml, name, lmco));
868 
869 	/*
870 	 * Obtain a handle for the first object on the link-map control list.
871 	 * If none exists (which would occur from a lazy load request), and
872 	 * the link-map control list is being relocated, create a handle.
873 	 */
874 	lmp = lmc->lc_head;
875 	if (HANDLES(lmp)) {
876 		ghp = (Grp_hdl *)HANDLES(lmp)->apl_data[0];
877 
878 		/*
879 		 * If this is a private handle, remove this state, so as to
880 		 * prevent any attempt to remove the handle more than once.
881 		 */
882 		ghp->gh_flags &= ~GPH_PRIVATE;
883 
884 	} else if (lmc->lc_flags & LMC_FLG_RELOCATING) {
885 		/*
886 		 * Establish a handle, and should anything fail, fall through
887 		 * to remove the link-map control list.
888 		 */
889 		if (((ghp = hdl_create(lml, lmc->lc_head, NULL, GPH_PUBLIC,
890 		    GPD_ADDEPS, 0)) == NULL) ||
891 		    (hdl_initialize(ghp, lmc->lc_head, 0, 0) == 0))
892 			lmc->lc_flags &= ~LMC_FLG_RELOCATING;
893 	} else {
894 		ghp = NULL;
895 	}
896 
897 	/*
898 	 * If relocation hasn't begun, simply remove all the objects from this
899 	 * list, and any handle that may have been created.
900 	 */
901 	if ((lmc->lc_flags & LMC_FLG_RELOCATING) == 0) {
902 		remove_incomplete(lml, lmco, clmp);
903 
904 		if (ghp) {
905 			ghp->gh_refcnt = 1;
906 			free_hdl(ghp);
907 		}
908 		return;
909 	}
910 
911 	ASSERT(ghp != NULL);
912 
913 	/*
914 	 * As the objects of this handle are being forcibly removed, first
915 	 * remove any associations to objects on parent link-map control
916 	 * lists.  This breaks the bond between a caller and a hierarchy of
917 	 * dependencies represented by the handle, thus the caller doesn't lock
918 	 * the hierarchy and prevent their deletion from the generic handle
919 	 * processing or remove_hdl().
920 	 *
921 	 * This scenario can be produced when the relocation of a object
922 	 * results in vectoring through a filter that is already loaded.  The
923 	 * filtee may be on the link-map list that is presently being processed,
924 	 * however an association between the filter and filtee would have been
925 	 * established during filtee processing.  It is this association that
926 	 * must be broken to allow the objects on this link-map list to be
927 	 * removed.
928 	 */
929 	for (ALIST_TRAVERSE(ghp->gh_depends, idx, gdp)) {
930 		Rt_map	*lmp = gdp->gd_depend;
931 
932 		/*
933 		 * If this object has not been relocated, break down any
934 		 * dependency relationships the object might have established.
935 		 */
936 		if ((FLAGS(lmp) & FLG_RT_RELOCED) == 0)
937 			remove_lists(lmp, 1);
938 
939 		if (CNTL(lmp) == lmco)
940 			continue;
941 
942 		if (gdp->gd_flags & GPD_FILTER) {
943 			Dyninfo	*dip = DYNINFO(lmp);
944 			uint_t	cnt, max = DYNINFOCNT(lmp);
945 
946 			for (cnt = 0; cnt < max; cnt++, dip++) {
947 				Alist	*falp;
948 				Aliste	idx2;
949 				Pdesc	*pdp;
950 
951 				if (((falp = (Alist *)dip->di_info) == NULL) ||
952 				    ((dip->di_flags & MSK_DI_FILTER) == 0))
953 					continue;
954 
955 				for (ALIST_TRAVERSE(falp, idx2, pdp)) {
956 					if ((Grp_hdl *)pdp->pd_info == ghp) {
957 						pdp->pd_info = NULL;
958 						break;
959 					}
960 				}
961 			}
962 		}
963 		(void) aplist_delete_value(GROUPS(lmp), ghp);
964 		alist_delete(ghp->gh_depends, &idx);
965 	}
966 
967 	/*
968 	 * Having removed any callers, set the group handle reference count to
969 	 * one, and let the generic handle remover delete the associated
970 	 * objects.
971 	 */
972 	ghp->gh_refcnt = 1;
973 	(void) remove_hdl(ghp, clmp, NULL);
974 
975 	/*
976 	 * If this link-map control list still contains objects, determine the
977 	 * previous control list and move the objects.
978 	 */
979 	if (lmc->lc_head) {
980 		Lm_cntl *plmc;
981 		Aliste  plmco;
982 
983 		plmco = lmco - lml->lm_lists->al_size;
984 		/* LINTED */
985 		plmc = (Lm_cntl *)alist_item_by_offset(lml->lm_lists, plmco);
986 
987 		lm_move(lml, lmco, plmco, lmc, plmc);
988 	}
989 }
990 
991 /*
992  * Remove the objects associated with a handle.  There are two goals here, to
993  * delete the objects associated with the handle, and to remove the handle
994  * itself.  Things get a little more complex if the objects selected for
995  * deletion are filters, in this case we also need to collect their filtees,
996  * and process the combined groups as a whole.  But, care still must be exer-
997  * cised to make sure any filtees found aren't being used by filters outside of
998  * the groups we've collect.  The series of events is basically:
999  *
1000  *  -	Determine the groups (handles) that might be deletable.
1001  *
1002  *  -	Determine the objects of these handles that can be deleted.
1003  *
1004  *  -	Fire the fini's of those objects selected for deletion.
1005  *
1006  *  -	Remove all inter-dependency linked lists while the objects link-maps
1007  *	are still available.
1008  *
1009  *  -	Remove all deletable objects link-maps and unmap the objects themselves.
1010  *
1011  *  -	Remove the handle descriptors for each deleted object, and hopefully
1012  *	the whole handle.
1013  *
1014  * A handle that can't be deleted is added to an orphans list.  This list is
1015  * revisited any time another dlclose() request results in handle descriptors
1016  * being deleted.  These deleted descriptors can be sufficient to allow the
1017  * final deletion of the orphaned handles.
1018  */
1019 int
1020 remove_hdl(Grp_hdl *ghp, Rt_map *clmp, int *removed)
1021 {
1022 	Rt_map		*lmp;
1023 	int		rescan = 0;
1024 	int		delcnt = 0, rmcnt = 0, error = 0, orphans;
1025 	APlist		*lmalp = NULL, *ghalp = NULL;
1026 	Aliste		idx1, idx2;
1027 	Grp_hdl		*ghp2;
1028 	Grp_desc	*gdp;
1029 	Lm_list		*lml = NULL;
1030 
1031 	/*
1032 	 * Generate the family of groups and objects that are candidates for
1033 	 * deletion.  This consists of the objects that are explicitly defined
1034 	 * as dependencies of this handle, plus any filtee handles and their
1035 	 * associated objects.
1036 	 */
1037 	if (gdp_collect(&ghalp, &lmalp, ghp) == 0) {
1038 		remove_collect(ghalp, lmalp);
1039 		return (0);
1040 	}
1041 
1042 	DBG_CALL(Dbg_file_hdl_title(DBG_HDL_DELETE));
1043 
1044 	/*
1045 	 * Traverse the groups we've collected to determine if any filtees are
1046 	 * included.  If so, and the filtee handle is in use by a filter outside
1047 	 * of the family of objects collected for this deletion, it can not be
1048 	 * removed.
1049 	 */
1050 	for (APLIST_TRAVERSE(ghalp, idx1, ghp2)) {
1051 		Grp_hdl	*ghp = ghp2;
1052 
1053 		DBG_CALL(Dbg_file_hdl_collect(ghp, 0));
1054 
1055 		if ((ghp->gh_flags & GPH_FILTEE) == 0)
1056 			continue;
1057 
1058 		/*
1059 		 * Special case for ld.so.1.  There can be multiple instances of
1060 		 * libdl.so.1 using this handle, so although we want the handles
1061 		 * reference count to be decremented, we don't want the handle
1062 		 * removed.
1063 		 */
1064 		if (ghp->gh_flags & GPH_LDSO) {
1065 			DBG_CALL(Dbg_file_hdl_collect(ghp,
1066 			    NAME(lml_rtld.lm_head)));
1067 			aplist_delete(ghalp, &idx1);
1068 			continue;
1069 		}
1070 
1071 		for (ALIST_TRAVERSE(ghp->gh_depends, idx2, gdp)) {
1072 			Grp_hdl	*ghp3;
1073 			Aliste	idx3;
1074 
1075 			/*
1076 			 * Determine whether this dependency is the filtee's
1077 			 * parent filter, and that it isn't also an explicit
1078 			 * dependency (in which case it would have added its own
1079 			 * dependencies to the handle).
1080 			 */
1081 			if ((gdp->gd_flags &
1082 			    (GPD_FILTER | GPD_ADDEPS)) != GPD_FILTER)
1083 				continue;
1084 
1085 			lmp = gdp->gd_depend;
1086 
1087 			if (FLAGS(lmp) & FLG_RT_DELETE)
1088 				continue;
1089 
1090 			if (aplist_test(&lmalp, lmp, 0) == ALE_EXISTS)
1091 				continue;
1092 
1093 			/*
1094 			 * Remove this group handle from our dynamic deletion
1095 			 * list.  In addition, recompute the list of objects
1096 			 * that are candidates for deletion to continue this
1097 			 * group verification.
1098 			 */
1099 			DBG_CALL(Dbg_file_hdl_collect(ghp, NAME(lmp)));
1100 			aplist_delete(ghalp, &idx1);
1101 
1102 			free(lmalp);
1103 			lmalp = NULL;
1104 			for (APLIST_TRAVERSE(ghalp, idx3, ghp3)) {
1105 				Aliste		idx4;
1106 				Grp_desc	*gdp4;
1107 
1108 				for (ALIST_TRAVERSE(ghp3->gh_depends,
1109 				    idx4, gdp4))  {
1110 					if ((gdp4->gd_flags & GPD_ADDEPS) == 0)
1111 						continue;
1112 					if (aplist_test(&lmalp, gdp4->gd_depend,
1113 					    AL_CNT_GRPCLCT) == ALE_ALLOCFAIL) {
1114 						remove_collect(ghalp, lmalp);
1115 						return (0);
1116 					}
1117 				}
1118 			}
1119 			break;
1120 		}
1121 	}
1122 
1123 	/*
1124 	 * Now that we've collected all the handles dependencies, traverse the
1125 	 * collection determining whether they are a candidate for deletion.
1126 	 */
1127 	for (APLIST_TRAVERSE(lmalp, idx1, lmp)) {
1128 		/*
1129 		 * Establish which link-map list we're dealing with for later
1130 		 * .fini processing.
1131 		 */
1132 		if (lml == NULL)
1133 			lml = LIST(lmp);
1134 
1135 		/*
1136 		 * If an object isn't a candidate for deletion we'll have to
1137 		 * rescan the handle insuring that this objects dependencies
1138 		 * aren't deleted either.
1139 		 */
1140 		if (is_deletable(&lmalp, &ghalp, lmp)) {
1141 			FLAGS(lmp) |= FLG_RT_DELETE;
1142 			delcnt++;
1143 		} else
1144 			rescan = 1;
1145 	}
1146 
1147 	/*
1148 	 * Rescan the handle if any objects where found non-deletable.
1149 	 */
1150 	while (rescan)
1151 		rescan = remove_rescan(lmalp, ghalp, &delcnt);
1152 
1153 	/*
1154 	 * Now that we have determined the number of groups that are candidates
1155 	 * for removal, mark each group descriptor as a candidate for removal
1156 	 * from the group.
1157 	 */
1158 	for (APLIST_TRAVERSE(ghalp, idx1, ghp2)) {
1159 		for (ALIST_TRAVERSE(ghp2->gh_depends, idx2, gdp))
1160 			gdp->gd_flags |= GPD_REMOVE;
1161 	}
1162 
1163 	/*
1164 	 * Now that we know which objects on this handle can't be deleted
1165 	 * determine whether they still need to remain identified as belonging
1166 	 * to this group to be able to continue binding to one another.
1167 	 */
1168 	for (APLIST_TRAVERSE(ghalp, idx1, ghp2)) {
1169 		Grp_hdl	*ghp = ghp2;
1170 
1171 		for (ALIST_TRAVERSE(ghp->gh_depends, idx2, gdp)) {
1172 			Aliste		idx3;
1173 			Bnd_desc	*bdp;
1174 
1175 			lmp = gdp->gd_depend;
1176 
1177 			if (FLAGS(lmp) & FLG_RT_DELETE)
1178 				continue;
1179 
1180 			for (APLIST_TRAVERSE(DEPENDS(lmp), idx3, bdp)) {
1181 				Aliste 		idx4;
1182 				Grp_desc	*gdp4;
1183 				Rt_map		*dlmp = bdp->b_depend;
1184 
1185 				/*
1186 				 * If this dependency (dlmp) can be referenced
1187 				 * by the caller (clmp) without being part of
1188 				 * this group (ghp) then belonging to this group
1189 				 * is no longer necessary.  This can occur when
1190 				 * objects are part of multiple handles, or if a
1191 				 * previously deleted handle was moved to the
1192 				 * orphan list and has been reopened.  Note,
1193 				 * first make sure the caller can reference the
1194 				 * dependency with this group, if it can't we
1195 				 * must be bound to a filtee, so there's no need
1196 				 * to remain a part of this group either.
1197 				 */
1198 				if ((callable(lmp, dlmp, 0, 0) == 0) ||
1199 				    callable(lmp, dlmp, ghp, 0))
1200 					continue;
1201 
1202 				if (gdp->gd_flags & GPD_REMOVE)
1203 					gdp->gd_flags &= ~GPD_REMOVE;
1204 
1205 				for (ALIST_TRAVERSE(ghp->gh_depends,
1206 				    idx4, gdp4)) {
1207 					if (gdp4->gd_depend != dlmp)
1208 						continue;
1209 
1210 					if (gdp4->gd_flags & GPD_REMOVE)
1211 						gdp4->gd_flags &= ~GPD_REMOVE;
1212 				}
1213 			}
1214 		}
1215 	}
1216 
1217 	/*
1218 	 * If the owner of a handle can't be deleted and it's handle descriptor
1219 	 * must remain also, don't delete the handle at all.  Leave it for
1220 	 * possible later use.  Although it's left intact, it will still be
1221 	 * moved to the orphans list, as we might be able to revisit it on later
1222 	 * dlclose() operations and finally remove the underlying objects.  Note
1223 	 * that the handle still remains attached to the owner via the HANDLES
1224 	 * list, so that it can be re-associated to the owner if a dlopen()
1225 	 * of this object reoccurs.
1226 	 */
1227 	for (APLIST_TRAVERSE(ghalp, idx1, ghp2)) {
1228 		Grp_hdl	*ghp = ghp2;
1229 
1230 		/*
1231 		 * If this handle is already an orphan, or if it's owner is
1232 		 * deletable there's no need to inspect its dependencies.
1233 		 */
1234 		if ((ghp->gh_ownlmp == NULL) ||
1235 		    (FLAGS(ghp->gh_ownlmp) & FLG_RT_DELETE))
1236 			continue;
1237 
1238 		/*
1239 		 * Make sure all handle dependencies aren't removed or the
1240 		 * dependencies themselves aren't deleted.
1241 		 */
1242 		for (ALIST_TRAVERSE(ghp->gh_depends, idx2, gdp)) {
1243 			lmp = gdp->gd_depend;
1244 
1245 			/*
1246 			 * The first dependency of a non-orphaned handle is the
1247 			 * owner.  If the handle descriptor for this isn't
1248 			 * required there's no need to look at any other of the
1249 			 * handles dependencies.
1250 			 */
1251 			if ((lmp == ghp->gh_ownlmp) &&
1252 			    (gdp->gd_flags & GPD_REMOVE))
1253 				break;
1254 
1255 			if (gdp->gd_flags & GPD_REMOVE)
1256 				gdp->gd_flags &= ~GPD_REMOVE;
1257 			if (FLAGS(lmp) & FLG_RT_DELETE) {
1258 				FLAGS(lmp) &= ~FLG_RT_DELETE;
1259 				delcnt--;
1260 			}
1261 		}
1262 	}
1263 
1264 	/*
1265 	 * Final scan of objects to see if any objects are to to be deleted.
1266 	 * Also - display diagnostic information on what operations are to be
1267 	 * performed on the collected handles before firing .fini's (which
1268 	 * produces additional diagnostics).
1269 	 */
1270 	for (APLIST_TRAVERSE(ghalp, idx1, ghp2)) {
1271 		Grp_hdl	*ghp = ghp2;
1272 
1273 		DBG_CALL(Dbg_file_hdl_title(DBG_HDL_DELETE));
1274 
1275 		for (ALIST_TRAVERSE(ghp->gh_depends, idx2, gdp)) {
1276 			Grp_hdl	*ghp3;
1277 			Aliste	idx3;
1278 			int	flag;
1279 
1280 			lmp = gdp->gd_depend;
1281 
1282 			/*
1283 			 * Note, we must never delete a parent.  The parent
1284 			 * may already be tagged for deletion from a previous
1285 			 * dlclose(). That dlclose has triggered this dlclose(),
1286 			 * but the parents deletion is the responsibility of the
1287 			 * previous dlclose(), not this one.
1288 			 */
1289 			if ((FLAGS(lmp) & FLG_RT_DELETE) &&
1290 			    ((gdp->gd_flags & GPD_PARENT) == 0)) {
1291 				flag = DBG_DEP_DELETE;
1292 
1293 				/*
1294 				 * Remove any pathnames from the FullpathNode
1295 				 * AVL tree.  As we're about to fire .fini's,
1296 				 * it's possible this object will be required
1297 				 * again, in which case we want to make sure a
1298 				 * new version of the object gets loaded.
1299 				 */
1300 				if (FPNODE(lmp))
1301 					fpavl_remove(lmp);
1302 			} else if (gdp->gd_flags & GPD_REMOVE)
1303 				flag = DBG_DEP_REMOVE;
1304 			else
1305 				flag = DBG_DEP_REMAIN;
1306 
1307 			DBG_CALL(Dbg_file_hdl_action(ghp, lmp, flag, 0));
1308 
1309 			/*
1310 			 * If this object contains any private handles, remove
1311 			 * them now.
1312 			 */
1313 			for (APLIST_TRAVERSE(HANDLES(lmp), idx3, ghp3)) {
1314 				if (ghp3->gh_flags & GPH_PRIVATE)
1315 					free_hdl(ghp3);
1316 			}
1317 		}
1318 	}
1319 
1320 	/*
1321 	 * If there are objects to be deleted process their .fini's.
1322 	 */
1323 	if (delcnt) {
1324 		Rt_map	**tobj;
1325 
1326 		/*
1327 		 * Sort and fire all fini's of the objects selected for
1328 		 * deletion.  Note that we have to start our search from the
1329 		 * link-map head - there's no telling whether this object has
1330 		 * dependencies on objects that were loaded before it and which
1331 		 * can now be deleted.  If the tsort() fails because of an
1332 		 * allocation error then that might just be a symptom of why
1333 		 * we're here in the first place - forgo the fini's but
1334 		 * continue to try cleaning up.
1335 		 */
1336 		lml->lm_flags |= LML_FLG_OBJDELETED;
1337 
1338 		if (((tobj = tsort(lml->lm_head, delcnt,
1339 		    (RT_SORT_DELETE | RT_SORT_FWD))) != NULL) &&
1340 		    (tobj != (Rt_map **)S_ERROR)) {
1341 			error = purge_exit_handlers(lml, tobj);
1342 			call_fini(lml, tobj, clmp);
1343 		}
1344 	}
1345 
1346 	/*
1347 	 * Now that .fini processing (which may have involved new bindings)
1348 	 * is complete, remove all inter-dependency lists from those objects
1349 	 * selected for deletion.
1350 	 */
1351 	for (APLIST_TRAVERSE(lmalp, idx1, lmp)) {
1352 		Dyninfo	*dip;
1353 		uint_t	cnt, max;
1354 
1355 		if (FLAGS(lmp) & FLG_RT_DELETE)
1356 			remove_lists(lmp, 0);
1357 
1358 		/*
1359 		 * Determine whether we're dealing with a filter, and if so
1360 		 * process any inter-dependencies with its filtee's.
1361 		 */
1362 		if ((FLAGS1(lmp) & MSK_RT_FILTER) == 0)
1363 			continue;
1364 
1365 		dip = DYNINFO(lmp);
1366 		max = DYNINFOCNT(lmp);
1367 
1368 		for (cnt = 0; cnt < max; cnt++, dip++) {
1369 			Alist	*falp;
1370 			Aliste	idx2;
1371 			Pdesc	*pdp;
1372 
1373 			if (((falp = (Alist *)dip->di_info) == NULL) ||
1374 			    ((dip->di_flags & MSK_DI_FILTER) == 0))
1375 				continue;
1376 
1377 			for (ALIST_TRAVERSE(falp, idx2, pdp)) {
1378 				Grp_hdl	*ghp;
1379 
1380 				if ((pdp->pd_plen == 0) ||
1381 				    ((ghp = (Grp_hdl *)pdp->pd_info) == NULL))
1382 					continue;
1383 
1384 				/*
1385 				 * Determine whether this filtee's handle is a
1386 				 * part of the list of handles being deleted.
1387 				 */
1388 				if (aplist_test(&ghalp, ghp, 0) == ALE_EXISTS) {
1389 					/*
1390 					 * If this handle exists on the deletion
1391 					 * list, then it has been removed.  If
1392 					 * this filter isn't going to be
1393 					 * deleted, sever its reference to the
1394 					 * handle.
1395 					 */
1396 					pdp->pd_info = NULL;
1397 				} else {
1398 					/*
1399 					 * If this handle isn't on the deletion
1400 					 * list, then it must still exist.  If
1401 					 * this filter is being deleted, make
1402 					 * sure the filtees reference count
1403 					 * gets decremented.
1404 					 */
1405 					if (FLAGS(lmp) & FLG_RT_DELETE) {
1406 						(void) dlclose_core(ghp,
1407 						    lmp, lml);
1408 					}
1409 				}
1410 			}
1411 		}
1412 	}
1413 
1414 	/*
1415 	 * If called from dlclose(), determine if there are already handles on
1416 	 * the orphans list that we can reinvestigate.
1417 	 */
1418 	if ((removed == 0) && aplist_nitems(hdl_alp[HDLIST_ORP]))
1419 		orphans = 1;
1420 	else
1421 		orphans = 0;
1422 
1423 	/*
1424 	 * Finally remove any handle infrastructure and remove any objects
1425 	 * marked for deletion.
1426 	 */
1427 	for (APLIST_TRAVERSE(ghalp, idx1, ghp2)) {
1428 		Grp_hdl	*ghp = ghp2;
1429 
1430 		/*
1431 		 * If we're not dealing with orphaned handles remove this handle
1432 		 * from its present handle list.
1433 		 */
1434 		if (removed == 0) {
1435 			uintptr_t ndx;
1436 
1437 			/* LINTED */
1438 			ndx = (uintptr_t)ghp % HDLIST_SZ;
1439 			(void) aplist_delete_value(hdl_alp[ndx], ghp);
1440 		}
1441 
1442 		/*
1443 		 * Traverse each handle dependency.  Retain the dependencies
1444 		 * flags to insure we don't delete any parents (the flags
1445 		 * information is deleted as part of the alist removal that
1446 		 * occurs before we inspect the object for deletion).
1447 		 */
1448 		for (ALIST_TRAVERSE(ghp->gh_depends, idx2, gdp)) {
1449 			uint_t	flags = gdp->gd_flags;
1450 
1451 			if ((flags & GPD_REMOVE) == 0)
1452 				continue;
1453 
1454 			lmp = gdp->gd_depend;
1455 			rmcnt++;
1456 
1457 			/*
1458 			 * If this object is the owner of the handle break that
1459 			 * association in case the handle is retained.
1460 			 */
1461 			if (ghp->gh_ownlmp == lmp) {
1462 				(void) aplist_delete_value(HANDLES(lmp), ghp);
1463 				ghp->gh_ownlmp = NULL;
1464 			}
1465 
1466 			(void) aplist_delete_value(GROUPS(lmp), ghp);
1467 			alist_delete(ghp->gh_depends, &idx2);
1468 
1469 			/*
1470 			 * Complete the link-map deletion if appropriate.
1471 			 */
1472 			if ((FLAGS(lmp) & FLG_RT_DELETE) &&
1473 			    ((flags & GPD_PARENT) == 0)) {
1474 				tls_modaddrem(lmp, TM_FLG_MODREM);
1475 				remove_so(LIST(lmp), lmp, clmp);
1476 			}
1477 		}
1478 
1479 		/*
1480 		 * If we've deleted all the dependencies of the handle, finalize
1481 		 * the cleanup by removing the handle itself.
1482 		 *
1483 		 * Otherwise we're left with a handle containing one or more
1484 		 * objects that can not be deleted (they're in use by other
1485 		 * handles, non-deletable, etc.), but require to remain a part
1486 		 * of this group to allow them to continue binding to one
1487 		 * another.
1488 		 *
1489 		 * If the handles reference count is zero, or represents a
1490 		 * link-map list (dlopen(0)), then move that handle to the
1491 		 * orphans list.  Should another dlclose() operation occur that
1492 		 * results in the removal of handle descriptors, these orphan
1493 		 * handles are re-examined to determine if their deletion can
1494 		 * be completed.
1495 		 */
1496 		if (ghp->gh_depends->al_nitems == 0) {
1497 			free(ghp->gh_depends);
1498 			free(ghp);
1499 
1500 		} else if ((ghp->gh_refcnt == 0) &&
1501 		    ((ghp->gh_flags & GPH_ZERO) == 0)) {
1502 			/*
1503 			 * Move this handle to the orphans list.
1504 			 */
1505 			(void) aplist_append(&hdl_alp[HDLIST_ORP], ghp,
1506 			    AL_CNT_HANDLES);
1507 
1508 			if (DBG_ENABLED) {
1509 				DBG_CALL(Dbg_file_hdl_title(DBG_HDL_ORPHAN));
1510 				for (ALIST_TRAVERSE(ghp->gh_depends, idx1, gdp))
1511 					DBG_CALL(Dbg_file_hdl_action(ghp,
1512 					    gdp->gd_depend, DBG_DEP_ORPHAN, 0));
1513 			}
1514 		}
1515 	}
1516 
1517 	/*
1518 	 * If no handle descriptors got removed there's no point in looking for
1519 	 * orphans to process.
1520 	 */
1521 	if (rmcnt == 0)
1522 		orphans = 0;
1523 
1524 	/*
1525 	 * Cleanup any alists we've created.
1526 	 */
1527 	remove_collect(ghalp, lmalp);
1528 
1529 	/*
1530 	 * If orphan processing isn't required we're done.  If our processing
1531 	 * originated from investigating orphans, return the number of handle
1532 	 * descriptors removed as an indication whether orphan processing
1533 	 * should continue.
1534 	 */
1535 	if (orphans == 0) {
1536 		if (removed)
1537 			*removed = rmcnt;
1538 		return (error);
1539 	}
1540 
1541 	/*
1542 	 * Traverse the orphans list as many times as necessary until no
1543 	 * handle removals occur.
1544 	 */
1545 	do {
1546 		APlist		*alp;
1547 		Aliste		idx;
1548 		Grp_hdl		*ghp, *oghp = NULL;
1549 		int		title = 0;
1550 
1551 		/*
1552 		 * Effectively clean the HDLIST_ORP list.  Any object that can't
1553 		 * be removed will be re-added to the list.
1554 		 */
1555 		alp = hdl_alp[HDLIST_ORP];
1556 		hdl_alp[HDLIST_ORP] = NULL;
1557 
1558 		rescan = 0;
1559 		for (APLIST_TRAVERSE(alp, idx, ghp)) {
1560 			int	_error, _remove;
1561 
1562 			if (title++ == 0)
1563 				DBG_CALL(Dbg_file_del_rescan(ghp->gh_ownlml));
1564 
1565 			if (oghp) {
1566 				(void) aplist_delete_value(alp, oghp);
1567 				oghp = NULL;
1568 			}
1569 
1570 			if (((_error = remove_hdl(ghp, clmp, &_remove)) != 0) &&
1571 			    (error == 0))
1572 				error = _error;
1573 
1574 			if (_remove)
1575 				rescan++;
1576 
1577 			oghp = ghp;
1578 		}
1579 		if (oghp) {
1580 			(void) aplist_delete_value(alp, oghp);
1581 			oghp = NULL;
1582 		}
1583 		if (alp)
1584 			free((void *)alp);
1585 
1586 	} while (rescan && aplist_nitems(hdl_alp[HDLIST_ORP]));
1587 
1588 	return (error);
1589 }
1590