xref: /illumos-gate/usr/src/lib/libc/port/gen/atexit.c (revision 2e145884)
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
541efec22Sraf  * Common Development and Distribution License (the "License").
641efec22Sraf  * 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  */
21e8031f0aSraf 
227c478bd9Sstevel@tonic-gate /*
2341efec22Sraf  * Copyright 2007 Sun Microsystems, Inc.  All rights reserved.
247c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
257c478bd9Sstevel@tonic-gate  */
267c478bd9Sstevel@tonic-gate 
277c478bd9Sstevel@tonic-gate #pragma ident	"%Z%%M%	%I%	%E% SMI"
287c478bd9Sstevel@tonic-gate 
297c478bd9Sstevel@tonic-gate /*	Copyright (c) 1988 AT&T	*/
307c478bd9Sstevel@tonic-gate /*	  All Rights Reserved  	*/
317c478bd9Sstevel@tonic-gate 
32e8031f0aSraf #pragma weak atexit = _atexit
337c478bd9Sstevel@tonic-gate 
34e8031f0aSraf #include "synonyms.h"
357c478bd9Sstevel@tonic-gate #include "thr_uberdata.h"
367c478bd9Sstevel@tonic-gate #include "libc_int.h"
377c478bd9Sstevel@tonic-gate #include "atexit.h"
387c478bd9Sstevel@tonic-gate #include "stdiom.h"
397c478bd9Sstevel@tonic-gate 
407c478bd9Sstevel@tonic-gate /*
417c478bd9Sstevel@tonic-gate  * Note that memory is managed by lmalloc()/lfree().
427c478bd9Sstevel@tonic-gate  *
437c478bd9Sstevel@tonic-gate  * Among other reasons, this is occasioned by the insistence of our
447c478bd9Sstevel@tonic-gate  * brothers sh(1) and csh(1) that they can do malloc, etc., better than
457c478bd9Sstevel@tonic-gate  * libc can.  Those programs define their own malloc routines, and
467c478bd9Sstevel@tonic-gate  * initialize the underlying mechanism in main().  This means that calls
477c478bd9Sstevel@tonic-gate  * to malloc occuring before main will crash.  The loader calls atexit(3C)
487c478bd9Sstevel@tonic-gate  * before calling main, so we'd better avoid malloc() when it does.
497c478bd9Sstevel@tonic-gate  *
507c478bd9Sstevel@tonic-gate  * Another reason for using lmalloc()/lfree() is that the atexit()
517c478bd9Sstevel@tonic-gate  * list must transcend all link maps.  See the Linker and Libraries
527c478bd9Sstevel@tonic-gate  * Guide for information on alternate link maps.
537c478bd9Sstevel@tonic-gate  *
547c478bd9Sstevel@tonic-gate  * See "thr_uberdata.h" for the definitions of structures used here.
557c478bd9Sstevel@tonic-gate  */
567c478bd9Sstevel@tonic-gate 
577c478bd9Sstevel@tonic-gate static int in_range(_exithdlr_func_t, Lc_addr_range_t[], uint_t count);
587c478bd9Sstevel@tonic-gate 
597c478bd9Sstevel@tonic-gate extern	caddr_t	_getfp(void);
607c478bd9Sstevel@tonic-gate 
617c478bd9Sstevel@tonic-gate /*
627c478bd9Sstevel@tonic-gate  * exitfns_lock is declared to be a recursive mutex so that we
637c478bd9Sstevel@tonic-gate  * can hold it while calling out to the registered functions.
647c478bd9Sstevel@tonic-gate  * If they call back to us, we are self-consistent and everything
657c478bd9Sstevel@tonic-gate  * works, even the case of calling exit() from functions called
667c478bd9Sstevel@tonic-gate  * by _exithandle() (recursive exit()).  All that is required is
677c478bd9Sstevel@tonic-gate  * that the registered functions actually return (no longjmp()s).
687c478bd9Sstevel@tonic-gate  *
697c478bd9Sstevel@tonic-gate  * Because exitfns_lock is declared to be a recursive mutex, we
707c478bd9Sstevel@tonic-gate  * cannot use it with lmutex_lock()/lmutex_unlock() and we must use
717c478bd9Sstevel@tonic-gate  * rmutex_lock()/rmutex_unlock() (which are defined to be simply
727c478bd9Sstevel@tonic-gate  * mutex_lock()/mutex_unlock()).  This means that atexit() and
737c478bd9Sstevel@tonic-gate  * exit() are not async-signal-safe.  We make them fork1-safe
747c478bd9Sstevel@tonic-gate  * via the atexit_locks()/atexit_unlocks() functions, called from
757c478bd9Sstevel@tonic-gate  * libc_prepare_atfork()/libc_child_atfork()/libc_parent_atfork()
767c478bd9Sstevel@tonic-gate  */
777c478bd9Sstevel@tonic-gate 
787c478bd9Sstevel@tonic-gate /*
797c478bd9Sstevel@tonic-gate  * atexit_locks() and atexit_unlocks() are called on every link map.
807c478bd9Sstevel@tonic-gate  * Do not use curthread->ul_uberdata->atexit_root for these.
817c478bd9Sstevel@tonic-gate  */
827c478bd9Sstevel@tonic-gate void
837c478bd9Sstevel@tonic-gate atexit_locks()
847c478bd9Sstevel@tonic-gate {
857c478bd9Sstevel@tonic-gate 	(void) rmutex_lock(&__uberdata.atexit_root.exitfns_lock);
867c478bd9Sstevel@tonic-gate }
877c478bd9Sstevel@tonic-gate 
887c478bd9Sstevel@tonic-gate void
897c478bd9Sstevel@tonic-gate atexit_unlocks()
907c478bd9Sstevel@tonic-gate {
917c478bd9Sstevel@tonic-gate 	(void) rmutex_unlock(&__uberdata.atexit_root.exitfns_lock);
927c478bd9Sstevel@tonic-gate }
937c478bd9Sstevel@tonic-gate 
947c478bd9Sstevel@tonic-gate /*
957c478bd9Sstevel@tonic-gate  * atexit() is called before the primordial thread is fully set up.
967c478bd9Sstevel@tonic-gate  * Be careful about dereferencing self->ul_uberdata->atexit_root.
977c478bd9Sstevel@tonic-gate  */
987c478bd9Sstevel@tonic-gate int
997c478bd9Sstevel@tonic-gate _atexit(void (*func)(void))
1007c478bd9Sstevel@tonic-gate {
1017c478bd9Sstevel@tonic-gate 	ulwp_t *self;
1027c478bd9Sstevel@tonic-gate 	atexit_root_t *arp;
1037c478bd9Sstevel@tonic-gate 	_exthdlr_t *p;
1047c478bd9Sstevel@tonic-gate 
1057c478bd9Sstevel@tonic-gate 	if ((p = lmalloc(sizeof (_exthdlr_t))) == NULL)
1067c478bd9Sstevel@tonic-gate 		return (-1);
1077c478bd9Sstevel@tonic-gate 
1087c478bd9Sstevel@tonic-gate 	if ((self = __curthread()) == NULL)
1097c478bd9Sstevel@tonic-gate 		arp = &__uberdata.atexit_root;
1107c478bd9Sstevel@tonic-gate 	else {
1117c478bd9Sstevel@tonic-gate 		arp = &self->ul_uberdata->atexit_root;
1127c478bd9Sstevel@tonic-gate 		(void) rmutex_lock(&arp->exitfns_lock);
1137c478bd9Sstevel@tonic-gate 	}
1147c478bd9Sstevel@tonic-gate 	p->hdlr = func;
1157c478bd9Sstevel@tonic-gate 	p->next = arp->head;
1167c478bd9Sstevel@tonic-gate 	arp->head = p;
1177c478bd9Sstevel@tonic-gate 	if (self != NULL)
1187c478bd9Sstevel@tonic-gate 		(void) rmutex_unlock(&arp->exitfns_lock);
1197c478bd9Sstevel@tonic-gate 	return (0);
1207c478bd9Sstevel@tonic-gate }
1217c478bd9Sstevel@tonic-gate 
1227c478bd9Sstevel@tonic-gate void
1237c478bd9Sstevel@tonic-gate _exithandle(void)
1247c478bd9Sstevel@tonic-gate {
1257c478bd9Sstevel@tonic-gate 	atexit_root_t *arp = &curthread->ul_uberdata->atexit_root;
1267c478bd9Sstevel@tonic-gate 	_exthdlr_t *p;
1277c478bd9Sstevel@tonic-gate 
1287c478bd9Sstevel@tonic-gate 	(void) rmutex_lock(&arp->exitfns_lock);
1297c478bd9Sstevel@tonic-gate 	arp->exit_frame_monitor = _getfp() + STACK_BIAS;
1307c478bd9Sstevel@tonic-gate 	p = arp->head;
1317c478bd9Sstevel@tonic-gate 	while (p != NULL) {
1327c478bd9Sstevel@tonic-gate 		arp->head = p->next;
1337c478bd9Sstevel@tonic-gate 		p->hdlr();
1347c478bd9Sstevel@tonic-gate 		lfree(p, sizeof (_exthdlr_t));
1357c478bd9Sstevel@tonic-gate 		p = arp->head;
1367c478bd9Sstevel@tonic-gate 	}
1377c478bd9Sstevel@tonic-gate 	(void) rmutex_unlock(&arp->exitfns_lock);
1387c478bd9Sstevel@tonic-gate }
1397c478bd9Sstevel@tonic-gate 
1407c478bd9Sstevel@tonic-gate /*
1417c478bd9Sstevel@tonic-gate  * _get_exit_frame_monitor is called by the C++ runtimes.
1427c478bd9Sstevel@tonic-gate  */
1437c478bd9Sstevel@tonic-gate void *
1447c478bd9Sstevel@tonic-gate _get_exit_frame_monitor(void)
1457c478bd9Sstevel@tonic-gate {
1467c478bd9Sstevel@tonic-gate 	atexit_root_t *arp = &curthread->ul_uberdata->atexit_root;
1477c478bd9Sstevel@tonic-gate 	return (&arp->exit_frame_monitor);
1487c478bd9Sstevel@tonic-gate }
1497c478bd9Sstevel@tonic-gate 
1507c478bd9Sstevel@tonic-gate /*
1517c478bd9Sstevel@tonic-gate  * The following is a routine which the loader (ld.so.1) calls when it
1527c478bd9Sstevel@tonic-gate  * processes a dlclose call on an object.  It resets all signal handlers
1537c478bd9Sstevel@tonic-gate  * which fall within the union of the ranges specified by the elements
1547c478bd9Sstevel@tonic-gate  * of the array range to SIG_DFL.
1557c478bd9Sstevel@tonic-gate  */
1567c478bd9Sstevel@tonic-gate static void
1577c478bd9Sstevel@tonic-gate _preexec_sig_unload(Lc_addr_range_t range[], uint_t count)
1587c478bd9Sstevel@tonic-gate {
1597c478bd9Sstevel@tonic-gate 	uberdata_t *udp = curthread->ul_uberdata;
1607c478bd9Sstevel@tonic-gate 	int sig;
16141efec22Sraf 	rwlock_t *rwlp;
1627c478bd9Sstevel@tonic-gate 	struct sigaction *sap;
1637c478bd9Sstevel@tonic-gate 	struct sigaction oact;
1647c478bd9Sstevel@tonic-gate 	void (*handler)();
1657c478bd9Sstevel@tonic-gate 
1667c478bd9Sstevel@tonic-gate 	for (sig = 1; sig < NSIG; sig++) {
1677c478bd9Sstevel@tonic-gate 		sap = (struct sigaction *)&udp->siguaction[sig].sig_uaction;
1687c478bd9Sstevel@tonic-gate again:
1697c478bd9Sstevel@tonic-gate 		handler = sap->sa_handler;
1707c478bd9Sstevel@tonic-gate 		if (handler != SIG_DFL && handler != SIG_IGN &&
1717c478bd9Sstevel@tonic-gate 		    in_range(handler, range, count)) {
17241efec22Sraf 			rwlp = &udp->siguaction[sig].sig_lock;
17341efec22Sraf 			lrw_wrlock(rwlp);
1747c478bd9Sstevel@tonic-gate 			if (handler != sap->sa_handler) {
17541efec22Sraf 				lrw_unlock(rwlp);
1767c478bd9Sstevel@tonic-gate 				goto again;
1777c478bd9Sstevel@tonic-gate 			}
1787c478bd9Sstevel@tonic-gate 			sap->sa_handler = SIG_DFL;
1797c478bd9Sstevel@tonic-gate 			sap->sa_flags = SA_SIGINFO;
1807c478bd9Sstevel@tonic-gate 			(void) sigemptyset(&sap->sa_mask);
1817c478bd9Sstevel@tonic-gate 			if (__sigaction(sig, NULL, &oact) == 0 &&
1827c478bd9Sstevel@tonic-gate 			    oact.sa_handler != SIG_DFL &&
1837c478bd9Sstevel@tonic-gate 			    oact.sa_handler != SIG_IGN)
1847c478bd9Sstevel@tonic-gate 				(void) __sigaction(sig, sap, NULL);
18541efec22Sraf 			lrw_unlock(rwlp);
1867c478bd9Sstevel@tonic-gate 		}
1877c478bd9Sstevel@tonic-gate 	}
1887c478bd9Sstevel@tonic-gate }
1897c478bd9Sstevel@tonic-gate 
1907c478bd9Sstevel@tonic-gate /*
1917c478bd9Sstevel@tonic-gate  * The following is a routine which the loader (ld.so.1) calls when it
1927c478bd9Sstevel@tonic-gate  * processes a dlclose call on an object.  It cancels all atfork() entries
1937c478bd9Sstevel@tonic-gate  * whose prefork, parent postfork, or child postfork functions fall within
1947c478bd9Sstevel@tonic-gate  * the union of the ranges specified by the elements of the array range.
1957c478bd9Sstevel@tonic-gate  */
1967c478bd9Sstevel@tonic-gate static void
1977c478bd9Sstevel@tonic-gate _preexec_atfork_unload(Lc_addr_range_t range[], uint_t count)
1987c478bd9Sstevel@tonic-gate {
199*2e145884Sraf 	ulwp_t *self = curthread;
200*2e145884Sraf 	uberdata_t *udp = self->ul_uberdata;
2017c478bd9Sstevel@tonic-gate 	atfork_t *atfork_q;
2027c478bd9Sstevel@tonic-gate 	atfork_t *atfp;
2037c478bd9Sstevel@tonic-gate 	atfork_t *next;
2047c478bd9Sstevel@tonic-gate 	void (*func)(void);
2057c478bd9Sstevel@tonic-gate 	int start_again;
2067c478bd9Sstevel@tonic-gate 
207*2e145884Sraf 	(void) _private_mutex_lock(&udp->atfork_lock);
2087c478bd9Sstevel@tonic-gate 	if ((atfork_q = udp->atforklist) != NULL) {
2097c478bd9Sstevel@tonic-gate 		atfp = atfork_q;
2107c478bd9Sstevel@tonic-gate 		do {
2117c478bd9Sstevel@tonic-gate 			next = atfp->forw;
2127c478bd9Sstevel@tonic-gate 			start_again = 0;
2137c478bd9Sstevel@tonic-gate 
2147c478bd9Sstevel@tonic-gate 			if (((func = atfp->prepare) != NULL &&
2157c478bd9Sstevel@tonic-gate 			    in_range(func, range, count)) ||
2167c478bd9Sstevel@tonic-gate 			    ((func = atfp->parent) != NULL &&
2177c478bd9Sstevel@tonic-gate 			    in_range(func, range, count)) ||
2187c478bd9Sstevel@tonic-gate 			    ((func = atfp->child) != NULL &&
2197c478bd9Sstevel@tonic-gate 			    in_range(func, range, count))) {
220*2e145884Sraf 				if (self->ul_fork) {
2217c478bd9Sstevel@tonic-gate 					/*
2227c478bd9Sstevel@tonic-gate 					 * dlclose() called from a fork handler.
2237c478bd9Sstevel@tonic-gate 					 * Deleting the entry would wreak havoc.
2247c478bd9Sstevel@tonic-gate 					 * Just null out the function pointers
2257c478bd9Sstevel@tonic-gate 					 * and leave the entry in place.
2267c478bd9Sstevel@tonic-gate 					 */
2277c478bd9Sstevel@tonic-gate 					atfp->prepare = NULL;
2287c478bd9Sstevel@tonic-gate 					atfp->parent = NULL;
2297c478bd9Sstevel@tonic-gate 					atfp->child = NULL;
2307c478bd9Sstevel@tonic-gate 					continue;
2317c478bd9Sstevel@tonic-gate 				}
2327c478bd9Sstevel@tonic-gate 				if (atfp == atfork_q) {
2337c478bd9Sstevel@tonic-gate 					/* deleting the list head member */
2347c478bd9Sstevel@tonic-gate 					udp->atforklist = atfork_q = next;
2357c478bd9Sstevel@tonic-gate 					start_again = 1;
2367c478bd9Sstevel@tonic-gate 				}
2377c478bd9Sstevel@tonic-gate 				atfp->forw->back = atfp->back;
2387c478bd9Sstevel@tonic-gate 				atfp->back->forw = atfp->forw;
2397c478bd9Sstevel@tonic-gate 				lfree(atfp, sizeof (atfork_t));
2407c478bd9Sstevel@tonic-gate 				if (atfp == atfork_q) {
2417c478bd9Sstevel@tonic-gate 					/* we deleted the whole list */
2427c478bd9Sstevel@tonic-gate 					udp->atforklist = NULL;
2437c478bd9Sstevel@tonic-gate 					break;
2447c478bd9Sstevel@tonic-gate 				}
2457c478bd9Sstevel@tonic-gate 			}
2467c478bd9Sstevel@tonic-gate 		} while ((atfp = next) != atfork_q || start_again);
2477c478bd9Sstevel@tonic-gate 	}
248*2e145884Sraf 	(void) _private_mutex_unlock(&udp->atfork_lock);
2497c478bd9Sstevel@tonic-gate }
2507c478bd9Sstevel@tonic-gate 
2517c478bd9Sstevel@tonic-gate /*
2527c478bd9Sstevel@tonic-gate  * The following is a routine which the loader (ld.so.1) calls when it
2537c478bd9Sstevel@tonic-gate  * processes a dlclose call on an object.  It sets the destructor
2547c478bd9Sstevel@tonic-gate  * function pointer to NULL for all keys whose destructors fall within
2557c478bd9Sstevel@tonic-gate  * the union of the ranges specified by the elements of the array range.
2567c478bd9Sstevel@tonic-gate  * We don't assign TSD_UNALLOCATED (the equivalent of pthread_key_destroy())
2577c478bd9Sstevel@tonic-gate  * because the thread may use the key's TSD further on in fini processing.
2587c478bd9Sstevel@tonic-gate  */
2597c478bd9Sstevel@tonic-gate static void
2607c478bd9Sstevel@tonic-gate _preexec_tsd_unload(Lc_addr_range_t range[], uint_t count)
2617c478bd9Sstevel@tonic-gate {
2627c478bd9Sstevel@tonic-gate 	tsd_metadata_t *tsdm = &curthread->ul_uberdata->tsd_metadata;
2637c478bd9Sstevel@tonic-gate 	void (*func)(void *);
2647c478bd9Sstevel@tonic-gate 	int key;
2657c478bd9Sstevel@tonic-gate 
2667c478bd9Sstevel@tonic-gate 	lmutex_lock(&tsdm->tsdm_lock);
2677c478bd9Sstevel@tonic-gate 	for (key = 1; key < tsdm->tsdm_nused; key++) {
2687c478bd9Sstevel@tonic-gate 		if ((func = tsdm->tsdm_destro[key]) != NULL &&
2697c478bd9Sstevel@tonic-gate 		    func != TSD_UNALLOCATED &&
2707c478bd9Sstevel@tonic-gate 		    in_range((_exithdlr_func_t)func, range, count))
2717c478bd9Sstevel@tonic-gate 			tsdm->tsdm_destro[key] = NULL;
2727c478bd9Sstevel@tonic-gate 	}
2737c478bd9Sstevel@tonic-gate 	lmutex_unlock(&tsdm->tsdm_lock);
2747c478bd9Sstevel@tonic-gate }
2757c478bd9Sstevel@tonic-gate 
2767c478bd9Sstevel@tonic-gate /*
2777c478bd9Sstevel@tonic-gate  * The following is a routine which the loader (ld.so.1) calls when it
2787c478bd9Sstevel@tonic-gate  * processes dlclose calls on objects with atexit registrations.  It
2797c478bd9Sstevel@tonic-gate  * executes the exit handlers that fall within the union of the ranges
2807c478bd9Sstevel@tonic-gate  * specified by the elements of the array range in the REVERSE ORDER of
2817c478bd9Sstevel@tonic-gate  * their registration.  Do not change this characteristic; it is REQUIRED
2827c478bd9Sstevel@tonic-gate  * BEHAVIOR.
2837c478bd9Sstevel@tonic-gate  */
2847c478bd9Sstevel@tonic-gate int
2857c478bd9Sstevel@tonic-gate _preexec_exit_handlers(Lc_addr_range_t range[], uint_t count)
2867c478bd9Sstevel@tonic-gate {
2877c478bd9Sstevel@tonic-gate 	atexit_root_t *arp = &curthread->ul_uberdata->atexit_root;
2887c478bd9Sstevel@tonic-gate 	_exthdlr_t *o;		/* previous node */
2897c478bd9Sstevel@tonic-gate 	_exthdlr_t *p;		/* this node */
2907c478bd9Sstevel@tonic-gate 
2917c478bd9Sstevel@tonic-gate 	(void) rmutex_lock(&arp->exitfns_lock);
2927c478bd9Sstevel@tonic-gate 	o = NULL;
2937c478bd9Sstevel@tonic-gate 	p = arp->head;
2947c478bd9Sstevel@tonic-gate 	while (p != NULL) {
2957c478bd9Sstevel@tonic-gate 		if (in_range(p->hdlr, range, count)) {
2967c478bd9Sstevel@tonic-gate 			/* We need to execute this one */
2977c478bd9Sstevel@tonic-gate 			if (o != NULL)
2987c478bd9Sstevel@tonic-gate 				o->next = p->next;
2997c478bd9Sstevel@tonic-gate 			else
3007c478bd9Sstevel@tonic-gate 				arp->head = p->next;
3017c478bd9Sstevel@tonic-gate 			p->hdlr();
3027c478bd9Sstevel@tonic-gate 			lfree(p, sizeof (_exthdlr_t));
3037c478bd9Sstevel@tonic-gate 			o = NULL;
3047c478bd9Sstevel@tonic-gate 			p = arp->head;
3057c478bd9Sstevel@tonic-gate 		} else {
3067c478bd9Sstevel@tonic-gate 			o = p;
3077c478bd9Sstevel@tonic-gate 			p = p->next;
3087c478bd9Sstevel@tonic-gate 		}
3097c478bd9Sstevel@tonic-gate 	}
3107c478bd9Sstevel@tonic-gate 	(void) rmutex_unlock(&arp->exitfns_lock);
3117c478bd9Sstevel@tonic-gate 
3127c478bd9Sstevel@tonic-gate 	_preexec_tsd_unload(range, count);
3137c478bd9Sstevel@tonic-gate 	_preexec_atfork_unload(range, count);
3147c478bd9Sstevel@tonic-gate 	_preexec_sig_unload(range, count);
3157c478bd9Sstevel@tonic-gate 
3167c478bd9Sstevel@tonic-gate 	return (0);
3177c478bd9Sstevel@tonic-gate }
3187c478bd9Sstevel@tonic-gate 
3197c478bd9Sstevel@tonic-gate static int
3207c478bd9Sstevel@tonic-gate in_range(_exithdlr_func_t addr, Lc_addr_range_t ranges[], uint_t count)
3217c478bd9Sstevel@tonic-gate {
3227c478bd9Sstevel@tonic-gate 	uint_t idx;
3237c478bd9Sstevel@tonic-gate 
3247c478bd9Sstevel@tonic-gate 	for (idx = 0; idx < count; idx++) {
3257c478bd9Sstevel@tonic-gate 		if ((void *)addr >= ranges[idx].lb &&
3267c478bd9Sstevel@tonic-gate 		    (void *)addr < ranges[idx].ub) {
3277c478bd9Sstevel@tonic-gate 			return (1);
3287c478bd9Sstevel@tonic-gate 		}
3297c478bd9Sstevel@tonic-gate 	}
3307c478bd9Sstevel@tonic-gate 
3317c478bd9Sstevel@tonic-gate 	return (0);
3327c478bd9Sstevel@tonic-gate }
333