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