xref: /illumos-gate/usr/src/cmd/sgs/rtld/common/tls.c (revision 7eca354d)
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
207c478bd9Sstevel@tonic-gate  */
215aefb655Srie 
227c478bd9Sstevel@tonic-gate /*
2356deab07SRod Evans  * Copyright 2009 Sun Microsystems, Inc.  All rights reserved.
245aefb655Srie  * Use is subject to license terms.
257c478bd9Sstevel@tonic-gate  */
267c478bd9Sstevel@tonic-gate 
277c478bd9Sstevel@tonic-gate #include <stdio.h>
287c478bd9Sstevel@tonic-gate #include <strings.h>
297c478bd9Sstevel@tonic-gate #include <sys/types.h>
307c478bd9Sstevel@tonic-gate #include <dlfcn.h>
317c478bd9Sstevel@tonic-gate #include <libc_int.h>
327c478bd9Sstevel@tonic-gate #include <_rtld.h>
337c478bd9Sstevel@tonic-gate #include <_elf.h>
347c478bd9Sstevel@tonic-gate #include <msg.h>
357c478bd9Sstevel@tonic-gate #include <debug.h>
367c478bd9Sstevel@tonic-gate 
377c478bd9Sstevel@tonic-gate #define	TLSBLOCKCNT	16	/* number of blocks of tmi_bits to allocate */
387c478bd9Sstevel@tonic-gate 				/* at a time. */
397c478bd9Sstevel@tonic-gate typedef struct {
407c478bd9Sstevel@tonic-gate 	uint_t	*tmi_bits;
417c478bd9Sstevel@tonic-gate 	ulong_t	tmi_lowfree;
427c478bd9Sstevel@tonic-gate 	ulong_t	tmi_cnt;
437c478bd9Sstevel@tonic-gate } Tlsmodid;
447c478bd9Sstevel@tonic-gate 
457c478bd9Sstevel@tonic-gate static Tlsmodid	tmid = {0, 0, 0};
467c478bd9Sstevel@tonic-gate 
47d326b23bSrie static ulong_t
tls_getmodid()487c478bd9Sstevel@tonic-gate tls_getmodid()
497c478bd9Sstevel@tonic-gate {
50d326b23bSrie 	ulong_t	ndx, cnt;
517c478bd9Sstevel@tonic-gate 
527c478bd9Sstevel@tonic-gate 	if (tmid.tmi_bits == 0) {
5356deab07SRod Evans 		if ((tmid.tmi_bits =
5456deab07SRod Evans 		    calloc(TLSBLOCKCNT, sizeof (uint_t))) == NULL)
5510a4fa49Srie 			return ((ulong_t)-1);
567c478bd9Sstevel@tonic-gate 		tmid.tmi_bits[0] = 1;
577c478bd9Sstevel@tonic-gate 		tmid.tmi_lowfree = 1;
587c478bd9Sstevel@tonic-gate 		tmid.tmi_cnt = TLSBLOCKCNT;
597c478bd9Sstevel@tonic-gate 		return (0);
607c478bd9Sstevel@tonic-gate 	}
617c478bd9Sstevel@tonic-gate 
62d326b23bSrie 	for (cnt = tmid.tmi_lowfree / (sizeof (uint_t) * 8);
63d326b23bSrie 	    cnt < tmid.tmi_cnt; cnt++) {
64d326b23bSrie 		uint_t	bits;
65d326b23bSrie 
667c478bd9Sstevel@tonic-gate 		/*
677c478bd9Sstevel@tonic-gate 		 * If all bits are assigned - move on.
687c478bd9Sstevel@tonic-gate 		 */
69d326b23bSrie 		if ((tmid.tmi_bits[cnt] ^ ~((uint_t)0)) == 0)
707c478bd9Sstevel@tonic-gate 			continue;
71d326b23bSrie 
72d326b23bSrie 		for (ndx = 0, bits = 1; bits; bits = bits << 1, ndx++) {
73d326b23bSrie 			if ((tmid.tmi_bits[cnt] & bits) == 0) {
74d326b23bSrie 				tmid.tmi_bits[cnt] |= bits;
75d326b23bSrie 				ndx = (cnt * (sizeof (uint_t)) * 8) + ndx;
767c478bd9Sstevel@tonic-gate 				tmid.tmi_lowfree = ndx + 1;
777c478bd9Sstevel@tonic-gate 				return (ndx);
787c478bd9Sstevel@tonic-gate 			}
797c478bd9Sstevel@tonic-gate 		}
807c478bd9Sstevel@tonic-gate 	}
817c478bd9Sstevel@tonic-gate 
827c478bd9Sstevel@tonic-gate 	/*
837c478bd9Sstevel@tonic-gate 	 * All bits taken - must allocate a new block
847c478bd9Sstevel@tonic-gate 	 */
8510a4fa49Srie 	if ((tmid.tmi_bits = realloc(tmid.tmi_bits,
867c478bd9Sstevel@tonic-gate 	    ((tmid.tmi_cnt * sizeof (uint_t)) +
8756deab07SRod Evans 	    (TLSBLOCKCNT * sizeof (uint_t))))) == NULL)
8810a4fa49Srie 		return ((ulong_t)-1);
8910a4fa49Srie 
907c478bd9Sstevel@tonic-gate 	/*
9110a4fa49Srie 	 * Clear out the tail of the new allocation.
927c478bd9Sstevel@tonic-gate 	 */
937c478bd9Sstevel@tonic-gate 	bzero(&(tmid.tmi_bits[tmid.tmi_cnt]), TLSBLOCKCNT * sizeof (uint_t));
947c478bd9Sstevel@tonic-gate 	tmid.tmi_bits[tmid.tmi_cnt] = 1;
957c478bd9Sstevel@tonic-gate 	ndx = (tmid.tmi_cnt * sizeof (uint_t)) * 8;
967c478bd9Sstevel@tonic-gate 	tmid.tmi_lowfree = ndx + 1;
977c478bd9Sstevel@tonic-gate 	tmid.tmi_cnt += TLSBLOCKCNT;
987c478bd9Sstevel@tonic-gate 
997c478bd9Sstevel@tonic-gate 	return (ndx);
1007c478bd9Sstevel@tonic-gate }
1017c478bd9Sstevel@tonic-gate 
1027c478bd9Sstevel@tonic-gate void
tls_freemodid(ulong_t modid)10310a4fa49Srie tls_freemodid(ulong_t modid)
1047c478bd9Sstevel@tonic-gate {
1057c478bd9Sstevel@tonic-gate 	ulong_t	i;
1067c478bd9Sstevel@tonic-gate 	uint_t	j;
1077c478bd9Sstevel@tonic-gate 
1087c478bd9Sstevel@tonic-gate 	i = modid / (sizeof (uint_t) * 8);
1097c478bd9Sstevel@tonic-gate 	/* LINTED */
1107c478bd9Sstevel@tonic-gate 	j = modid % (sizeof (uint_t) * 8);
1117c478bd9Sstevel@tonic-gate 	j = ~(1 << j);
1127c478bd9Sstevel@tonic-gate 	tmid.tmi_bits[i] &= j;
1137c478bd9Sstevel@tonic-gate 	if (modid < tmid.tmi_lowfree)
1147c478bd9Sstevel@tonic-gate 		tmid.tmi_lowfree = modid;
1157c478bd9Sstevel@tonic-gate }
1167c478bd9Sstevel@tonic-gate 
1177c478bd9Sstevel@tonic-gate void
tls_modaddrem(Rt_map * lmp,uint_t flag)11810a4fa49Srie tls_modaddrem(Rt_map *lmp, uint_t flag)
1197c478bd9Sstevel@tonic-gate {
12010a4fa49Srie 	Lm_list		*lml = LIST(lmp);
1217c478bd9Sstevel@tonic-gate 	TLS_modinfo	tmi;
12210a4fa49Srie 	Phdr		*tlsphdr;
1235e90af26SToomas Soome 	int		(*fptr)(TLS_modinfo *);
1247c478bd9Sstevel@tonic-gate 
12510a4fa49Srie 	if (flag & TM_FLG_MODADD) {
1265e90af26SToomas Soome 		fptr = lml->lm_lcs[CI_TLS_MODADD].lc_un.lc_func;
12710a4fa49Srie 	} else if (FLAGS1(lmp) & FL1_RT_TLSADD) {
1285e90af26SToomas Soome 		fptr = lml->lm_lcs[CI_TLS_MODREM].lc_un.lc_func;
12910a4fa49Srie 	} else {
1307c478bd9Sstevel@tonic-gate 		return;
13110a4fa49Srie 	}
1327c478bd9Sstevel@tonic-gate 
1337c478bd9Sstevel@tonic-gate 	tlsphdr = PTTLS(lmp);
1347c478bd9Sstevel@tonic-gate 
1357c478bd9Sstevel@tonic-gate 	bzero(&tmi, sizeof (tmi));
1367c478bd9Sstevel@tonic-gate 	tmi.tm_modname = PATHNAME(lmp);
1377c478bd9Sstevel@tonic-gate 	tmi.tm_modid = TLSMODID(lmp);
1387c478bd9Sstevel@tonic-gate 	tmi.tm_tlsblock = (void *)(tlsphdr->p_vaddr);
13910a4fa49Srie 
1407c478bd9Sstevel@tonic-gate 	if (!(FLAGS(lmp) & FLG_RT_FIXED))
1417c478bd9Sstevel@tonic-gate 		tmi.tm_tlsblock = (void *)((uintptr_t)tmi.tm_tlsblock +
142b71d513aSedp 		    ADDR(lmp));
14310a4fa49Srie 
1447c478bd9Sstevel@tonic-gate 	tmi.tm_filesz = tlsphdr->p_filesz;
1457c478bd9Sstevel@tonic-gate 	tmi.tm_memsz = tlsphdr->p_memsz;
1467c478bd9Sstevel@tonic-gate 	tmi.tm_flags = 0;
1477c478bd9Sstevel@tonic-gate 	tmi.tm_stattlsoffset = 0;
1487c478bd9Sstevel@tonic-gate 
1495aefb655Srie 	DBG_CALL(Dbg_tls_modactivity(LIST(lmp), &tmi, flag));
1505e90af26SToomas Soome 	(void) (*fptr)(&tmi);
1517c478bd9Sstevel@tonic-gate 
1527c478bd9Sstevel@tonic-gate 	/*
153d326b23bSrie 	 * Tag that this link-map has registered its TLS, and, if this object
154d326b23bSrie 	 * is being removed, free up the module id.
1557c478bd9Sstevel@tonic-gate 	 */
15610a4fa49Srie 	FLAGS1(lmp) |= FL1_RT_TLSADD;
15710a4fa49Srie 
1587c478bd9Sstevel@tonic-gate 	if (flag & TM_FLG_MODREM)
1597c478bd9Sstevel@tonic-gate 		tls_freemodid(TLSMODID(lmp));
1607c478bd9Sstevel@tonic-gate }
1617c478bd9Sstevel@tonic-gate 
162d326b23bSrie static ulong_t	tls_static_size = 0;	/* static TLS buffer size */
163d326b23bSrie static ulong_t	tls_static_resv = 512;	/* (extra) static TLS reservation */
164d326b23bSrie 
165d326b23bSrie /*
166d326b23bSrie  * Track any static TLS use, retain the TLS header, and assign a TLS module
167d326b23bSrie  * identifier.
168d326b23bSrie  */
169d326b23bSrie int
tls_assign(Lm_list * lml,Rt_map * lmp,Phdr * phdr)170d326b23bSrie tls_assign(Lm_list *lml, Rt_map *lmp, Phdr *phdr)
1717c478bd9Sstevel@tonic-gate {
172d326b23bSrie 	ulong_t	memsz = S_ROUND(phdr->p_memsz, M_TLSSTATALIGN);
173d326b23bSrie 	ulong_t	filesz = phdr->p_filesz;
174d326b23bSrie 	ulong_t	resv = tls_static_resv;
175d326b23bSrie 
176d326b23bSrie 	/*
177d326b23bSrie 	 * If this object explicitly references static TLS, then there are some
178d326b23bSrie 	 * limitations.
179d326b23bSrie 	 */
180d326b23bSrie 	if (FLAGS1(lmp) & FL1_RT_TLSSTAT) {
181d326b23bSrie 		/*
182d326b23bSrie 		 * Static TLS is only available to objects on the primary
183d326b23bSrie 		 * link-map list.
184d326b23bSrie 		 */
185b71d513aSedp 		if (((lml->lm_flags & LML_FLG_BASELM) == 0) ||
186b71d513aSedp 		    ((rtld_flags2 & RT_FL2_NOPLM) != 0)) {
187d326b23bSrie 			eprintf(lml, ERR_FATAL, MSG_INTL(MSG_TLS_STATBASE),
188d326b23bSrie 			    NAME(lmp));
189d326b23bSrie 			return (0);
190d326b23bSrie 		}
191d326b23bSrie 
192d326b23bSrie 		/*
193d326b23bSrie 		 * All TLS blocks that are processed before thread
194d326b23bSrie 		 * initialization, are registered with libc.  This
195d326b23bSrie 		 * initialization is carried out through a handshake with libc
196d326b23bSrie 		 * prior to executing any user code (ie. before the first .init
197d326b23bSrie 		 * sections are called).  As part of this initialization, a
198d326b23bSrie 		 * small backup TLS reservation is added (tls_static_resv).
199d326b23bSrie 		 * Only explicit static TLS references that can be satisfied by
200d326b23bSrie 		 * this TLS backup reservation can be satisfied.
201d326b23bSrie 		 */
202d326b23bSrie 		if (rtld_flags2 & RT_FL2_PLMSETUP) {
203d326b23bSrie 			/*
204d326b23bSrie 			 * Initialized static TLS can not be satisfied from the
205d326b23bSrie 			 * TLS backup reservation.
206d326b23bSrie 			 */
207d326b23bSrie 			if (filesz) {
208d326b23bSrie 				eprintf(lml, ERR_FATAL,
209d326b23bSrie 				    MSG_INTL(MSG_TLS_STATINIT), NAME(lmp));
210d326b23bSrie 				return (0);
211d326b23bSrie 			}
212d326b23bSrie 
213d326b23bSrie 			/*
214d326b23bSrie 			 * Make sure the backup reservation is sufficient.
215d326b23bSrie 			 */
216d326b23bSrie 			if (memsz > tls_static_resv) {
217d326b23bSrie 				eprintf(lml, ERR_FATAL,
218d326b23bSrie 				    MSG_INTL(MSG_TLS_STATSIZE), NAME(lmp),
219d326b23bSrie 				    EC_XWORD(memsz), EC_XWORD(tls_static_resv));
220d326b23bSrie 				return (0);
221d326b23bSrie 			}
222d326b23bSrie 
223d326b23bSrie 			tls_static_resv -= memsz;
224d326b23bSrie 		}
225d326b23bSrie 	}
226d326b23bSrie 
2277c478bd9Sstevel@tonic-gate 	/*
228d326b23bSrie 	 * If we haven't yet initialized threads, or this static reservation can
229d326b23bSrie 	 * be satisfied from the TLS backup reservation, determine the total
230d326b23bSrie 	 * static TLS size, and assign this object a static TLS offset.
2317c478bd9Sstevel@tonic-gate 	 */
232d326b23bSrie 	if (((rtld_flags2 & RT_FL2_PLMSETUP) == 0) ||
233d326b23bSrie 	    (FLAGS1(lmp) & FL1_RT_TLSSTAT)) {
234d326b23bSrie 		tls_static_size += memsz;
2357c478bd9Sstevel@tonic-gate 		TLSSTATOFF(lmp) = tls_static_size;
2367c478bd9Sstevel@tonic-gate 	}
2377c478bd9Sstevel@tonic-gate 
2387c478bd9Sstevel@tonic-gate 	/*
239d326b23bSrie 	 * Retain the PT_TLS header, obtain a new module identifier, and
240d326b23bSrie 	 * indicate that this link-map list contains a new TLS object.
2417c478bd9Sstevel@tonic-gate 	 */
242d326b23bSrie 	PTTLS(lmp) = phdr;
2437c478bd9Sstevel@tonic-gate 	TLSMODID(lmp) = tls_getmodid();
244d326b23bSrie 
245d326b23bSrie 	/*
246d326b23bSrie 	 * Now that we have a TLS module id, generate any static TLS reservation
247d326b23bSrie 	 * diagnostic.
248d326b23bSrie 	 */
249d326b23bSrie 	if (resv != tls_static_resv)
250d326b23bSrie 		DBG_CALL(Dbg_tls_static_resv(lmp, memsz, tls_static_resv));
251d326b23bSrie 
252d326b23bSrie 	return (++lml->lm_tls);
2537c478bd9Sstevel@tonic-gate }
2547c478bd9Sstevel@tonic-gate 
2557c478bd9Sstevel@tonic-gate int
tls_statmod(Lm_list * lml,Rt_map * lmp)25610a4fa49Srie tls_statmod(Lm_list *lml, Rt_map *lmp)
2577c478bd9Sstevel@tonic-gate {
25810a4fa49Srie 	uint_t		tlsmodndx, tlsmodcnt = lml->lm_tls;
25910a4fa49Srie 	TLS_modinfo	**tlsmodlist, *tlsbuflist;
2605aefb655Srie 	Phdr		*tlsphdr;
2615e90af26SToomas Soome 	int		(*fptr)(TLS_modinfo **, ulong_t);
2627c478bd9Sstevel@tonic-gate 
2635e90af26SToomas Soome 	fptr = lml->lm_lcs[CI_TLS_STATMOD].lc_un.lc_func;
2647c478bd9Sstevel@tonic-gate 
265f79d60b6Srie 	/*
266f79d60b6Srie 	 * Allocate a buffer to report the TLS modules, the buffer consists of:
267f79d60b6Srie 	 *
268f79d60b6Srie 	 *	TLS_modinfo *	ptrs[tlsmodcnt + 1]
269f79d60b6Srie 	 *	TLS_modinfo	bufs[tlsmodcnt]
270f79d60b6Srie 	 *
271f79d60b6Srie 	 * The ptrs are initialized to the bufs - except the last one which
272f79d60b6Srie 	 * null terminates the array.
273f79d60b6Srie 	 *
274f79d60b6Srie 	 * Note, even if no TLS has yet been observed, we still supply a
275f79d60b6Srie 	 * TLS buffer with a single null entry.  This allows us to initialize
276f79d60b6Srie 	 * the backup TLS reservation.
277f79d60b6Srie 	 */
278*7eca354dSToomas Soome 	if ((tlsmodlist = calloc(1, (sizeof (TLS_modinfo *) * (tlsmodcnt + 1)) +
279*7eca354dSToomas Soome 	    (sizeof (TLS_modinfo) * tlsmodcnt))) == NULL)
280f79d60b6Srie 		return (0);
281f79d60b6Srie 
282f79d60b6Srie 	lml->lm_tls = 0;
283f79d60b6Srie 
2847c478bd9Sstevel@tonic-gate 	/*
2857c478bd9Sstevel@tonic-gate 	 * If we don't have any TLS modules - report that and return.
2867c478bd9Sstevel@tonic-gate 	 */
2877c478bd9Sstevel@tonic-gate 	if (tlsmodcnt == 0) {
2885e90af26SToomas Soome 		if (fptr != NULL)
2895e90af26SToomas Soome 			(void) (*fptr)(tlsmodlist, tls_static_resv);
290d326b23bSrie 		DBG_CALL(Dbg_tls_static_block(&lml_main, 0, 0,
291d326b23bSrie 		    tls_static_resv));
2927c478bd9Sstevel@tonic-gate 		return (1);
2937c478bd9Sstevel@tonic-gate 	}
2947c478bd9Sstevel@tonic-gate 
2957c478bd9Sstevel@tonic-gate 	/*
296f79d60b6Srie 	 * Initialize the TLS buffer.
2977c478bd9Sstevel@tonic-gate 	 */
2987c478bd9Sstevel@tonic-gate 	tlsbuflist = (TLS_modinfo *)((uintptr_t)tlsmodlist +
29910a4fa49Srie 	    ((tlsmodcnt + 1) * sizeof (TLS_modinfo *)));
30010a4fa49Srie 
3017c478bd9Sstevel@tonic-gate 	for (tlsmodndx = 0; tlsmodndx < tlsmodcnt; tlsmodndx++)
3027c478bd9Sstevel@tonic-gate 		tlsmodlist[tlsmodndx] = &tlsbuflist[tlsmodndx];
3037c478bd9Sstevel@tonic-gate 
3047c478bd9Sstevel@tonic-gate 	/*
3057c478bd9Sstevel@tonic-gate 	 * Account for the initial dtv ptr in the TLSSIZE calculation.
3067c478bd9Sstevel@tonic-gate 	 */
3077c478bd9Sstevel@tonic-gate 	tlsmodndx = 0;
308cb511613SAli Bahrami 	for (lmp = lml->lm_head; lmp; lmp = NEXT_RT_MAP(lmp)) {
30956deab07SRod Evans 		if (THIS_IS_NOT_ELF(lmp) ||
3107c478bd9Sstevel@tonic-gate 		    (PTTLS(lmp) == 0) || (PTTLS(lmp)->p_memsz == 0))
3117c478bd9Sstevel@tonic-gate 			continue;
3127c478bd9Sstevel@tonic-gate 
3137c478bd9Sstevel@tonic-gate 		tlsphdr = PTTLS(lmp);
3147c478bd9Sstevel@tonic-gate 
3157c478bd9Sstevel@tonic-gate 		tlsmodlist[tlsmodndx]->tm_modname = PATHNAME(lmp);
3167c478bd9Sstevel@tonic-gate 		tlsmodlist[tlsmodndx]->tm_modid = TLSMODID(lmp);
31710a4fa49Srie 		tlsmodlist[tlsmodndx]->tm_tlsblock = (void *)(tlsphdr->p_vaddr);
31810a4fa49Srie 
31910a4fa49Srie 		if (!(FLAGS(lmp) & FLG_RT_FIXED)) {
32010a4fa49Srie 			tlsmodlist[tlsmodndx]->tm_tlsblock = (void *)
32110a4fa49Srie 			    ((uintptr_t)tlsmodlist[tlsmodndx]->tm_tlsblock +
32210a4fa49Srie 			    ADDR(lmp));
32310a4fa49Srie 		}
3247c478bd9Sstevel@tonic-gate 		tlsmodlist[tlsmodndx]->tm_filesz = tlsphdr->p_filesz;
3257c478bd9Sstevel@tonic-gate 		tlsmodlist[tlsmodndx]->tm_memsz = tlsphdr->p_memsz;
3267c478bd9Sstevel@tonic-gate 		tlsmodlist[tlsmodndx]->tm_flags = TM_FLG_STATICTLS;
32710a4fa49Srie 		tlsmodlist[tlsmodndx]->tm_stattlsoffset = TLSSTATOFF(lmp);
3287c478bd9Sstevel@tonic-gate 		tlsmodndx++;
3297c478bd9Sstevel@tonic-gate 	}
3307c478bd9Sstevel@tonic-gate 
3315aefb655Srie 	DBG_CALL(Dbg_tls_static_block(&lml_main, (void *)tlsmodlist,
332d326b23bSrie 	    tls_static_size, tls_static_resv));
3335e90af26SToomas Soome 	(void) (*fptr)(tlsmodlist, (tls_static_size + tls_static_resv));
3347c478bd9Sstevel@tonic-gate 
3357c478bd9Sstevel@tonic-gate 	/*
3367c478bd9Sstevel@tonic-gate 	 * We're done with the list - clean it up.
3377c478bd9Sstevel@tonic-gate 	 */
3387c478bd9Sstevel@tonic-gate 	free(tlsmodlist);
3397c478bd9Sstevel@tonic-gate 	return (1);
3407c478bd9Sstevel@tonic-gate }
341