17c478bd9Sstevel@tonic-gate /* 27c478bd9Sstevel@tonic-gate * CDDL HEADER START 37c478bd9Sstevel@tonic-gate * 47c478bd9Sstevel@tonic-gate * The contents of this file are subject to the terms of the 55aefb655Srie * Common Development and Distribution License (the "License"). 65aefb655Srie * You may not use this file except in compliance with the License. 77c478bd9Sstevel@tonic-gate * 87c478bd9Sstevel@tonic-gate * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE 97c478bd9Sstevel@tonic-gate * or http://www.opensolaris.org/os/licensing. 107c478bd9Sstevel@tonic-gate * See the License for the specific language governing permissions 117c478bd9Sstevel@tonic-gate * and limitations under the License. 127c478bd9Sstevel@tonic-gate * 137c478bd9Sstevel@tonic-gate * When distributing Covered Code, include this CDDL HEADER in each 147c478bd9Sstevel@tonic-gate * file and include the License file at usr/src/OPENSOLARIS.LICENSE. 157c478bd9Sstevel@tonic-gate * If applicable, add the following below this CDDL HEADER, with the 167c478bd9Sstevel@tonic-gate * fields enclosed by brackets "[]" replaced with your own identifying 177c478bd9Sstevel@tonic-gate * information: Portions Copyright [yyyy] [name of copyright owner] 187c478bd9Sstevel@tonic-gate * 197c478bd9Sstevel@tonic-gate * CDDL HEADER END 207257d1b4Sraf */ 217257d1b4Sraf 227257d1b4Sraf /* 23*2020b2b6SRod Evans * Copyright (c) 1998, 2010, Oracle and/or its affiliates. All rights reserved. 247257d1b4Sraf */ 257257d1b4Sraf 267257d1b4Sraf /* 277c478bd9Sstevel@tonic-gate * Remove objects. Objects need removal from a process as part of: 287c478bd9Sstevel@tonic-gate * 292017c965SRod Evans * - a dlclose() request 307c478bd9Sstevel@tonic-gate * 312017c965SRod Evans * - tearing down a dlopen(), lazy-load, or filter hierarchy that failed to 327c478bd9Sstevel@tonic-gate * completely load 337c478bd9Sstevel@tonic-gate * 347c478bd9Sstevel@tonic-gate * Any other failure condition will result in process exit (in which case all 357c478bd9Sstevel@tonic-gate * we have to do is execute the fini's - tear down is unnecessary). 367c478bd9Sstevel@tonic-gate * 377c478bd9Sstevel@tonic-gate * Any removal of objects is therefore associated with a dlopen() handle. There 387c478bd9Sstevel@tonic-gate * is a small window between creation of the first dlopen() object and creating 397c478bd9Sstevel@tonic-gate * its handle (in which case remove_so() can get rid of the new link-map if 407c478bd9Sstevel@tonic-gate * necessary), but other than this all object removal is driven by inspecting 417c478bd9Sstevel@tonic-gate * the components of a handle. 427c478bd9Sstevel@tonic-gate * 437c478bd9Sstevel@tonic-gate * Things to note. The creation of a link-map, and its addition to the link-map 447c478bd9Sstevel@tonic-gate * list occurs in {elf|aout}_new_lm(), if this returns success the link-map is 457c478bd9Sstevel@tonic-gate * valid and added, otherwise any steps (allocations) in the process of creating 467c478bd9Sstevel@tonic-gate * the link-map would have been undone. If a failure occurs between creating 477c478bd9Sstevel@tonic-gate * the link-map and adding it to a handle, remove_so() is called to remove the 487c478bd9Sstevel@tonic-gate * link-map. If a failures occurs after a handle have been created, 497c478bd9Sstevel@tonic-gate * remove_hdl() is called to remove the handle and the link-map. 507c478bd9Sstevel@tonic-gate */ 517c478bd9Sstevel@tonic-gate 527c478bd9Sstevel@tonic-gate #include <string.h> 537c478bd9Sstevel@tonic-gate #include <stdio.h> 547c478bd9Sstevel@tonic-gate #include <unistd.h> 557c478bd9Sstevel@tonic-gate #include <dlfcn.h> 567c478bd9Sstevel@tonic-gate #include <sys/debug.h> 577c478bd9Sstevel@tonic-gate #include <sys/avl.h> 585aefb655Srie #include <libc_int.h> 595aefb655Srie #include <debug.h> 607c478bd9Sstevel@tonic-gate #include "_rtld.h" 617c478bd9Sstevel@tonic-gate #include "_audit.h" 627c478bd9Sstevel@tonic-gate #include "_elf.h" 637c478bd9Sstevel@tonic-gate #include "msg.h" 647c478bd9Sstevel@tonic-gate 657c478bd9Sstevel@tonic-gate /* 667c478bd9Sstevel@tonic-gate * Atexit callback provided by libc. As part of dlclose() determine the address 677c478bd9Sstevel@tonic-gate * ranges of all objects that are to be deleted. Pass this information to 687c478bd9Sstevel@tonic-gate * libc's pre-atexit routine. Libc will purge any registered atexit() calls 697c478bd9Sstevel@tonic-gate * related to those objects about to be deleted. 707c478bd9Sstevel@tonic-gate */ 717c478bd9Sstevel@tonic-gate static int 727c478bd9Sstevel@tonic-gate purge_exit_handlers(Lm_list *lml, Rt_map **tobj) 737c478bd9Sstevel@tonic-gate { 747c478bd9Sstevel@tonic-gate uint_t num; 757c478bd9Sstevel@tonic-gate Rt_map **_tobj; 767c478bd9Sstevel@tonic-gate Lc_addr_range_t *addr, *_addr; 777c478bd9Sstevel@tonic-gate int error; 7810a4fa49Srie int (*fptr)(Lc_addr_range_t *, uint_t); 797c478bd9Sstevel@tonic-gate 807c478bd9Sstevel@tonic-gate /* 817c478bd9Sstevel@tonic-gate * Has a callback been established? 827c478bd9Sstevel@tonic-gate */ 8310a4fa49Srie if ((fptr = lml->lm_lcs[CI_ATEXIT].lc_un.lc_func) == NULL) 847c478bd9Sstevel@tonic-gate return (0); 857c478bd9Sstevel@tonic-gate 867c478bd9Sstevel@tonic-gate /* 877c478bd9Sstevel@tonic-gate * Determine the total number of mapped segments that will be unloaded. 887c478bd9Sstevel@tonic-gate */ 897c478bd9Sstevel@tonic-gate for (num = 0, _tobj = tobj; *_tobj != NULL; _tobj++) { 907c478bd9Sstevel@tonic-gate Rt_map *lmp = *_tobj; 917c478bd9Sstevel@tonic-gate 927c478bd9Sstevel@tonic-gate num += MMAPCNT(lmp); 937c478bd9Sstevel@tonic-gate } 947c478bd9Sstevel@tonic-gate 957c478bd9Sstevel@tonic-gate /* 967c478bd9Sstevel@tonic-gate * Account for a null entry at the end of the address range array. 977c478bd9Sstevel@tonic-gate */ 987c478bd9Sstevel@tonic-gate if (num++ == 0) 997c478bd9Sstevel@tonic-gate return (0); 1007c478bd9Sstevel@tonic-gate 1017c478bd9Sstevel@tonic-gate /* 1027c478bd9Sstevel@tonic-gate * Allocate an array for the address range. 1037c478bd9Sstevel@tonic-gate */ 10456deab07SRod Evans if ((addr = malloc(num * sizeof (Lc_addr_range_t))) == NULL) 1057c478bd9Sstevel@tonic-gate return (1); 1067c478bd9Sstevel@tonic-gate 1077c478bd9Sstevel@tonic-gate /* 1087c478bd9Sstevel@tonic-gate * Fill the address range with each loadable segments size and address. 1097c478bd9Sstevel@tonic-gate */ 1107c478bd9Sstevel@tonic-gate for (_tobj = tobj, _addr = addr; *_tobj != NULL; _tobj++) { 1117c478bd9Sstevel@tonic-gate Rt_map *lmp = *_tobj; 11256deab07SRod Evans mmapobj_result_t *mpp = MMAPS(lmp); 11356deab07SRod Evans uint_t ndx; 1147c478bd9Sstevel@tonic-gate 11556deab07SRod Evans for (ndx = 0; ndx < MMAPCNT(lmp); ndx++, mpp++) { 11656deab07SRod Evans _addr->lb = (void *)(uintptr_t)(mpp->mr_addr + 11756deab07SRod Evans mpp->mr_offset); 11856deab07SRod Evans _addr->ub = (void *)(uintptr_t)(mpp->mr_addr + 11956deab07SRod Evans mpp->mr_msize); 1207c478bd9Sstevel@tonic-gate _addr++; 1217c478bd9Sstevel@tonic-gate } 1227c478bd9Sstevel@tonic-gate } 1237c478bd9Sstevel@tonic-gate _addr->lb = _addr->ub = 0; 1247c478bd9Sstevel@tonic-gate 12574a8d72aSrie leave(LIST(*tobj), 0); 12610a4fa49Srie error = (*fptr)(addr, (num - 1)); 12774a8d72aSrie (void) enter(0); 1287c478bd9Sstevel@tonic-gate 1297c478bd9Sstevel@tonic-gate /* 1307c478bd9Sstevel@tonic-gate * If we fail to converse with libc, generate an error message to 1317c478bd9Sstevel@tonic-gate * satisfy any dlerror() usage. 1327c478bd9Sstevel@tonic-gate */ 1337c478bd9Sstevel@tonic-gate if (error) 1345aefb655Srie eprintf(lml, ERR_FATAL, MSG_INTL(MSG_ARG_ATEXIT), error); 1357c478bd9Sstevel@tonic-gate 1367c478bd9Sstevel@tonic-gate free(addr); 1377c478bd9Sstevel@tonic-gate return (error); 1387c478bd9Sstevel@tonic-gate } 1397c478bd9Sstevel@tonic-gate 1407c478bd9Sstevel@tonic-gate /* 14156deab07SRod Evans * Break down an Alist containing pathname descriptors. In most instances, the 142*2020b2b6SRod Evans * Alist is removed completely. However, in some instances the alist is cleaned 143*2020b2b6SRod Evans * of all entries, but retained for later use. 1447c478bd9Sstevel@tonic-gate */ 1457c478bd9Sstevel@tonic-gate void 146*2020b2b6SRod Evans remove_alist(Alist **alpp, int complete) 1477c478bd9Sstevel@tonic-gate { 14856deab07SRod Evans Alist *alp = *alpp; 1497c478bd9Sstevel@tonic-gate 15056deab07SRod Evans if (alp) { 15156deab07SRod Evans if (complete) { 15256deab07SRod Evans free((void *)alp); 15356deab07SRod Evans *alpp = NULL; 15456deab07SRod Evans } else { 155*2020b2b6SRod Evans alist_reset(alp); 1567c478bd9Sstevel@tonic-gate } 1577c478bd9Sstevel@tonic-gate } 15856deab07SRod Evans } 1597c478bd9Sstevel@tonic-gate 1607c478bd9Sstevel@tonic-gate /* 1617c478bd9Sstevel@tonic-gate * Remove a link-map list descriptor. This is called to finalize the removal 1627c478bd9Sstevel@tonic-gate * of an entire link-map list, after all link-maps have been removed, or none 16312b8e62eSrie * got added. As load_one() can process a list of potential candidate objects, 1647c478bd9Sstevel@tonic-gate * the link-map descriptor must be maintained as each object is processed. Only 1657c478bd9Sstevel@tonic-gate * after all objects have been processed can a failure condition finally tear 1667c478bd9Sstevel@tonic-gate * down the link-map list descriptor. 1677c478bd9Sstevel@tonic-gate */ 1687c478bd9Sstevel@tonic-gate void 1697c478bd9Sstevel@tonic-gate remove_lml(Lm_list *lml) 1707c478bd9Sstevel@tonic-gate { 171b4059b01SRod Evans if (lml && (lml->lm_head == NULL)) { 1725aefb655Srie if (lml->lm_lmidstr) 1735aefb655Srie free(lml->lm_lmidstr); 1747c478bd9Sstevel@tonic-gate if (lml->lm_alp) 1757c478bd9Sstevel@tonic-gate free(lml->lm_alp); 1767c478bd9Sstevel@tonic-gate if (lml->lm_lists) 1777c478bd9Sstevel@tonic-gate free(lml->lm_lists); 178*2020b2b6SRod Evans if (lml->lm_aud_cookies) 179*2020b2b6SRod Evans free(lml->lm_aud_cookies); 1807c478bd9Sstevel@tonic-gate 1817c478bd9Sstevel@tonic-gate /* 18210a4fa49Srie * Cleanup any pending RTLDINFO in the case where it was 18310a4fa49Srie * allocated but not called (see _relocate_lmc()). 1847c478bd9Sstevel@tonic-gate */ 18510a4fa49Srie if (lml->lm_rti) 18610a4fa49Srie free(lml->lm_rti); 1877c478bd9Sstevel@tonic-gate if (lml->lm_fpavl) { 1887c478bd9Sstevel@tonic-gate /* 1897c478bd9Sstevel@tonic-gate * As we are freeing the link-map list, all nodes must 1907c478bd9Sstevel@tonic-gate * have previously been removed. 1917c478bd9Sstevel@tonic-gate */ 1927c478bd9Sstevel@tonic-gate ASSERT(avl_numnodes(lml->lm_fpavl) == 0); 1937c478bd9Sstevel@tonic-gate free(lml->lm_fpavl); 1947c478bd9Sstevel@tonic-gate } 19557ef7aa9SRod Evans (void) aplist_delete_value(dynlm_list, lml); 1967c478bd9Sstevel@tonic-gate free(lml); 1977c478bd9Sstevel@tonic-gate } 1987c478bd9Sstevel@tonic-gate } 1997c478bd9Sstevel@tonic-gate 2007c478bd9Sstevel@tonic-gate /* 2017c478bd9Sstevel@tonic-gate * Remove a link-map. This removes a link-map from its associated list and 2027c478bd9Sstevel@tonic-gate * free's up the link-map itself. Note, all components that are freed are local 2037c478bd9Sstevel@tonic-gate * to the link-map, no inter-link-map lists are operated on as these are all 2047c478bd9Sstevel@tonic-gate * broken down by dlclose() while all objects are still mapped. 2057c478bd9Sstevel@tonic-gate * 2067c478bd9Sstevel@tonic-gate * This routine is called from dlclose() to zap individual link-maps after their 2077c478bd9Sstevel@tonic-gate * interdependencies (DEPENDS(), CALLER(), handles, etc.) have been removed. 2087c478bd9Sstevel@tonic-gate * This routine is also called from the bowels of load_one() in the case of a 2097c478bd9Sstevel@tonic-gate * link-map creation failure. 2107c478bd9Sstevel@tonic-gate */ 2117c478bd9Sstevel@tonic-gate void 212*2020b2b6SRod Evans remove_so(Lm_list *lml, Rt_map *lmp, Rt_map *clmp) 2137c478bd9Sstevel@tonic-gate { 2147c478bd9Sstevel@tonic-gate Dyninfo *dip; 2157c478bd9Sstevel@tonic-gate 216b4059b01SRod Evans if (lmp == NULL) 2177c478bd9Sstevel@tonic-gate return; 2187c478bd9Sstevel@tonic-gate 2197c478bd9Sstevel@tonic-gate /* 2207c478bd9Sstevel@tonic-gate * Unlink the link map from the link-map list. 2217c478bd9Sstevel@tonic-gate */ 2227c478bd9Sstevel@tonic-gate if (lml && lmp) 223*2020b2b6SRod Evans lm_delete(lml, lmp, clmp); 2247c478bd9Sstevel@tonic-gate 2257c478bd9Sstevel@tonic-gate /* 22610a4fa49Srie * If this object contributed any local external vectors for the current 22710a4fa49Srie * link-map list, remove the vectors. If this object contributed any 22810a4fa49Srie * global external vectors we should find some new candidates, or leave 22910a4fa49Srie * this object lying around. 2307c478bd9Sstevel@tonic-gate */ 23110a4fa49Srie if (lml) { 23210a4fa49Srie int tag; 23310a4fa49Srie 23410a4fa49Srie for (tag = 0; tag < CI_MAX; tag++) { 23510a4fa49Srie if (lml->lm_lcs[tag].lc_lmp == lmp) { 236b4059b01SRod Evans lml->lm_lcs[tag].lc_lmp = NULL; 23710a4fa49Srie lml->lm_lcs[tag].lc_un.lc_val = 0; 23810a4fa49Srie } 23910a4fa49Srie if (glcs[tag].lc_lmp == lmp) { 240b4059b01SRod Evans ASSERT(glcs[tag].lc_lmp != NULL); 241b4059b01SRod Evans glcs[tag].lc_lmp = NULL; 24210a4fa49Srie glcs[tag].lc_un.lc_val = 0; 24310a4fa49Srie } 24410a4fa49Srie } 2457c478bd9Sstevel@tonic-gate } 2467c478bd9Sstevel@tonic-gate 2475aefb655Srie DBG_CALL(Dbg_file_delete(lmp)); 2487c478bd9Sstevel@tonic-gate 2497c478bd9Sstevel@tonic-gate /* 250*2020b2b6SRod Evans * If this object is an auditor, determine whether any link-map lists 251*2020b2b6SRod Evans * are maintaining cookies to represent this auditor. These cookies 252*2020b2b6SRod Evans * are established for local auditing preinit and activity events. 253*2020b2b6SRod Evans */ 254*2020b2b6SRod Evans if (FLAGS(lmp) & FLG_RT_AUDIT) { 255*2020b2b6SRod Evans Lm_list *nlml; 256*2020b2b6SRod Evans Aliste idx1; 257*2020b2b6SRod Evans 258*2020b2b6SRod Evans for (APLIST_TRAVERSE(dynlm_list, idx1, nlml)) { 259*2020b2b6SRod Evans Rt_map *hlmp = nlml->lm_head; 260*2020b2b6SRod Evans Audit_client *acp; 261*2020b2b6SRod Evans Aliste idx2; 262*2020b2b6SRod Evans 263*2020b2b6SRod Evans if ((hlmp == NULL) || (FLAGS(hlmp) & FLG_RT_AUDIT)) 264*2020b2b6SRod Evans continue; 265*2020b2b6SRod Evans 266*2020b2b6SRod Evans for (ALIST_TRAVERSE(nlml->lm_aud_cookies, idx2, acp)) { 267*2020b2b6SRod Evans if (acp->ac_lmp != lmp) { 268*2020b2b6SRod Evans alist_delete(nlml->lm_aud_cookies, 269*2020b2b6SRod Evans &idx2); 270*2020b2b6SRod Evans break; 271*2020b2b6SRod Evans } 272*2020b2b6SRod Evans } 273*2020b2b6SRod Evans } 274*2020b2b6SRod Evans } 275*2020b2b6SRod Evans 276*2020b2b6SRod Evans /* 277c1c6f601Srie * If this is a temporary link-map, put in place to facilitate the 278c1c6f601Srie * link-edit or a relocatable object, then the link-map contains no 279c1c6f601Srie * information that needs to be cleaned up. 280c1c6f601Srie */ 281c1c6f601Srie if (FLAGS(lmp) & FLG_RT_OBJECT) 282c1c6f601Srie return; 283c1c6f601Srie 284c1c6f601Srie /* 2857c478bd9Sstevel@tonic-gate * Remove any FullpathNode AVL names if they still exist. 2867c478bd9Sstevel@tonic-gate */ 2877c478bd9Sstevel@tonic-gate if (FPNODE(lmp)) 2887c478bd9Sstevel@tonic-gate fpavl_remove(lmp); 2897c478bd9Sstevel@tonic-gate 2907c478bd9Sstevel@tonic-gate /* 2917c478bd9Sstevel@tonic-gate * Remove any alias names. 2927c478bd9Sstevel@tonic-gate */ 29356deab07SRod Evans if (ALIAS(lmp)) 2947c478bd9Sstevel@tonic-gate free(ALIAS(lmp)); 2957c478bd9Sstevel@tonic-gate 2967c478bd9Sstevel@tonic-gate /* 2977c478bd9Sstevel@tonic-gate * Remove any of this objects filtee infrastructure. The filtees them- 2987c478bd9Sstevel@tonic-gate * selves have already been removed. 2997c478bd9Sstevel@tonic-gate */ 30056deab07SRod Evans if (((dip = DYNINFO(lmp)) != NULL) && (FLAGS1(lmp) & MSK_RT_FILTER)) { 3017c478bd9Sstevel@tonic-gate uint_t cnt, max = DYNINFOCNT(lmp); 3027c478bd9Sstevel@tonic-gate 3037c478bd9Sstevel@tonic-gate for (cnt = 0; cnt < max; cnt++, dip++) { 30456deab07SRod Evans if ((dip->di_info == NULL) || 30556deab07SRod Evans ((dip->di_flags & MSK_DI_FILTER) == 0)) 30656deab07SRod Evans continue; 30756deab07SRod Evans 308*2020b2b6SRod Evans remove_alist((Alist **)&(dip->di_info), 1); 3097c478bd9Sstevel@tonic-gate } 3107c478bd9Sstevel@tonic-gate } 3117c478bd9Sstevel@tonic-gate 3127c478bd9Sstevel@tonic-gate /* 3137c478bd9Sstevel@tonic-gate * Deallocate any remaining cruft and free the link-map. 3147c478bd9Sstevel@tonic-gate */ 3157c478bd9Sstevel@tonic-gate if (RLIST(lmp)) 316*2020b2b6SRod Evans remove_alist(&RLIST(lmp), 1); 3177c478bd9Sstevel@tonic-gate 3187c478bd9Sstevel@tonic-gate if (AUDITORS(lmp)) 3197247f888Srie audit_desc_cleanup(lmp); 3207c478bd9Sstevel@tonic-gate if (AUDINFO(lmp)) 3217247f888Srie audit_info_cleanup(lmp); 3227c478bd9Sstevel@tonic-gate 323cce0e03bSab196087 /* 324cce0e03bSab196087 * Note that COPY_R() and COPY_S() reference the same memory 325cce0e03bSab196087 * location, and that we want to release the memory referenced 326cce0e03bSab196087 * without regard to which list it logically belongs to. We can 327cce0e03bSab196087 * use either pointer to do this. 328cce0e03bSab196087 */ 329cce0e03bSab196087 if (COPY_R(lmp)) 330cce0e03bSab196087 free(COPY_R(lmp)); 3317c478bd9Sstevel@tonic-gate 3327c478bd9Sstevel@tonic-gate /* 3337c478bd9Sstevel@tonic-gate * During a dlclose() any groups this object was a part of will have 3347c478bd9Sstevel@tonic-gate * been torn down. However, we can get here to remove an object that 3357c478bd9Sstevel@tonic-gate * has failed to load, perhaps because its addition to a handle failed. 3367c478bd9Sstevel@tonic-gate * Therefore if this object indicates that its part of a group tear 3377c478bd9Sstevel@tonic-gate * these associations down. 3387c478bd9Sstevel@tonic-gate */ 339cce0e03bSab196087 if (GROUPS(lmp) != NULL) { 340cce0e03bSab196087 Aliste idx1; 341cce0e03bSab196087 Grp_hdl *ghp; 3427c478bd9Sstevel@tonic-gate 343cce0e03bSab196087 for (APLIST_TRAVERSE(GROUPS(lmp), idx1, ghp)) { 3447c478bd9Sstevel@tonic-gate Grp_desc *gdp; 345cce0e03bSab196087 Aliste idx2; 3467c478bd9Sstevel@tonic-gate 347cce0e03bSab196087 for (ALIST_TRAVERSE(ghp->gh_depends, idx2, gdp)) { 3487c478bd9Sstevel@tonic-gate if (gdp->gd_depend != lmp) 3497c478bd9Sstevel@tonic-gate continue; 3507c478bd9Sstevel@tonic-gate 351cce0e03bSab196087 alist_delete(ghp->gh_depends, &idx2); 3527c478bd9Sstevel@tonic-gate break; 3537c478bd9Sstevel@tonic-gate } 3547c478bd9Sstevel@tonic-gate } 3557c478bd9Sstevel@tonic-gate free(GROUPS(lmp)); 3567c478bd9Sstevel@tonic-gate } 3577c478bd9Sstevel@tonic-gate if (HANDLES(lmp)) 3587c478bd9Sstevel@tonic-gate free(HANDLES(lmp)); 3597c478bd9Sstevel@tonic-gate 3607c478bd9Sstevel@tonic-gate /* 3617c478bd9Sstevel@tonic-gate * Clean up reglist if needed 3627c478bd9Sstevel@tonic-gate */ 36356deab07SRod Evans if (reglist) { 3647c478bd9Sstevel@tonic-gate Reglist *cur, *prv, *del; 3657c478bd9Sstevel@tonic-gate 3667c478bd9Sstevel@tonic-gate cur = prv = reglist; 36756deab07SRod Evans while (cur) { 3687c478bd9Sstevel@tonic-gate if (cur->rl_lmp == lmp) { 3697c478bd9Sstevel@tonic-gate del = cur; 3707c478bd9Sstevel@tonic-gate if (cur == reglist) { 3717c478bd9Sstevel@tonic-gate reglist = cur->rl_next; 3727c478bd9Sstevel@tonic-gate cur = prv = reglist; 3737c478bd9Sstevel@tonic-gate } else { 3747c478bd9Sstevel@tonic-gate prv->rl_next = cur->rl_next; 3757c478bd9Sstevel@tonic-gate cur = cur->rl_next; 3767c478bd9Sstevel@tonic-gate } 3777c478bd9Sstevel@tonic-gate free(del); 3787c478bd9Sstevel@tonic-gate } else { 3797c478bd9Sstevel@tonic-gate prv = cur; 3807c478bd9Sstevel@tonic-gate cur = cur->rl_next; 3817c478bd9Sstevel@tonic-gate } 3827c478bd9Sstevel@tonic-gate } 3837c478bd9Sstevel@tonic-gate } 3847c478bd9Sstevel@tonic-gate 3857247f888Srie /* 38656deab07SRod Evans * If this link map represents a relocatable object concatenation, then 38756deab07SRod Evans * the image was simply generated in allocated memory. Free the memory. 38856deab07SRod Evans * Note: memory maps were fabricated for the relocatable object, and 38956deab07SRod Evans * the mapping infrastructure must be free'd, but there are no address 39056deab07SRod Evans * mappings that must be unmapped. 3917247f888Srie * 39256deab07SRod Evans * Otherwise, unmap the object. 3937247f888Srie */ 39456deab07SRod Evans if (FLAGS(lmp) & FLG_RT_IMGALLOC) 39556deab07SRod Evans free((void *)ADDR(lmp)); 39656deab07SRod Evans 39708278a5eSRod Evans if (CAPCHAIN(lmp)) 39808278a5eSRod Evans free((void *)CAPCHAIN(lmp)); 39908278a5eSRod Evans 40056deab07SRod Evans if (MMAPS(lmp)) { 40156deab07SRod Evans if ((FLAGS(lmp) & FLG_RT_IMGALLOC) == 0) 40256deab07SRod Evans unmap_obj(MMAPS(lmp), MMAPCNT(lmp)); 40356deab07SRod Evans free(MMAPS(lmp)); 40456deab07SRod Evans } 4057247f888Srie 4067c478bd9Sstevel@tonic-gate free(lmp); 4077c478bd9Sstevel@tonic-gate } 4087c478bd9Sstevel@tonic-gate 4097c478bd9Sstevel@tonic-gate /* 4107c478bd9Sstevel@tonic-gate * Traverse an objects dependency list removing callers and dependencies. 4117c478bd9Sstevel@tonic-gate * There's a chicken and egg problem with tearing down link-maps. Any 41275e7992aSrie * relationship between link-maps is maintained on a DEPENDS list, and an 41375e7992aSrie * associated CALLERS list. These lists can't be broken down at the time a 41475e7992aSrie * single link-map is removed, as any related link-map may have already been 41575e7992aSrie * removed. Thus, lists between link-maps must be broken down before the 41675e7992aSrie * individual link-maps themselves. 4177c478bd9Sstevel@tonic-gate */ 41856deab07SRod Evans static void 4197c478bd9Sstevel@tonic-gate remove_lists(Rt_map *lmp, int lazy) 4207c478bd9Sstevel@tonic-gate { 421cce0e03bSab196087 Aliste idx1; 422cce0e03bSab196087 Bnd_desc *bdp; 4237c478bd9Sstevel@tonic-gate 4247c478bd9Sstevel@tonic-gate /* 4257c478bd9Sstevel@tonic-gate * First, traverse this objects dependencies. 4267c478bd9Sstevel@tonic-gate */ 427cce0e03bSab196087 for (APLIST_TRAVERSE(DEPENDS(lmp), idx1, bdp)) { 4287c478bd9Sstevel@tonic-gate Rt_map *dlmp = bdp->b_depend; 4297c478bd9Sstevel@tonic-gate 4307c478bd9Sstevel@tonic-gate /* 4317c478bd9Sstevel@tonic-gate * Remove this object from the dependencies callers. 4327c478bd9Sstevel@tonic-gate */ 433cce0e03bSab196087 (void) aplist_delete_value(CALLERS(dlmp), bdp); 4347c478bd9Sstevel@tonic-gate free(bdp); 4357c478bd9Sstevel@tonic-gate } 4367c478bd9Sstevel@tonic-gate if (DEPENDS(lmp)) { 4377c478bd9Sstevel@tonic-gate free(DEPENDS(lmp)); 438cce0e03bSab196087 DEPENDS(lmp) = NULL; 4397c478bd9Sstevel@tonic-gate } 4407c478bd9Sstevel@tonic-gate 4417c478bd9Sstevel@tonic-gate /* 4427c478bd9Sstevel@tonic-gate * Second, traverse this objects callers. 4437c478bd9Sstevel@tonic-gate */ 444cce0e03bSab196087 for (APLIST_TRAVERSE(CALLERS(lmp), idx1, bdp)) { 4457c478bd9Sstevel@tonic-gate Rt_map *clmp = bdp->b_caller; 44675e7992aSrie Dyninfo *dip; 4477c478bd9Sstevel@tonic-gate 4487c478bd9Sstevel@tonic-gate /* 4497c478bd9Sstevel@tonic-gate * If we're removing an object that was triggered by a lazyload, 4507c478bd9Sstevel@tonic-gate * remove the callers DYNINFO() entry and bump the lazy counts. 4517c478bd9Sstevel@tonic-gate * This reinitialization of the lazy information allows a lazy 4527c478bd9Sstevel@tonic-gate * object to be reloaded again later. Although we may be 4537c478bd9Sstevel@tonic-gate * breaking down a group of lazyloaded objects because one has 4547c478bd9Sstevel@tonic-gate * failed to relocate, it's possible that one or more of the 4557c478bd9Sstevel@tonic-gate * individual objects can be reloaded without a problem. 4567c478bd9Sstevel@tonic-gate */ 45775e7992aSrie if (lazy && ((dip = DYNINFO(clmp)) != NULL)) { 4587c478bd9Sstevel@tonic-gate uint_t cnt, max = DYNINFOCNT(clmp); 4597c478bd9Sstevel@tonic-gate 4607c478bd9Sstevel@tonic-gate for (cnt = 0; cnt < max; cnt++, dip++) { 46175e7992aSrie if ((dip->di_flags & FLG_DI_LAZY) == 0) 4627c478bd9Sstevel@tonic-gate continue; 4637c478bd9Sstevel@tonic-gate 4647c478bd9Sstevel@tonic-gate if (dip->di_info == (void *)lmp) { 465b4059b01SRod Evans dip->di_info = NULL; 4667c478bd9Sstevel@tonic-gate 4677c478bd9Sstevel@tonic-gate if (LAZY(clmp)++ == 0) 4687c478bd9Sstevel@tonic-gate LIST(clmp)->lm_lazy++; 4697c478bd9Sstevel@tonic-gate } 4707c478bd9Sstevel@tonic-gate } 4717c478bd9Sstevel@tonic-gate } 4727c478bd9Sstevel@tonic-gate 473cce0e03bSab196087 (void) aplist_delete_value(DEPENDS(clmp), bdp); 4747c478bd9Sstevel@tonic-gate free(bdp); 4757c478bd9Sstevel@tonic-gate } 4767c478bd9Sstevel@tonic-gate if (CALLERS(lmp)) { 4777c478bd9Sstevel@tonic-gate free(CALLERS(lmp)); 478cce0e03bSab196087 CALLERS(lmp) = NULL; 4797c478bd9Sstevel@tonic-gate } 4807c478bd9Sstevel@tonic-gate } 4817c478bd9Sstevel@tonic-gate 4827c478bd9Sstevel@tonic-gate /* 4837c478bd9Sstevel@tonic-gate * Delete any temporary link-map control list. 4847c478bd9Sstevel@tonic-gate */ 4857c478bd9Sstevel@tonic-gate void 4867c478bd9Sstevel@tonic-gate remove_cntl(Lm_list *lml, Aliste lmco) 4877c478bd9Sstevel@tonic-gate { 4887c478bd9Sstevel@tonic-gate Aliste _lmco = lmco; 4897c478bd9Sstevel@tonic-gate #if DEBUG 490cce0e03bSab196087 Lm_cntl *lmc; 491cce0e03bSab196087 492cce0e03bSab196087 lmc = (Lm_cntl *)alist_item_by_offset(lml->lm_lists, lmco); 4937c478bd9Sstevel@tonic-gate 4947c478bd9Sstevel@tonic-gate /* 4957c478bd9Sstevel@tonic-gate * This element should be empty. 4967c478bd9Sstevel@tonic-gate */ 497b4059b01SRod Evans ASSERT(lmc->lc_head == NULL); 4987c478bd9Sstevel@tonic-gate #endif 499cce0e03bSab196087 alist_delete_by_offset(lml->lm_lists, &_lmco); 5007c478bd9Sstevel@tonic-gate } 5017c478bd9Sstevel@tonic-gate 5027c478bd9Sstevel@tonic-gate /* 5037c478bd9Sstevel@tonic-gate * If a lazy loaded object, or filtee fails to load, possibly because it, or 5047c478bd9Sstevel@tonic-gate * one of its dependencies can't be relocated, then tear down any objects 5057c478bd9Sstevel@tonic-gate * that are apart of this link-map control list. 5067c478bd9Sstevel@tonic-gate */ 50756deab07SRod Evans static void 508*2020b2b6SRod Evans remove_incomplete(Lm_list *lml, Aliste lmco, Rt_map *clmp) 5097c478bd9Sstevel@tonic-gate { 5107c478bd9Sstevel@tonic-gate Rt_map *lmp; 5117c478bd9Sstevel@tonic-gate Lm_cntl *lmc; 5127c478bd9Sstevel@tonic-gate 5137c478bd9Sstevel@tonic-gate /* LINTED */ 514cce0e03bSab196087 lmc = (Lm_cntl *)alist_item_by_offset(lml->lm_lists, lmco); 5157c478bd9Sstevel@tonic-gate 5167c478bd9Sstevel@tonic-gate /* 517*2020b2b6SRod Evans * If auditing is in effect, the loading of these objects might have 518*2020b2b6SRod Evans * resulted in la_objopen() events being posted. Normally, an 519*2020b2b6SRod Evans * la_objclose() event is posted after an object's .fini is executed, 520*2020b2b6SRod Evans * just before the objects are unloaded. These failed objects do not 521*2020b2b6SRod Evans * have their .fini's executed, but an la_objclose() event should still 522*2020b2b6SRod Evans * be posted to any auditors. 523*2020b2b6SRod Evans */ 524*2020b2b6SRod Evans if ((lml->lm_tflags | AFLAGS(clmp)) & LML_TFLG_AUD_OBJCLOSE) { 525*2020b2b6SRod Evans for (lmp = lmc->lc_head; lmp; lmp = NEXT_RT_MAP(lmp)) 526*2020b2b6SRod Evans audit_objclose(lmp, clmp); 527*2020b2b6SRod Evans } 528*2020b2b6SRod Evans 529*2020b2b6SRod Evans /* 530*2020b2b6SRod Evans * Remove any lists that may point between objects. 5317c478bd9Sstevel@tonic-gate */ 532cb511613SAli Bahrami for (lmp = lmc->lc_head; lmp; lmp = NEXT_RT_MAP(lmp)) 5337c478bd9Sstevel@tonic-gate remove_lists(lmp, 1); 5347c478bd9Sstevel@tonic-gate 5357c478bd9Sstevel@tonic-gate /* 5367c478bd9Sstevel@tonic-gate * Finally, remove each object. remove_so() calls lm_delete(), thus 5377c478bd9Sstevel@tonic-gate * effectively the link-map control head gets updated to point to the 5387c478bd9Sstevel@tonic-gate * next link-map. 5397c478bd9Sstevel@tonic-gate */ 540b4059b01SRod Evans while ((lmp = lmc->lc_head) != NULL) 541*2020b2b6SRod Evans remove_so(lml, lmp, clmp); 5427c478bd9Sstevel@tonic-gate 543b4059b01SRod Evans lmc->lc_head = lmc->lc_tail = NULL; 5447c478bd9Sstevel@tonic-gate } 5457c478bd9Sstevel@tonic-gate 5467c478bd9Sstevel@tonic-gate /* 5477c478bd9Sstevel@tonic-gate * Determine whether an object is deletable. 5487c478bd9Sstevel@tonic-gate */ 549cce0e03bSab196087 static int 550cce0e03bSab196087 is_deletable(APlist **lmalp, APlist **ghalp, Rt_map *lmp) 5517c478bd9Sstevel@tonic-gate { 552cce0e03bSab196087 Aliste idx; 553cce0e03bSab196087 Bnd_desc *bdp; 554cce0e03bSab196087 Grp_hdl *ghp; 5557c478bd9Sstevel@tonic-gate 5567c478bd9Sstevel@tonic-gate /* 5577c478bd9Sstevel@tonic-gate * If the object hasn't yet been relocated take this as a sign that 5587c478bd9Sstevel@tonic-gate * it's loading failed, thus we're here to cleanup. If the object is 5597c478bd9Sstevel@tonic-gate * relocated it will only be retained if it was marked non-deletable, 5607c478bd9Sstevel@tonic-gate * and exists on the main link-map control list. 5617c478bd9Sstevel@tonic-gate */ 5627c478bd9Sstevel@tonic-gate if ((FLAGS(lmp) & FLG_RT_RELOCED) && 563cce0e03bSab196087 (MODE(lmp) & RTLD_NODELETE) && (CNTL(lmp) == ALIST_OFF_DATA)) 5647c478bd9Sstevel@tonic-gate return (0); 5657c478bd9Sstevel@tonic-gate 5667c478bd9Sstevel@tonic-gate /* 5677c478bd9Sstevel@tonic-gate * If this object is the head of a handle that has not been captured as 5687c478bd9Sstevel@tonic-gate * a candidate for deletion, then this object is in use from a dlopen() 5697c478bd9Sstevel@tonic-gate * outside of the scope of this dlclose() family. Dlopen'ed objects, 5707c478bd9Sstevel@tonic-gate * and filtees, have group descriptors for their callers. Typically 5717c478bd9Sstevel@tonic-gate * this parent will have callers that are not apart of this dlclose() 5727c478bd9Sstevel@tonic-gate * family, and thus would be caught by the CALLERS test below. However, 5737c478bd9Sstevel@tonic-gate * if the caller had itself been dlopen'ed, it may not have any explicit 574*2020b2b6SRod Evans * callers registered for itself. Thus, by looking for objects with 5757c478bd9Sstevel@tonic-gate * handles we can ferret out these outsiders. 5767c478bd9Sstevel@tonic-gate */ 577cce0e03bSab196087 for (APLIST_TRAVERSE(HANDLES(lmp), idx, ghp)) { 5782017c965SRod Evans /* 5792017c965SRod Evans * If this is a private handle, then the handle isn't referenced 5802017c965SRod Evans * from outside of the group of objects being deleted, and can 5812017c965SRod Evans * be ignored when evaluating objects for deletion. 5822017c965SRod Evans */ 5832017c965SRod Evans if (ghp->gh_flags & GPH_PRIVATE) 5842017c965SRod Evans continue; 585cce0e03bSab196087 if (aplist_test(ghalp, ghp, 0) != ALE_EXISTS) 5867c478bd9Sstevel@tonic-gate return (0); 5877c478bd9Sstevel@tonic-gate } 5887c478bd9Sstevel@tonic-gate 5897c478bd9Sstevel@tonic-gate /* 5907c478bd9Sstevel@tonic-gate * If this object is called by any object outside of the family of 5917c478bd9Sstevel@tonic-gate * objects selected for deletion, it can't be deleted. 5927c478bd9Sstevel@tonic-gate */ 593cce0e03bSab196087 for (APLIST_TRAVERSE(CALLERS(lmp), idx, bdp)) { 5942017c965SRod Evans if (aplist_test(lmalp, bdp->b_caller, 0) != ALE_EXISTS) 5957c478bd9Sstevel@tonic-gate return (0); 5967c478bd9Sstevel@tonic-gate } 5977c478bd9Sstevel@tonic-gate 5987c478bd9Sstevel@tonic-gate /* 5997c478bd9Sstevel@tonic-gate * This object is a candidate for deletion. 6007c478bd9Sstevel@tonic-gate */ 6017c478bd9Sstevel@tonic-gate return (1); 6027c478bd9Sstevel@tonic-gate } 6037c478bd9Sstevel@tonic-gate 6047c478bd9Sstevel@tonic-gate /* 6057c478bd9Sstevel@tonic-gate * Collect the groups (handles) and associated objects that are candidates for 6067c478bd9Sstevel@tonic-gate * deletion. The criteria for deleting an object is whether it is only refer- 6077c478bd9Sstevel@tonic-gate * enced from the objects within the groups that are candidates for deletion. 6087c478bd9Sstevel@tonic-gate */ 6097c478bd9Sstevel@tonic-gate static int 610cce0e03bSab196087 gdp_collect(APlist **ghalpp, APlist **lmalpp, Grp_hdl *ghp1) 6117c478bd9Sstevel@tonic-gate { 61256deab07SRod Evans Aliste idx1; 6137c478bd9Sstevel@tonic-gate Grp_desc *gdp; 6147c478bd9Sstevel@tonic-gate int action; 6157c478bd9Sstevel@tonic-gate 6167c478bd9Sstevel@tonic-gate /* 6177c478bd9Sstevel@tonic-gate * Add this group to our group collection. If it isn't added either an 6187c478bd9Sstevel@tonic-gate * allocation has failed, or it already exists. 6197c478bd9Sstevel@tonic-gate */ 620cce0e03bSab196087 if ((action = aplist_test(ghalpp, ghp1, AL_CNT_GRPCLCT)) != 621cce0e03bSab196087 ALE_CREATE) 6227c478bd9Sstevel@tonic-gate return (action); 6237c478bd9Sstevel@tonic-gate 6247c478bd9Sstevel@tonic-gate /* 6257c478bd9Sstevel@tonic-gate * Traverse the dependencies of the group and collect the associated 6267c478bd9Sstevel@tonic-gate * objects. 6277c478bd9Sstevel@tonic-gate */ 62856deab07SRod Evans for (ALIST_TRAVERSE(ghp1->gh_depends, idx1, gdp)) { 6297c478bd9Sstevel@tonic-gate Rt_map *lmp = gdp->gd_depend; 6307c478bd9Sstevel@tonic-gate 6317c478bd9Sstevel@tonic-gate /* 6327c478bd9Sstevel@tonic-gate * We only want to process dependencies for deletion. Although 6337c478bd9Sstevel@tonic-gate * we want to purge group descriptors for parents, we don't want 6347c478bd9Sstevel@tonic-gate * to analyze the parent itself for additional filters or 6357c478bd9Sstevel@tonic-gate * deletion. 6367c478bd9Sstevel@tonic-gate */ 637efb9e8b8Srie if ((gdp->gd_flags & GPD_PARENT) || 638efb9e8b8Srie ((gdp->gd_flags & GPD_ADDEPS) == 0)) 6397c478bd9Sstevel@tonic-gate continue; 6407c478bd9Sstevel@tonic-gate 641cce0e03bSab196087 if ((action = aplist_test(lmalpp, lmp, AL_CNT_GRPCLCT)) == 642cce0e03bSab196087 ALE_ALLOCFAIL) 6437c478bd9Sstevel@tonic-gate return (0); 6447c478bd9Sstevel@tonic-gate if (action == ALE_EXISTS) 6457c478bd9Sstevel@tonic-gate continue; 6467c478bd9Sstevel@tonic-gate 6477c478bd9Sstevel@tonic-gate /* 6481c272b97Srie * If this object is a candidate for deletion, determine if the 6491c272b97Srie * object provides any filtees. If so, the filter groups are 6501c272b97Srie * added to the group collection. 6511c272b97Srie * 6521c272b97Srie * An object is a candidate for deletion if: 6531c272b97Srie * 6542017c965SRod Evans * - the object hasn't yet been relocated, in which case 6551c272b97Srie * we're here to clean up a failed load, or 6562017c965SRod Evans * - the object doesn't reside on the base link-map control 6571c272b97Srie * list, in which case a group of objects, typically 6581c272b97Srie * lazily loaded, or filtees, need cleaning up, or 6592017c965SRod Evans * - the object isn't tagged as non-deletable. 6607c478bd9Sstevel@tonic-gate */ 6617c478bd9Sstevel@tonic-gate if ((((FLAGS(lmp) & FLG_RT_RELOCED) == 0) || 662cce0e03bSab196087 (CNTL(lmp) != ALIST_OFF_DATA) || 6637c478bd9Sstevel@tonic-gate ((MODE(lmp) & RTLD_NODELETE) == 0)) && 6647c478bd9Sstevel@tonic-gate (FLAGS1(lmp) & MSK_RT_FILTER)) { 6657c478bd9Sstevel@tonic-gate Dyninfo *dip = DYNINFO(lmp); 6667c478bd9Sstevel@tonic-gate uint_t cnt, max = DYNINFOCNT(lmp); 6677c478bd9Sstevel@tonic-gate 6687c478bd9Sstevel@tonic-gate for (cnt = 0; cnt < max; cnt++, dip++) { 66956deab07SRod Evans Alist *falp; 67056deab07SRod Evans Aliste idx2; 67156deab07SRod Evans Pdesc *pdp; 6727c478bd9Sstevel@tonic-gate 67356deab07SRod Evans if (((falp = (Alist *)dip->di_info) == NULL) || 6747c478bd9Sstevel@tonic-gate ((dip->di_flags & MSK_DI_FILTER) == 0)) 6757c478bd9Sstevel@tonic-gate continue; 6767c478bd9Sstevel@tonic-gate 67756deab07SRod Evans for (ALIST_TRAVERSE(falp, idx2, pdp)) { 6787c478bd9Sstevel@tonic-gate Grp_hdl *ghp2; 6797c478bd9Sstevel@tonic-gate 68056deab07SRod Evans if ((pdp->pd_plen == 0) || ((ghp2 = 68156deab07SRod Evans (Grp_hdl *)pdp->pd_info) == NULL)) 6827c478bd9Sstevel@tonic-gate continue; 6837c478bd9Sstevel@tonic-gate 6847c478bd9Sstevel@tonic-gate if (gdp_collect(ghalpp, lmalpp, 6857c478bd9Sstevel@tonic-gate ghp2) == 0) 6867c478bd9Sstevel@tonic-gate return (0); 6877c478bd9Sstevel@tonic-gate } 6887c478bd9Sstevel@tonic-gate } 6897c478bd9Sstevel@tonic-gate } 6907c478bd9Sstevel@tonic-gate } 6917c478bd9Sstevel@tonic-gate return (1); 6927c478bd9Sstevel@tonic-gate } 6937c478bd9Sstevel@tonic-gate 6947c478bd9Sstevel@tonic-gate /* 6957c478bd9Sstevel@tonic-gate * Traverse the list of deletable candidates. If an object can't be deleted 6967c478bd9Sstevel@tonic-gate * then neither can its dependencies or filtees. Any object that is cleared 6977c478bd9Sstevel@tonic-gate * from being deleted drops the deletion count, plus, if there are no longer 6987c478bd9Sstevel@tonic-gate * any deletions pending we can discontinue any further processing. 6997c478bd9Sstevel@tonic-gate */ 7007c478bd9Sstevel@tonic-gate static int 701cce0e03bSab196087 remove_rescan(APlist *lmalp, APlist *ghalp, int *delcnt) 7027c478bd9Sstevel@tonic-gate { 703cce0e03bSab196087 Aliste idx1; 704cce0e03bSab196087 Rt_map *lmp; 7057c478bd9Sstevel@tonic-gate int rescan = 0; 7067c478bd9Sstevel@tonic-gate 707cce0e03bSab196087 for (APLIST_TRAVERSE(lmalp, idx1, lmp)) { 708cce0e03bSab196087 Aliste idx2; 709cce0e03bSab196087 Bnd_desc *bdp; 7107c478bd9Sstevel@tonic-gate Dyninfo *dip; 7117c478bd9Sstevel@tonic-gate uint_t cnt, max; 7127c478bd9Sstevel@tonic-gate 7137c478bd9Sstevel@tonic-gate if (FLAGS(lmp) & FLG_RT_DELETE) 7147c478bd9Sstevel@tonic-gate continue; 7157c478bd9Sstevel@tonic-gate 7167c478bd9Sstevel@tonic-gate /* 7177c478bd9Sstevel@tonic-gate * As this object can't be deleted, make sure its dependencies 7187c478bd9Sstevel@tonic-gate * aren't deleted either. 7197c478bd9Sstevel@tonic-gate */ 720cce0e03bSab196087 for (APLIST_TRAVERSE(DEPENDS(lmp), idx2, bdp)) { 721cce0e03bSab196087 Rt_map *dlmp = bdp->b_depend; 7227c478bd9Sstevel@tonic-gate 7237c478bd9Sstevel@tonic-gate if (FLAGS(dlmp) & FLG_RT_DELETE) { 7247c478bd9Sstevel@tonic-gate FLAGS(dlmp) &= ~FLG_RT_DELETE; 7257c478bd9Sstevel@tonic-gate if (--(*delcnt) == 0) 7267c478bd9Sstevel@tonic-gate return (0); 7277c478bd9Sstevel@tonic-gate rescan = 1; 7287c478bd9Sstevel@tonic-gate } 7297c478bd9Sstevel@tonic-gate } 7307c478bd9Sstevel@tonic-gate 7317c478bd9Sstevel@tonic-gate /* 7327c478bd9Sstevel@tonic-gate * If this object is a filtee and one of its filters is outside 7337c478bd9Sstevel@tonic-gate * of this dlclose family, then it can't be deleted either. 7347c478bd9Sstevel@tonic-gate */ 7357c478bd9Sstevel@tonic-gate if ((FLAGS1(lmp) & MSK_RT_FILTER) == 0) 7367c478bd9Sstevel@tonic-gate continue; 7377c478bd9Sstevel@tonic-gate 7387c478bd9Sstevel@tonic-gate dip = DYNINFO(lmp); 7397c478bd9Sstevel@tonic-gate max = DYNINFOCNT(lmp); 7407c478bd9Sstevel@tonic-gate 7417c478bd9Sstevel@tonic-gate for (cnt = 0; cnt < max; cnt++, dip++) { 74256deab07SRod Evans Alist *falp; 74356deab07SRod Evans Pdesc *pdp; 7447c478bd9Sstevel@tonic-gate 74556deab07SRod Evans if (((falp = (Alist *)dip->di_info) == NULL) || 7467c478bd9Sstevel@tonic-gate ((dip->di_flags & MSK_DI_FILTER) == 0)) 7477c478bd9Sstevel@tonic-gate continue; 7487c478bd9Sstevel@tonic-gate 74956deab07SRod Evans for (ALIST_TRAVERSE(falp, idx2, pdp)) { 75056deab07SRod Evans Aliste idx3; 7517c478bd9Sstevel@tonic-gate Grp_hdl *ghp; 7527c478bd9Sstevel@tonic-gate Grp_desc *gdp; 7537c478bd9Sstevel@tonic-gate 75456deab07SRod Evans if ((pdp->pd_plen == 0) || 75556deab07SRod Evans ((ghp = (Grp_hdl *)pdp->pd_info) == NULL)) 7567c478bd9Sstevel@tonic-gate continue; 7577c478bd9Sstevel@tonic-gate 758cce0e03bSab196087 if (aplist_test(&ghalp, ghp, 0) == 759cce0e03bSab196087 ALE_EXISTS) 7607c478bd9Sstevel@tonic-gate continue; 7617c478bd9Sstevel@tonic-gate 76256deab07SRod Evans for (ALIST_TRAVERSE(ghp->gh_depends, idx3, 7637c478bd9Sstevel@tonic-gate gdp)) { 7647c478bd9Sstevel@tonic-gate Rt_map *dlmp = gdp->gd_depend; 7657c478bd9Sstevel@tonic-gate 7667c478bd9Sstevel@tonic-gate if (FLAGS(dlmp) & FLG_RT_DELETE) { 7677c478bd9Sstevel@tonic-gate FLAGS(dlmp) &= ~FLG_RT_DELETE; 7687c478bd9Sstevel@tonic-gate if (--(*delcnt) == 0) 7697c478bd9Sstevel@tonic-gate return (0); 7707c478bd9Sstevel@tonic-gate rescan = 1; 7717c478bd9Sstevel@tonic-gate } 7727c478bd9Sstevel@tonic-gate } 7737c478bd9Sstevel@tonic-gate 7747c478bd9Sstevel@tonic-gate /* 7757c478bd9Sstevel@tonic-gate * Remove this group handle from our dynamic 7767c478bd9Sstevel@tonic-gate * deletion list. 7777c478bd9Sstevel@tonic-gate */ 778cce0e03bSab196087 (void) aplist_delete_value(ghalp, ghp); 7797c478bd9Sstevel@tonic-gate } 7807c478bd9Sstevel@tonic-gate } 7817c478bd9Sstevel@tonic-gate } 7827c478bd9Sstevel@tonic-gate return (rescan); 7837c478bd9Sstevel@tonic-gate } 7847c478bd9Sstevel@tonic-gate 7857c478bd9Sstevel@tonic-gate /* 7867c478bd9Sstevel@tonic-gate * Cleanup any collection alists we've created. 7877c478bd9Sstevel@tonic-gate */ 7887c478bd9Sstevel@tonic-gate static void 789cce0e03bSab196087 remove_collect(APlist *ghalp, APlist *lmalp) 7907c478bd9Sstevel@tonic-gate { 7917c478bd9Sstevel@tonic-gate if (ghalp) 7927c478bd9Sstevel@tonic-gate free(ghalp); 7937c478bd9Sstevel@tonic-gate if (lmalp) 7947c478bd9Sstevel@tonic-gate free(lmalp); 7957c478bd9Sstevel@tonic-gate } 7967c478bd9Sstevel@tonic-gate 7977c478bd9Sstevel@tonic-gate /* 7982017c965SRod Evans * Remove a handle, leaving the associated objects intact. 7997c478bd9Sstevel@tonic-gate */ 8007c478bd9Sstevel@tonic-gate void 8012017c965SRod Evans free_hdl(Grp_hdl *ghp) 8027c478bd9Sstevel@tonic-gate { 8032017c965SRod Evans if (--(ghp->gh_refcnt) == 0) { 8047c478bd9Sstevel@tonic-gate Grp_desc *gdp; 805cce0e03bSab196087 Aliste idx; 8068af2c5b9Srie uintptr_t ndx; 8078af2c5b9Srie 808cce0e03bSab196087 for (ALIST_TRAVERSE(ghp->gh_depends, idx, gdp)) { 8097c478bd9Sstevel@tonic-gate Rt_map *lmp = gdp->gd_depend; 8107c478bd9Sstevel@tonic-gate 8115aefb655Srie if (ghp->gh_ownlmp == lmp) 812cce0e03bSab196087 (void) aplist_delete_value(HANDLES(lmp), ghp); 813cce0e03bSab196087 (void) aplist_delete_value(GROUPS(lmp), ghp); 8147c478bd9Sstevel@tonic-gate } 8157c478bd9Sstevel@tonic-gate (void) free(ghp->gh_depends); 8167c478bd9Sstevel@tonic-gate 8177c478bd9Sstevel@tonic-gate /* LINTED */ 8187c478bd9Sstevel@tonic-gate ndx = (uintptr_t)ghp % HDLIST_SZ; 81956deab07SRod Evans (void) aplist_delete_value(hdl_alp[ndx], ghp); 8207c478bd9Sstevel@tonic-gate 8217c478bd9Sstevel@tonic-gate (void) free(ghp); 8227c478bd9Sstevel@tonic-gate } 8237c478bd9Sstevel@tonic-gate } 8247c478bd9Sstevel@tonic-gate 8257c478bd9Sstevel@tonic-gate /* 82602ca3e02Srie * If a load operation, using a new link-map control list, has failed, then 82702ca3e02Srie * forcibly remove the failed objects. This failure can occur as a result 82802ca3e02Srie * of a lazy load, a dlopen(), or a filtee load, once the application is 82902ca3e02Srie * running. If the link-map control list has not yet started relocation, then 83002ca3e02Srie * cleanup is simply a process of removing all the objects from the control 83102ca3e02Srie * list. If relocation has begun, then other loads may have been triggered to 83202ca3e02Srie * satisfy the relocations, and thus we need to break down the control list 83302ca3e02Srie * using handles. 83402ca3e02Srie * 83502ca3e02Srie * The objects associated with this load must be part of a unique handle. In 83602ca3e02Srie * the case of a dlopen() or filtee request, a handle will have been created. 83702ca3e02Srie * For a lazyload request, a handle must be generated so that the remove 83802ca3e02Srie * process can use the handle. 83902ca3e02Srie * 84002ca3e02Srie * During the course of processing these objects, other objects (handles) may 84102ca3e02Srie * have been loaded to satisfy relocation requirements. After these families 84202ca3e02Srie * have successfully loaded, they will have been propagated to the same link-map 84302ca3e02Srie * control list. The failed objects need to be removed from this list, while 84402ca3e02Srie * any successfully loaded families can be left alone, and propagated to the 84502ca3e02Srie * previous link-map control list. By associating each load request with a 84602ca3e02Srie * handle, we can isolate the failed objects while not interfering with any 84702ca3e02Srie * successfully loaded families. 8487c478bd9Sstevel@tonic-gate */ 8497c478bd9Sstevel@tonic-gate void 850481bba9eSRod Evans remove_lmc(Lm_list *lml, Rt_map *clmp, Aliste lmco, const char *name) 8517c478bd9Sstevel@tonic-gate { 85202ca3e02Srie Grp_hdl *ghp; 8537c478bd9Sstevel@tonic-gate Grp_desc *gdp; 854cce0e03bSab196087 Aliste idx; 855481bba9eSRod Evans Lm_cntl *lmc; 85602ca3e02Srie Rt_map *lmp; 8577c478bd9Sstevel@tonic-gate 858481bba9eSRod Evans /* 859481bba9eSRod Evans * Determine the link-map control list, and whether any object has been 860481bba9eSRod Evans * added to this list. 861481bba9eSRod Evans */ 862481bba9eSRod Evans /* LINTED */ 863481bba9eSRod Evans lmc = (Lm_cntl *)alist_item_by_offset(lml->lm_lists, lmco); 864481bba9eSRod Evans if (lmc->lc_head == NULL) 865481bba9eSRod Evans return; 866481bba9eSRod Evans 86702ca3e02Srie DBG_CALL(Dbg_file_cleanup(lml, name, lmco)); 8687c478bd9Sstevel@tonic-gate 86902ca3e02Srie /* 87002ca3e02Srie * Obtain a handle for the first object on the link-map control list. 87102ca3e02Srie * If none exists (which would occur from a lazy load request), and 87202ca3e02Srie * the link-map control list is being relocated, create a handle. 87302ca3e02Srie */ 87402ca3e02Srie lmp = lmc->lc_head; 87502ca3e02Srie if (HANDLES(lmp)) { 876cce0e03bSab196087 ghp = (Grp_hdl *)HANDLES(lmp)->apl_data[0]; 87702ca3e02Srie 8782017c965SRod Evans /* 8792017c965SRod Evans * If this is a private handle, remove this state, so as to 8802017c965SRod Evans * prevent any attempt to remove the handle more than once. 8812017c965SRod Evans */ 8822017c965SRod Evans ghp->gh_flags &= ~GPH_PRIVATE; 8832017c965SRod Evans 88402ca3e02Srie } else if (lmc->lc_flags & LMC_FLG_RELOCATING) { 88502ca3e02Srie /* 88602ca3e02Srie * Establish a handle, and should anything fail, fall through 88702ca3e02Srie * to remove the link-map control list. 88802ca3e02Srie */ 8892017c965SRod Evans if (((ghp = hdl_create(lml, lmc->lc_head, NULL, GPH_PUBLIC, 890b4059b01SRod Evans GPD_ADDEPS, 0)) == NULL) || 89102ca3e02Srie (hdl_initialize(ghp, lmc->lc_head, 0, 0) == 0)) 89202ca3e02Srie lmc->lc_flags &= ~LMC_FLG_RELOCATING; 893ed98f06cSrie } else { 894b4059b01SRod Evans ghp = NULL; 89502ca3e02Srie } 89602ca3e02Srie 89702ca3e02Srie /* 89802ca3e02Srie * If relocation hasn't begun, simply remove all the objects from this 89902ca3e02Srie * list, and any handle that may have been created. 90002ca3e02Srie */ 90102ca3e02Srie if ((lmc->lc_flags & LMC_FLG_RELOCATING) == 0) { 902*2020b2b6SRod Evans remove_incomplete(lml, lmco, clmp); 90302ca3e02Srie 90402ca3e02Srie if (ghp) { 90502ca3e02Srie ghp->gh_refcnt = 1; 9062017c965SRod Evans free_hdl(ghp); 90702ca3e02Srie } 90802ca3e02Srie return; 90902ca3e02Srie } 91002ca3e02Srie 911b4059b01SRod Evans ASSERT(ghp != NULL); 912ed98f06cSrie 91302ca3e02Srie /* 91402ca3e02Srie * As the objects of this handle are being forcibly removed, first 91502ca3e02Srie * remove any associations to objects on parent link-map control 91602ca3e02Srie * lists. This breaks the bond between a caller and a hierarchy of 91702ca3e02Srie * dependencies represented by the handle, thus the caller doesn't lock 91802ca3e02Srie * the hierarchy and prevent their deletion from the generic handle 91902ca3e02Srie * processing or remove_hdl(). 92002ca3e02Srie * 92102ca3e02Srie * This scenario can be produced when the relocation of a object 92202ca3e02Srie * results in vectoring through a filter that is already loaded. The 92302ca3e02Srie * filtee may be on the link-map list that is presently being processed, 92402ca3e02Srie * however an association between the filter and filtee would have been 92502ca3e02Srie * established during filtee processing. It is this association that 92602ca3e02Srie * must be broken to allow the objects on this link-map list to be 92702ca3e02Srie * removed. 92802ca3e02Srie */ 929cce0e03bSab196087 for (ALIST_TRAVERSE(ghp->gh_depends, idx, gdp)) { 9307c478bd9Sstevel@tonic-gate Rt_map *lmp = gdp->gd_depend; 9317c478bd9Sstevel@tonic-gate 93202ca3e02Srie /* 93302ca3e02Srie * If this object has not been relocated, break down any 93402ca3e02Srie * dependency relationships the object might have established. 93502ca3e02Srie */ 93602ca3e02Srie if ((FLAGS(lmp) & FLG_RT_RELOCED) == 0) 93702ca3e02Srie remove_lists(lmp, 1); 93802ca3e02Srie 93902ca3e02Srie if (CNTL(lmp) == lmco) 94002ca3e02Srie continue; 94102ca3e02Srie 94202ca3e02Srie if (gdp->gd_flags & GPD_FILTER) { 94302ca3e02Srie Dyninfo *dip = DYNINFO(lmp); 94402ca3e02Srie uint_t cnt, max = DYNINFOCNT(lmp); 94502ca3e02Srie 94602ca3e02Srie for (cnt = 0; cnt < max; cnt++, dip++) { 94756deab07SRod Evans Alist *falp; 94856deab07SRod Evans Aliste idx2; 94956deab07SRod Evans Pdesc *pdp; 95002ca3e02Srie 95156deab07SRod Evans if (((falp = (Alist *)dip->di_info) == NULL) || 95202ca3e02Srie ((dip->di_flags & MSK_DI_FILTER) == 0)) 95302ca3e02Srie continue; 95402ca3e02Srie 95556deab07SRod Evans for (ALIST_TRAVERSE(falp, idx2, pdp)) { 95656deab07SRod Evans if ((Grp_hdl *)pdp->pd_info == ghp) { 957b4059b01SRod Evans pdp->pd_info = NULL; 9587c478bd9Sstevel@tonic-gate break; 9597c478bd9Sstevel@tonic-gate } 9607c478bd9Sstevel@tonic-gate } 9617c478bd9Sstevel@tonic-gate } 96202ca3e02Srie } 963cce0e03bSab196087 (void) aplist_delete_value(GROUPS(lmp), ghp); 964cce0e03bSab196087 alist_delete(ghp->gh_depends, &idx); 96502ca3e02Srie } 96602ca3e02Srie 96702ca3e02Srie /* 96802ca3e02Srie * Having removed any callers, set the group handle reference count to 96902ca3e02Srie * one, and let the generic handle remover delete the associated 97002ca3e02Srie * objects. 97102ca3e02Srie */ 97202ca3e02Srie ghp->gh_refcnt = 1; 973b4059b01SRod Evans (void) remove_hdl(ghp, clmp, NULL); 97402ca3e02Srie 97502ca3e02Srie /* 97602ca3e02Srie * If this link-map control list still contains objects, determine the 97702ca3e02Srie * previous control list and move the objects. 97802ca3e02Srie */ 97902ca3e02Srie if (lmc->lc_head) { 98002ca3e02Srie Lm_cntl *plmc; 98102ca3e02Srie Aliste plmco; 98202ca3e02Srie 98302ca3e02Srie plmco = lmco - lml->lm_lists->al_size; 98402ca3e02Srie /* LINTED */ 985cce0e03bSab196087 plmc = (Lm_cntl *)alist_item_by_offset(lml->lm_lists, plmco); 98602ca3e02Srie 98702ca3e02Srie lm_move(lml, lmco, plmco, lmc, plmc); 98802ca3e02Srie } 98902ca3e02Srie } 9907c478bd9Sstevel@tonic-gate 9917c478bd9Sstevel@tonic-gate /* 9927c478bd9Sstevel@tonic-gate * Remove the objects associated with a handle. There are two goals here, to 9937c478bd9Sstevel@tonic-gate * delete the objects associated with the handle, and to remove the handle 9947c478bd9Sstevel@tonic-gate * itself. Things get a little more complex if the objects selected for 9957c478bd9Sstevel@tonic-gate * deletion are filters, in this case we also need to collect their filtees, 9967c478bd9Sstevel@tonic-gate * and process the combined groups as a whole. But, care still must be exer- 9977c478bd9Sstevel@tonic-gate * cised to make sure any filtees found aren't being used by filters outside of 9987c478bd9Sstevel@tonic-gate * the groups we've collect. The series of events is basically: 9997c478bd9Sstevel@tonic-gate * 10002017c965SRod Evans * - Determine the groups (handles) that might be deletable. 10017c478bd9Sstevel@tonic-gate * 10022017c965SRod Evans * - Determine the objects of these handles that can be deleted. 10037c478bd9Sstevel@tonic-gate * 10042017c965SRod Evans * - Fire the fini's of those objects selected for deletion. 10057c478bd9Sstevel@tonic-gate * 10062017c965SRod Evans * - Remove all inter-dependency linked lists while the objects link-maps 10077c478bd9Sstevel@tonic-gate * are still available. 10087c478bd9Sstevel@tonic-gate * 10092017c965SRod Evans * - Remove all deletable objects link-maps and unmap the objects themselves. 10107c478bd9Sstevel@tonic-gate * 10112017c965SRod Evans * - Remove the handle descriptors for each deleted object, and hopefully 10127c478bd9Sstevel@tonic-gate * the whole handle. 10137c478bd9Sstevel@tonic-gate * 1014*2020b2b6SRod Evans * A handle that can't be deleted is added to an orphans list. This list is 10157c478bd9Sstevel@tonic-gate * revisited any time another dlclose() request results in handle descriptors 10167c478bd9Sstevel@tonic-gate * being deleted. These deleted descriptors can be sufficient to allow the 10177c478bd9Sstevel@tonic-gate * final deletion of the orphaned handles. 10187c478bd9Sstevel@tonic-gate */ 10197c478bd9Sstevel@tonic-gate int 10207c478bd9Sstevel@tonic-gate remove_hdl(Grp_hdl *ghp, Rt_map *clmp, int *removed) 10217c478bd9Sstevel@tonic-gate { 1022cce0e03bSab196087 Rt_map *lmp; 10237c478bd9Sstevel@tonic-gate int rescan = 0; 10247c478bd9Sstevel@tonic-gate int delcnt = 0, rmcnt = 0, error = 0, orphans; 1025cce0e03bSab196087 APlist *lmalp = NULL, *ghalp = NULL; 1026cce0e03bSab196087 Aliste idx1, idx2; 1027cce0e03bSab196087 Grp_hdl *ghp2; 10287c478bd9Sstevel@tonic-gate Grp_desc *gdp; 1029cce0e03bSab196087 Lm_list *lml = NULL; 10307c478bd9Sstevel@tonic-gate 10317c478bd9Sstevel@tonic-gate /* 10327c478bd9Sstevel@tonic-gate * Generate the family of groups and objects that are candidates for 10337c478bd9Sstevel@tonic-gate * deletion. This consists of the objects that are explicitly defined 10347c478bd9Sstevel@tonic-gate * as dependencies of this handle, plus any filtee handles and their 10357c478bd9Sstevel@tonic-gate * associated objects. 10367c478bd9Sstevel@tonic-gate */ 10377c478bd9Sstevel@tonic-gate if (gdp_collect(&ghalp, &lmalp, ghp) == 0) { 10387c478bd9Sstevel@tonic-gate remove_collect(ghalp, lmalp); 10397c478bd9Sstevel@tonic-gate return (0); 10407c478bd9Sstevel@tonic-gate } 10417c478bd9Sstevel@tonic-gate 10428af2c5b9Srie DBG_CALL(Dbg_file_hdl_title(DBG_HDL_DELETE)); 10437c478bd9Sstevel@tonic-gate 10447c478bd9Sstevel@tonic-gate /* 10457c478bd9Sstevel@tonic-gate * Traverse the groups we've collected to determine if any filtees are 10467c478bd9Sstevel@tonic-gate * included. If so, and the filtee handle is in use by a filter outside 10477c478bd9Sstevel@tonic-gate * of the family of objects collected for this deletion, it can not be 10487c478bd9Sstevel@tonic-gate * removed. 10497c478bd9Sstevel@tonic-gate */ 1050cce0e03bSab196087 for (APLIST_TRAVERSE(ghalp, idx1, ghp2)) { 1051cce0e03bSab196087 Grp_hdl *ghp = ghp2; 10527c478bd9Sstevel@tonic-gate 10537c478bd9Sstevel@tonic-gate DBG_CALL(Dbg_file_hdl_collect(ghp, 0)); 10547c478bd9Sstevel@tonic-gate 10557c478bd9Sstevel@tonic-gate if ((ghp->gh_flags & GPH_FILTEE) == 0) 10567c478bd9Sstevel@tonic-gate continue; 10577c478bd9Sstevel@tonic-gate 10587c478bd9Sstevel@tonic-gate /* 10597c478bd9Sstevel@tonic-gate * Special case for ld.so.1. There can be multiple instances of 10607c478bd9Sstevel@tonic-gate * libdl.so.1 using this handle, so although we want the handles 10617c478bd9Sstevel@tonic-gate * reference count to be decremented, we don't want the handle 10627c478bd9Sstevel@tonic-gate * removed. 10637c478bd9Sstevel@tonic-gate */ 10647c478bd9Sstevel@tonic-gate if (ghp->gh_flags & GPH_LDSO) { 10657c478bd9Sstevel@tonic-gate DBG_CALL(Dbg_file_hdl_collect(ghp, 10667c478bd9Sstevel@tonic-gate NAME(lml_rtld.lm_head))); 1067cce0e03bSab196087 aplist_delete(ghalp, &idx1); 10687c478bd9Sstevel@tonic-gate continue; 10697c478bd9Sstevel@tonic-gate } 10707c478bd9Sstevel@tonic-gate 1071cce0e03bSab196087 for (ALIST_TRAVERSE(ghp->gh_depends, idx2, gdp)) { 1072cce0e03bSab196087 Grp_hdl *ghp3; 1073cce0e03bSab196087 Aliste idx3; 10747c478bd9Sstevel@tonic-gate 10757c478bd9Sstevel@tonic-gate /* 10767c478bd9Sstevel@tonic-gate * Determine whether this dependency is the filtee's 10777c478bd9Sstevel@tonic-gate * parent filter, and that it isn't also an explicit 10787c478bd9Sstevel@tonic-gate * dependency (in which case it would have added its own 10797c478bd9Sstevel@tonic-gate * dependencies to the handle). 10807c478bd9Sstevel@tonic-gate */ 10817c478bd9Sstevel@tonic-gate if ((gdp->gd_flags & 10827c478bd9Sstevel@tonic-gate (GPD_FILTER | GPD_ADDEPS)) != GPD_FILTER) 10837c478bd9Sstevel@tonic-gate continue; 10847c478bd9Sstevel@tonic-gate 1085dde769a2SRod Evans lmp = gdp->gd_depend; 1086dde769a2SRod Evans 1087dde769a2SRod Evans if (FLAGS(lmp) & FLG_RT_DELETE) 1088dde769a2SRod Evans continue; 1089dde769a2SRod Evans 1090dde769a2SRod Evans if (aplist_test(&lmalp, lmp, 0) == ALE_EXISTS) 10917c478bd9Sstevel@tonic-gate continue; 10927c478bd9Sstevel@tonic-gate 10937c478bd9Sstevel@tonic-gate /* 10947c478bd9Sstevel@tonic-gate * Remove this group handle from our dynamic deletion 10957c478bd9Sstevel@tonic-gate * list. In addition, recompute the list of objects 10967c478bd9Sstevel@tonic-gate * that are candidates for deletion to continue this 10977c478bd9Sstevel@tonic-gate * group verification. 10987c478bd9Sstevel@tonic-gate */ 1099dde769a2SRod Evans DBG_CALL(Dbg_file_hdl_collect(ghp, NAME(lmp))); 1100cce0e03bSab196087 aplist_delete(ghalp, &idx1); 11017c478bd9Sstevel@tonic-gate 11027c478bd9Sstevel@tonic-gate free(lmalp); 1103cce0e03bSab196087 lmalp = NULL; 1104cce0e03bSab196087 for (APLIST_TRAVERSE(ghalp, idx3, ghp3)) { 1105cce0e03bSab196087 Aliste idx4; 11067c478bd9Sstevel@tonic-gate Grp_desc *gdp4; 11077c478bd9Sstevel@tonic-gate 1108cce0e03bSab196087 for (ALIST_TRAVERSE(ghp3->gh_depends, 1109cce0e03bSab196087 idx4, gdp4)) { 11107c478bd9Sstevel@tonic-gate if ((gdp4->gd_flags & GPD_ADDEPS) == 0) 11117c478bd9Sstevel@tonic-gate continue; 1112cce0e03bSab196087 if (aplist_test(&lmalp, gdp4->gd_depend, 1113cce0e03bSab196087 AL_CNT_GRPCLCT) == ALE_ALLOCFAIL) { 11147c478bd9Sstevel@tonic-gate remove_collect(ghalp, lmalp); 11157c478bd9Sstevel@tonic-gate return (0); 11167c478bd9Sstevel@tonic-gate } 11177c478bd9Sstevel@tonic-gate } 11187c478bd9Sstevel@tonic-gate } 11197c478bd9Sstevel@tonic-gate break; 11207c478bd9Sstevel@tonic-gate } 11217c478bd9Sstevel@tonic-gate } 11227c478bd9Sstevel@tonic-gate 11237c478bd9Sstevel@tonic-gate /* 11247c478bd9Sstevel@tonic-gate * Now that we've collected all the handles dependencies, traverse the 11257c478bd9Sstevel@tonic-gate * collection determining whether they are a candidate for deletion. 11267c478bd9Sstevel@tonic-gate */ 1127cce0e03bSab196087 for (APLIST_TRAVERSE(lmalp, idx1, lmp)) { 11287c478bd9Sstevel@tonic-gate /* 11297c478bd9Sstevel@tonic-gate * Establish which link-map list we're dealing with for later 11307c478bd9Sstevel@tonic-gate * .fini processing. 11317c478bd9Sstevel@tonic-gate */ 1132b4059b01SRod Evans if (lml == NULL) 11337c478bd9Sstevel@tonic-gate lml = LIST(lmp); 11347c478bd9Sstevel@tonic-gate 11357c478bd9Sstevel@tonic-gate /* 11367c478bd9Sstevel@tonic-gate * If an object isn't a candidate for deletion we'll have to 11377c478bd9Sstevel@tonic-gate * rescan the handle insuring that this objects dependencies 11387c478bd9Sstevel@tonic-gate * aren't deleted either. 11397c478bd9Sstevel@tonic-gate */ 11407c478bd9Sstevel@tonic-gate if (is_deletable(&lmalp, &ghalp, lmp)) { 11417c478bd9Sstevel@tonic-gate FLAGS(lmp) |= FLG_RT_DELETE; 11427c478bd9Sstevel@tonic-gate delcnt++; 11437c478bd9Sstevel@tonic-gate } else 11447c478bd9Sstevel@tonic-gate rescan = 1; 11457c478bd9Sstevel@tonic-gate } 11467c478bd9Sstevel@tonic-gate 11477c478bd9Sstevel@tonic-gate /* 11487c478bd9Sstevel@tonic-gate * Rescan the handle if any objects where found non-deletable. 11497c478bd9Sstevel@tonic-gate */ 11507c478bd9Sstevel@tonic-gate while (rescan) 11517c478bd9Sstevel@tonic-gate rescan = remove_rescan(lmalp, ghalp, &delcnt); 11527c478bd9Sstevel@tonic-gate 11537c478bd9Sstevel@tonic-gate /* 11547c478bd9Sstevel@tonic-gate * Now that we have determined the number of groups that are candidates 11557c478bd9Sstevel@tonic-gate * for removal, mark each group descriptor as a candidate for removal 11567c478bd9Sstevel@tonic-gate * from the group. 11577c478bd9Sstevel@tonic-gate */ 1158cce0e03bSab196087 for (APLIST_TRAVERSE(ghalp, idx1, ghp2)) { 1159cce0e03bSab196087 for (ALIST_TRAVERSE(ghp2->gh_depends, idx2, gdp)) 11607c478bd9Sstevel@tonic-gate gdp->gd_flags |= GPD_REMOVE; 11617c478bd9Sstevel@tonic-gate } 11627c478bd9Sstevel@tonic-gate 11637c478bd9Sstevel@tonic-gate /* 11647c478bd9Sstevel@tonic-gate * Now that we know which objects on this handle can't be deleted 11657c478bd9Sstevel@tonic-gate * determine whether they still need to remain identified as belonging 11667c478bd9Sstevel@tonic-gate * to this group to be able to continue binding to one another. 11677c478bd9Sstevel@tonic-gate */ 1168cce0e03bSab196087 for (APLIST_TRAVERSE(ghalp, idx1, ghp2)) { 1169cce0e03bSab196087 Grp_hdl *ghp = ghp2; 11707c478bd9Sstevel@tonic-gate 1171cce0e03bSab196087 for (ALIST_TRAVERSE(ghp->gh_depends, idx2, gdp)) { 1172cce0e03bSab196087 Aliste idx3; 1173cce0e03bSab196087 Bnd_desc *bdp; 11747c478bd9Sstevel@tonic-gate 11757c478bd9Sstevel@tonic-gate lmp = gdp->gd_depend; 11767c478bd9Sstevel@tonic-gate 11777c478bd9Sstevel@tonic-gate if (FLAGS(lmp) & FLG_RT_DELETE) 11787c478bd9Sstevel@tonic-gate continue; 11797c478bd9Sstevel@tonic-gate 1180cce0e03bSab196087 for (APLIST_TRAVERSE(DEPENDS(lmp), idx3, bdp)) { 1181cce0e03bSab196087 Aliste idx4; 11827c478bd9Sstevel@tonic-gate Grp_desc *gdp4; 1183cce0e03bSab196087 Rt_map *dlmp = bdp->b_depend; 11847c478bd9Sstevel@tonic-gate 11857c478bd9Sstevel@tonic-gate /* 11867c478bd9Sstevel@tonic-gate * If this dependency (dlmp) can be referenced 11877c478bd9Sstevel@tonic-gate * by the caller (clmp) without being part of 11887c478bd9Sstevel@tonic-gate * this group (ghp) then belonging to this group 11897c478bd9Sstevel@tonic-gate * is no longer necessary. This can occur when 11907c478bd9Sstevel@tonic-gate * objects are part of multiple handles, or if a 11917c478bd9Sstevel@tonic-gate * previously deleted handle was moved to the 11927c478bd9Sstevel@tonic-gate * orphan list and has been reopened. Note, 11937c478bd9Sstevel@tonic-gate * first make sure the caller can reference the 11947c478bd9Sstevel@tonic-gate * dependency with this group, if it can't we 11957c478bd9Sstevel@tonic-gate * must be bound to a filtee, so there's no need 11967c478bd9Sstevel@tonic-gate * to remain a part of this group either. 11977c478bd9Sstevel@tonic-gate */ 119860758829Srie if ((callable(lmp, dlmp, 0, 0) == 0) || 119960758829Srie callable(lmp, dlmp, ghp, 0)) 12007c478bd9Sstevel@tonic-gate continue; 12017c478bd9Sstevel@tonic-gate 12027c478bd9Sstevel@tonic-gate if (gdp->gd_flags & GPD_REMOVE) 12037c478bd9Sstevel@tonic-gate gdp->gd_flags &= ~GPD_REMOVE; 12047c478bd9Sstevel@tonic-gate 12057c478bd9Sstevel@tonic-gate for (ALIST_TRAVERSE(ghp->gh_depends, 1206cce0e03bSab196087 idx4, gdp4)) { 12077c478bd9Sstevel@tonic-gate if (gdp4->gd_depend != dlmp) 12087c478bd9Sstevel@tonic-gate continue; 12097c478bd9Sstevel@tonic-gate 12107c478bd9Sstevel@tonic-gate if (gdp4->gd_flags & GPD_REMOVE) 12117c478bd9Sstevel@tonic-gate gdp4->gd_flags &= ~GPD_REMOVE; 12127c478bd9Sstevel@tonic-gate } 12137c478bd9Sstevel@tonic-gate } 12147c478bd9Sstevel@tonic-gate } 12157c478bd9Sstevel@tonic-gate } 12167c478bd9Sstevel@tonic-gate 12177c478bd9Sstevel@tonic-gate /* 12187c478bd9Sstevel@tonic-gate * If the owner of a handle can't be deleted and it's handle descriptor 12197c478bd9Sstevel@tonic-gate * must remain also, don't delete the handle at all. Leave it for 12207c478bd9Sstevel@tonic-gate * possible later use. Although it's left intact, it will still be 12217c478bd9Sstevel@tonic-gate * moved to the orphans list, as we might be able to revisit it on later 12227c478bd9Sstevel@tonic-gate * dlclose() operations and finally remove the underlying objects. Note 12237c478bd9Sstevel@tonic-gate * that the handle still remains attached to the owner via the HANDLES 12247c478bd9Sstevel@tonic-gate * list, so that it can be re-associated to the owner if a dlopen() 12257c478bd9Sstevel@tonic-gate * of this object reoccurs. 12267c478bd9Sstevel@tonic-gate */ 1227cce0e03bSab196087 for (APLIST_TRAVERSE(ghalp, idx1, ghp2)) { 1228cce0e03bSab196087 Grp_hdl *ghp = ghp2; 12297c478bd9Sstevel@tonic-gate 12307c478bd9Sstevel@tonic-gate /* 12317c478bd9Sstevel@tonic-gate * If this handle is already an orphan, or if it's owner is 12327c478bd9Sstevel@tonic-gate * deletable there's no need to inspect its dependencies. 12337c478bd9Sstevel@tonic-gate */ 1234b4059b01SRod Evans if ((ghp->gh_ownlmp == NULL) || 12355aefb655Srie (FLAGS(ghp->gh_ownlmp) & FLG_RT_DELETE)) 12367c478bd9Sstevel@tonic-gate continue; 12377c478bd9Sstevel@tonic-gate 12387c478bd9Sstevel@tonic-gate /* 12397c478bd9Sstevel@tonic-gate * Make sure all handle dependencies aren't removed or the 12407c478bd9Sstevel@tonic-gate * dependencies themselves aren't deleted. 12417c478bd9Sstevel@tonic-gate */ 1242cce0e03bSab196087 for (ALIST_TRAVERSE(ghp->gh_depends, idx2, gdp)) { 12437c478bd9Sstevel@tonic-gate lmp = gdp->gd_depend; 12447c478bd9Sstevel@tonic-gate 12457c478bd9Sstevel@tonic-gate /* 12467c478bd9Sstevel@tonic-gate * The first dependency of a non-orphaned handle is the 12477c478bd9Sstevel@tonic-gate * owner. If the handle descriptor for this isn't 12487c478bd9Sstevel@tonic-gate * required there's no need to look at any other of the 12497c478bd9Sstevel@tonic-gate * handles dependencies. 12507c478bd9Sstevel@tonic-gate */ 12515aefb655Srie if ((lmp == ghp->gh_ownlmp) && 12527c478bd9Sstevel@tonic-gate (gdp->gd_flags & GPD_REMOVE)) 12537c478bd9Sstevel@tonic-gate break; 12547c478bd9Sstevel@tonic-gate 12557c478bd9Sstevel@tonic-gate if (gdp->gd_flags & GPD_REMOVE) 12567c478bd9Sstevel@tonic-gate gdp->gd_flags &= ~GPD_REMOVE; 12577c478bd9Sstevel@tonic-gate if (FLAGS(lmp) & FLG_RT_DELETE) { 12587c478bd9Sstevel@tonic-gate FLAGS(lmp) &= ~FLG_RT_DELETE; 12597c478bd9Sstevel@tonic-gate delcnt--; 12607c478bd9Sstevel@tonic-gate } 12617c478bd9Sstevel@tonic-gate } 12627c478bd9Sstevel@tonic-gate } 12637c478bd9Sstevel@tonic-gate 12647c478bd9Sstevel@tonic-gate /* 12657c478bd9Sstevel@tonic-gate * Final scan of objects to see if any objects are to to be deleted. 12667c478bd9Sstevel@tonic-gate * Also - display diagnostic information on what operations are to be 12677c478bd9Sstevel@tonic-gate * performed on the collected handles before firing .fini's (which 12687c478bd9Sstevel@tonic-gate * produces additional diagnostics). 12697c478bd9Sstevel@tonic-gate */ 1270cce0e03bSab196087 for (APLIST_TRAVERSE(ghalp, idx1, ghp2)) { 1271cce0e03bSab196087 Grp_hdl *ghp = ghp2; 12727c478bd9Sstevel@tonic-gate 12738af2c5b9Srie DBG_CALL(Dbg_file_hdl_title(DBG_HDL_DELETE)); 12747c478bd9Sstevel@tonic-gate 1275cce0e03bSab196087 for (ALIST_TRAVERSE(ghp->gh_depends, idx2, gdp)) { 12762017c965SRod Evans Grp_hdl *ghp3; 12772017c965SRod Evans Aliste idx3; 12787c478bd9Sstevel@tonic-gate int flag; 12797c478bd9Sstevel@tonic-gate 12807c478bd9Sstevel@tonic-gate lmp = gdp->gd_depend; 12817c478bd9Sstevel@tonic-gate 1282efb9e8b8Srie /* 1283efb9e8b8Srie * Note, we must never delete a parent. The parent 1284efb9e8b8Srie * may already be tagged for deletion from a previous 1285efb9e8b8Srie * dlclose(). That dlclose has triggered this dlclose(), 1286efb9e8b8Srie * but the parents deletion is the responsibility of the 1287efb9e8b8Srie * previous dlclose(), not this one. 1288efb9e8b8Srie */ 1289efb9e8b8Srie if ((FLAGS(lmp) & FLG_RT_DELETE) && 1290efb9e8b8Srie ((gdp->gd_flags & GPD_PARENT) == 0)) { 12917c478bd9Sstevel@tonic-gate flag = DBG_DEP_DELETE; 129202ca3e02Srie 12937c478bd9Sstevel@tonic-gate /* 12947c478bd9Sstevel@tonic-gate * Remove any pathnames from the FullpathNode 12957c478bd9Sstevel@tonic-gate * AVL tree. As we're about to fire .fini's, 12967c478bd9Sstevel@tonic-gate * it's possible this object will be required 12977c478bd9Sstevel@tonic-gate * again, in which case we want to make sure a 12987c478bd9Sstevel@tonic-gate * new version of the object gets loaded. 12997c478bd9Sstevel@tonic-gate */ 13007c478bd9Sstevel@tonic-gate if (FPNODE(lmp)) 13017c478bd9Sstevel@tonic-gate fpavl_remove(lmp); 13027c478bd9Sstevel@tonic-gate } else if (gdp->gd_flags & GPD_REMOVE) 13037c478bd9Sstevel@tonic-gate flag = DBG_DEP_REMOVE; 13047c478bd9Sstevel@tonic-gate else 13057c478bd9Sstevel@tonic-gate flag = DBG_DEP_REMAIN; 13067c478bd9Sstevel@tonic-gate 130702ca3e02Srie DBG_CALL(Dbg_file_hdl_action(ghp, lmp, flag, 0)); 13082017c965SRod Evans 13092017c965SRod Evans /* 13102017c965SRod Evans * If this object contains any private handles, remove 13112017c965SRod Evans * them now. 13122017c965SRod Evans */ 13132017c965SRod Evans for (APLIST_TRAVERSE(HANDLES(lmp), idx3, ghp3)) { 13142017c965SRod Evans if (ghp3->gh_flags & GPH_PRIVATE) 13152017c965SRod Evans free_hdl(ghp3); 13162017c965SRod Evans } 13177c478bd9Sstevel@tonic-gate } 13187c478bd9Sstevel@tonic-gate } 13197c478bd9Sstevel@tonic-gate 13207c478bd9Sstevel@tonic-gate /* 13217c478bd9Sstevel@tonic-gate * If there are objects to be deleted process their .fini's. 13227c478bd9Sstevel@tonic-gate */ 13237c478bd9Sstevel@tonic-gate if (delcnt) { 13247c478bd9Sstevel@tonic-gate Rt_map **tobj; 13257c478bd9Sstevel@tonic-gate 13267c478bd9Sstevel@tonic-gate /* 13277c478bd9Sstevel@tonic-gate * Sort and fire all fini's of the objects selected for 13287c478bd9Sstevel@tonic-gate * deletion. Note that we have to start our search from the 13297c478bd9Sstevel@tonic-gate * link-map head - there's no telling whether this object has 13307c478bd9Sstevel@tonic-gate * dependencies on objects that were loaded before it and which 13317c478bd9Sstevel@tonic-gate * can now be deleted. If the tsort() fails because of an 13327c478bd9Sstevel@tonic-gate * allocation error then that might just be a symptom of why 13337c478bd9Sstevel@tonic-gate * we're here in the first place - forgo the fini's but 13347c478bd9Sstevel@tonic-gate * continue to try cleaning up. 13357c478bd9Sstevel@tonic-gate */ 1336dffec89cSrie lml->lm_flags |= LML_FLG_OBJDELETED; 1337dffec89cSrie 13387c478bd9Sstevel@tonic-gate if (((tobj = tsort(lml->lm_head, delcnt, 1339b4059b01SRod Evans (RT_SORT_DELETE | RT_SORT_FWD))) != NULL) && 13407c478bd9Sstevel@tonic-gate (tobj != (Rt_map **)S_ERROR)) { 13417c478bd9Sstevel@tonic-gate error = purge_exit_handlers(lml, tobj); 1342*2020b2b6SRod Evans call_fini(lml, tobj, clmp); 13437c478bd9Sstevel@tonic-gate } 13447c478bd9Sstevel@tonic-gate } 13457c478bd9Sstevel@tonic-gate 13467c478bd9Sstevel@tonic-gate /* 13477c478bd9Sstevel@tonic-gate * Now that .fini processing (which may have involved new bindings) 13487c478bd9Sstevel@tonic-gate * is complete, remove all inter-dependency lists from those objects 13497c478bd9Sstevel@tonic-gate * selected for deletion. 13507c478bd9Sstevel@tonic-gate */ 1351cce0e03bSab196087 for (APLIST_TRAVERSE(lmalp, idx1, lmp)) { 13527c478bd9Sstevel@tonic-gate Dyninfo *dip; 13537c478bd9Sstevel@tonic-gate uint_t cnt, max; 13547c478bd9Sstevel@tonic-gate 13557c478bd9Sstevel@tonic-gate if (FLAGS(lmp) & FLG_RT_DELETE) 13567c478bd9Sstevel@tonic-gate remove_lists(lmp, 0); 13577c478bd9Sstevel@tonic-gate 13587c478bd9Sstevel@tonic-gate /* 13597c478bd9Sstevel@tonic-gate * Determine whether we're dealing with a filter, and if so 13607c478bd9Sstevel@tonic-gate * process any inter-dependencies with its filtee's. 13617c478bd9Sstevel@tonic-gate */ 13627c478bd9Sstevel@tonic-gate if ((FLAGS1(lmp) & MSK_RT_FILTER) == 0) 13637c478bd9Sstevel@tonic-gate continue; 13647c478bd9Sstevel@tonic-gate 13657c478bd9Sstevel@tonic-gate dip = DYNINFO(lmp); 13667c478bd9Sstevel@tonic-gate max = DYNINFOCNT(lmp); 13677c478bd9Sstevel@tonic-gate 13687c478bd9Sstevel@tonic-gate for (cnt = 0; cnt < max; cnt++, dip++) { 136956deab07SRod Evans Alist *falp; 137056deab07SRod Evans Aliste idx2; 137156deab07SRod Evans Pdesc *pdp; 13727c478bd9Sstevel@tonic-gate 137356deab07SRod Evans if (((falp = (Alist *)dip->di_info) == NULL) || 13747c478bd9Sstevel@tonic-gate ((dip->di_flags & MSK_DI_FILTER) == 0)) 13757c478bd9Sstevel@tonic-gate continue; 13767c478bd9Sstevel@tonic-gate 137756deab07SRod Evans for (ALIST_TRAVERSE(falp, idx2, pdp)) { 13787c478bd9Sstevel@tonic-gate Grp_hdl *ghp; 13797c478bd9Sstevel@tonic-gate 138056deab07SRod Evans if ((pdp->pd_plen == 0) || 138156deab07SRod Evans ((ghp = (Grp_hdl *)pdp->pd_info) == NULL)) 13827c478bd9Sstevel@tonic-gate continue; 13837c478bd9Sstevel@tonic-gate 13847c478bd9Sstevel@tonic-gate /* 13857c478bd9Sstevel@tonic-gate * Determine whether this filtee's handle is a 13867c478bd9Sstevel@tonic-gate * part of the list of handles being deleted. 13877c478bd9Sstevel@tonic-gate */ 1388cce0e03bSab196087 if (aplist_test(&ghalp, ghp, 0) == ALE_EXISTS) { 13897c478bd9Sstevel@tonic-gate /* 13907c478bd9Sstevel@tonic-gate * If this handle exists on the deletion 13917c478bd9Sstevel@tonic-gate * list, then it has been removed. If 13927c478bd9Sstevel@tonic-gate * this filter isn't going to be 139302ca3e02Srie * deleted, sever its reference to the 13947c478bd9Sstevel@tonic-gate * handle. 13957c478bd9Sstevel@tonic-gate */ 139656deab07SRod Evans pdp->pd_info = NULL; 13977c478bd9Sstevel@tonic-gate } else { 13987c478bd9Sstevel@tonic-gate /* 13997c478bd9Sstevel@tonic-gate * If this handle isn't on the deletion 14007c478bd9Sstevel@tonic-gate * list, then it must still exist. If 14017c478bd9Sstevel@tonic-gate * this filter is being deleted, make 14027c478bd9Sstevel@tonic-gate * sure the filtees reference count 14037c478bd9Sstevel@tonic-gate * gets decremented. 14047c478bd9Sstevel@tonic-gate */ 1405dde769a2SRod Evans if (FLAGS(lmp) & FLG_RT_DELETE) { 14067247f888Srie (void) dlclose_core(ghp, 14077247f888Srie lmp, lml); 14087247f888Srie } 14097c478bd9Sstevel@tonic-gate } 14107c478bd9Sstevel@tonic-gate } 14117c478bd9Sstevel@tonic-gate } 14127c478bd9Sstevel@tonic-gate } 14137c478bd9Sstevel@tonic-gate 14147c478bd9Sstevel@tonic-gate /* 14157c478bd9Sstevel@tonic-gate * If called from dlclose(), determine if there are already handles on 14167c478bd9Sstevel@tonic-gate * the orphans list that we can reinvestigate. 14177c478bd9Sstevel@tonic-gate */ 141856deab07SRod Evans if ((removed == 0) && aplist_nitems(hdl_alp[HDLIST_ORP])) 14197c478bd9Sstevel@tonic-gate orphans = 1; 14207c478bd9Sstevel@tonic-gate else 14217c478bd9Sstevel@tonic-gate orphans = 0; 14227c478bd9Sstevel@tonic-gate 14237c478bd9Sstevel@tonic-gate /* 14247c478bd9Sstevel@tonic-gate * Finally remove any handle infrastructure and remove any objects 14257c478bd9Sstevel@tonic-gate * marked for deletion. 14267c478bd9Sstevel@tonic-gate */ 1427cce0e03bSab196087 for (APLIST_TRAVERSE(ghalp, idx1, ghp2)) { 1428cce0e03bSab196087 Grp_hdl *ghp = ghp2; 14297c478bd9Sstevel@tonic-gate 14307c478bd9Sstevel@tonic-gate /* 14317c478bd9Sstevel@tonic-gate * If we're not dealing with orphaned handles remove this handle 14327c478bd9Sstevel@tonic-gate * from its present handle list. 14337c478bd9Sstevel@tonic-gate */ 14347c478bd9Sstevel@tonic-gate if (removed == 0) { 14357c478bd9Sstevel@tonic-gate uintptr_t ndx; 14367c478bd9Sstevel@tonic-gate 14377c478bd9Sstevel@tonic-gate /* LINTED */ 14387c478bd9Sstevel@tonic-gate ndx = (uintptr_t)ghp % HDLIST_SZ; 143956deab07SRod Evans (void) aplist_delete_value(hdl_alp[ndx], ghp); 14407c478bd9Sstevel@tonic-gate } 14417c478bd9Sstevel@tonic-gate 14427c478bd9Sstevel@tonic-gate /* 1443efb9e8b8Srie * Traverse each handle dependency. Retain the dependencies 1444efb9e8b8Srie * flags to insure we don't delete any parents (the flags 1445efb9e8b8Srie * information is deleted as part of the alist removal that 1446efb9e8b8Srie * occurs before we inspect the object for deletion). 14477c478bd9Sstevel@tonic-gate */ 1448cce0e03bSab196087 for (ALIST_TRAVERSE(ghp->gh_depends, idx2, gdp)) { 1449efb9e8b8Srie uint_t flags = gdp->gd_flags; 1450efb9e8b8Srie 1451efb9e8b8Srie if ((flags & GPD_REMOVE) == 0) 14527c478bd9Sstevel@tonic-gate continue; 14537c478bd9Sstevel@tonic-gate 14547c478bd9Sstevel@tonic-gate lmp = gdp->gd_depend; 14557c478bd9Sstevel@tonic-gate rmcnt++; 14567c478bd9Sstevel@tonic-gate 14577c478bd9Sstevel@tonic-gate /* 14587c478bd9Sstevel@tonic-gate * If this object is the owner of the handle break that 14597c478bd9Sstevel@tonic-gate * association in case the handle is retained. 14607c478bd9Sstevel@tonic-gate */ 14615aefb655Srie if (ghp->gh_ownlmp == lmp) { 1462cce0e03bSab196087 (void) aplist_delete_value(HANDLES(lmp), ghp); 1463b4059b01SRod Evans ghp->gh_ownlmp = NULL; 14647c478bd9Sstevel@tonic-gate } 14657c478bd9Sstevel@tonic-gate 1466cce0e03bSab196087 (void) aplist_delete_value(GROUPS(lmp), ghp); 1467cce0e03bSab196087 alist_delete(ghp->gh_depends, &idx2); 14687c478bd9Sstevel@tonic-gate 14697c478bd9Sstevel@tonic-gate /* 14707c478bd9Sstevel@tonic-gate * Complete the link-map deletion if appropriate. 14717c478bd9Sstevel@tonic-gate */ 1472efb9e8b8Srie if ((FLAGS(lmp) & FLG_RT_DELETE) && 1473efb9e8b8Srie ((flags & GPD_PARENT) == 0)) { 147410a4fa49Srie tls_modaddrem(lmp, TM_FLG_MODREM); 1475*2020b2b6SRod Evans remove_so(LIST(lmp), lmp, clmp); 14767c478bd9Sstevel@tonic-gate } 14777c478bd9Sstevel@tonic-gate } 14787c478bd9Sstevel@tonic-gate 14797c478bd9Sstevel@tonic-gate /* 148002ca3e02Srie * If we've deleted all the dependencies of the handle, finalize 14817c478bd9Sstevel@tonic-gate * the cleanup by removing the handle itself. 14827c478bd9Sstevel@tonic-gate * 14837c478bd9Sstevel@tonic-gate * Otherwise we're left with a handle containing one or more 14847c478bd9Sstevel@tonic-gate * objects that can not be deleted (they're in use by other 14857c478bd9Sstevel@tonic-gate * handles, non-deletable, etc.), but require to remain a part 14867c478bd9Sstevel@tonic-gate * of this group to allow them to continue binding to one 148702ca3e02Srie * another. 148802ca3e02Srie * 148902ca3e02Srie * If the handles reference count is zero, or represents a 149002ca3e02Srie * link-map list (dlopen(0)), then move that handle to the 149102ca3e02Srie * orphans list. Should another dlclose() operation occur that 14927c478bd9Sstevel@tonic-gate * results in the removal of handle descriptors, these orphan 149302ca3e02Srie * handles are re-examined to determine if their deletion can 149402ca3e02Srie * be completed. 14957c478bd9Sstevel@tonic-gate */ 1496cce0e03bSab196087 if (ghp->gh_depends->al_nitems == 0) { 14977c478bd9Sstevel@tonic-gate free(ghp->gh_depends); 14987c478bd9Sstevel@tonic-gate free(ghp); 149902ca3e02Srie 1500b4059b01SRod Evans } else if ((ghp->gh_refcnt == 0) && 150102ca3e02Srie ((ghp->gh_flags & GPH_ZERO) == 0)) { 15027c478bd9Sstevel@tonic-gate /* 150302ca3e02Srie * Move this handle to the orphans list. 15047c478bd9Sstevel@tonic-gate */ 150556deab07SRod Evans (void) aplist_append(&hdl_alp[HDLIST_ORP], ghp, 150656deab07SRod Evans AL_CNT_HANDLES); 15077c478bd9Sstevel@tonic-gate 15085aefb655Srie if (DBG_ENABLED) { 15098af2c5b9Srie DBG_CALL(Dbg_file_hdl_title(DBG_HDL_ORPHAN)); 1510cce0e03bSab196087 for (ALIST_TRAVERSE(ghp->gh_depends, idx1, gdp)) 15117c478bd9Sstevel@tonic-gate DBG_CALL(Dbg_file_hdl_action(ghp, 151202ca3e02Srie gdp->gd_depend, DBG_DEP_ORPHAN, 0)); 15137c478bd9Sstevel@tonic-gate } 15147c478bd9Sstevel@tonic-gate } 15157c478bd9Sstevel@tonic-gate } 15167c478bd9Sstevel@tonic-gate 15177c478bd9Sstevel@tonic-gate /* 15187c478bd9Sstevel@tonic-gate * If no handle descriptors got removed there's no point in looking for 15197c478bd9Sstevel@tonic-gate * orphans to process. 15207c478bd9Sstevel@tonic-gate */ 15217c478bd9Sstevel@tonic-gate if (rmcnt == 0) 15227c478bd9Sstevel@tonic-gate orphans = 0; 15237c478bd9Sstevel@tonic-gate 15247c478bd9Sstevel@tonic-gate /* 15257c478bd9Sstevel@tonic-gate * Cleanup any alists we've created. 15267c478bd9Sstevel@tonic-gate */ 15277c478bd9Sstevel@tonic-gate remove_collect(ghalp, lmalp); 15287c478bd9Sstevel@tonic-gate 15297c478bd9Sstevel@tonic-gate /* 15307c478bd9Sstevel@tonic-gate * If orphan processing isn't required we're done. If our processing 15317c478bd9Sstevel@tonic-gate * originated from investigating orphans, return the number of handle 15327c478bd9Sstevel@tonic-gate * descriptors removed as an indication whether orphan processing 15337c478bd9Sstevel@tonic-gate * should continue. 15347c478bd9Sstevel@tonic-gate */ 15357c478bd9Sstevel@tonic-gate if (orphans == 0) { 15367c478bd9Sstevel@tonic-gate if (removed) 15377c478bd9Sstevel@tonic-gate *removed = rmcnt; 15387c478bd9Sstevel@tonic-gate return (error); 15397c478bd9Sstevel@tonic-gate } 15407c478bd9Sstevel@tonic-gate 15417c478bd9Sstevel@tonic-gate /* 15427c478bd9Sstevel@tonic-gate * Traverse the orphans list as many times as necessary until no 15437c478bd9Sstevel@tonic-gate * handle removals occur. 15447c478bd9Sstevel@tonic-gate */ 15457c478bd9Sstevel@tonic-gate do { 154656deab07SRod Evans APlist *alp; 154756deab07SRod Evans Aliste idx; 1548b4059b01SRod Evans Grp_hdl *ghp, *oghp = NULL; 15495aefb655Srie int title = 0; 15507c478bd9Sstevel@tonic-gate 15517c478bd9Sstevel@tonic-gate /* 15527c478bd9Sstevel@tonic-gate * Effectively clean the HDLIST_ORP list. Any object that can't 15537c478bd9Sstevel@tonic-gate * be removed will be re-added to the list. 15547c478bd9Sstevel@tonic-gate */ 155556deab07SRod Evans alp = hdl_alp[HDLIST_ORP]; 155656deab07SRod Evans hdl_alp[HDLIST_ORP] = NULL; 15577c478bd9Sstevel@tonic-gate 15587c478bd9Sstevel@tonic-gate rescan = 0; 155956deab07SRod Evans for (APLIST_TRAVERSE(alp, idx, ghp)) { 15607c478bd9Sstevel@tonic-gate int _error, _remove; 15617c478bd9Sstevel@tonic-gate 15625aefb655Srie if (title++ == 0) 15635aefb655Srie DBG_CALL(Dbg_file_del_rescan(ghp->gh_ownlml)); 15645aefb655Srie 15657c478bd9Sstevel@tonic-gate if (oghp) { 156656deab07SRod Evans (void) aplist_delete_value(alp, oghp); 1567b4059b01SRod Evans oghp = NULL; 15687c478bd9Sstevel@tonic-gate } 15697c478bd9Sstevel@tonic-gate 15707c478bd9Sstevel@tonic-gate if (((_error = remove_hdl(ghp, clmp, &_remove)) != 0) && 15717c478bd9Sstevel@tonic-gate (error == 0)) 15727c478bd9Sstevel@tonic-gate error = _error; 15737c478bd9Sstevel@tonic-gate 15747c478bd9Sstevel@tonic-gate if (_remove) 15757c478bd9Sstevel@tonic-gate rescan++; 15767c478bd9Sstevel@tonic-gate 15777c478bd9Sstevel@tonic-gate oghp = ghp; 15787c478bd9Sstevel@tonic-gate } 15797c478bd9Sstevel@tonic-gate if (oghp) { 158056deab07SRod Evans (void) aplist_delete_value(alp, oghp); 1581b4059b01SRod Evans oghp = NULL; 15827c478bd9Sstevel@tonic-gate } 158356deab07SRod Evans if (alp) 158456deab07SRod Evans free((void *)alp); 15857c478bd9Sstevel@tonic-gate 158656deab07SRod Evans } while (rescan && aplist_nitems(hdl_alp[HDLIST_ORP])); 15877c478bd9Sstevel@tonic-gate 15887c478bd9Sstevel@tonic-gate return (error); 15897c478bd9Sstevel@tonic-gate } 1590