xref: /titanic_52/usr/src/lib/libc_db/common/thread_db.c (revision cd8037ee05b2c5598728fdcd498596fc17bfdfa3)
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  */
2141efec22Sraf 
227c478bd9Sstevel@tonic-gate /*
23d4204c85Sraf  * Copyright 2008 Sun Microsystems, Inc.  All rights reserved.
247c478bd9Sstevel@tonic-gate  * Use is subject to license terms.
257c478bd9Sstevel@tonic-gate  */
267c478bd9Sstevel@tonic-gate 
27*cd8037eeSBryan Cantrill /*
28*cd8037eeSBryan Cantrill  * Copyright (c) 2014, Joyent, Inc. All rights reserved.
29*cd8037eeSBryan Cantrill  */
30*cd8037eeSBryan Cantrill 
317c478bd9Sstevel@tonic-gate #include <stdio.h>
327c478bd9Sstevel@tonic-gate #include <stdlib.h>
337c478bd9Sstevel@tonic-gate #include <stddef.h>
347c478bd9Sstevel@tonic-gate #include <unistd.h>
357c478bd9Sstevel@tonic-gate #include <thr_uberdata.h>
367c478bd9Sstevel@tonic-gate #include <thread_db.h>
377c478bd9Sstevel@tonic-gate #include <libc_int.h>
387c478bd9Sstevel@tonic-gate 
397c478bd9Sstevel@tonic-gate /*
407c478bd9Sstevel@tonic-gate  * Private structures.
417c478bd9Sstevel@tonic-gate  */
427c478bd9Sstevel@tonic-gate 
437c478bd9Sstevel@tonic-gate typedef union {
447c478bd9Sstevel@tonic-gate 	mutex_t		lock;
457c478bd9Sstevel@tonic-gate 	rwlock_t	rwlock;
467c478bd9Sstevel@tonic-gate 	sema_t		semaphore;
477c478bd9Sstevel@tonic-gate 	cond_t		condition;
487c478bd9Sstevel@tonic-gate } td_so_un_t;
497c478bd9Sstevel@tonic-gate 
507c478bd9Sstevel@tonic-gate struct td_thragent {
517c478bd9Sstevel@tonic-gate 	rwlock_t	rwlock;
527c478bd9Sstevel@tonic-gate 	struct ps_prochandle *ph_p;
537c478bd9Sstevel@tonic-gate 	int		initialized;
547c478bd9Sstevel@tonic-gate 	int		sync_tracking;
557c478bd9Sstevel@tonic-gate 	int		model;
567c478bd9Sstevel@tonic-gate 	int		primary_map;
577c478bd9Sstevel@tonic-gate 	psaddr_t	bootstrap_addr;
587c478bd9Sstevel@tonic-gate 	psaddr_t	uberdata_addr;
597c478bd9Sstevel@tonic-gate 	psaddr_t	tdb_eventmask_addr;
607c478bd9Sstevel@tonic-gate 	psaddr_t	tdb_register_sync_addr;
617c478bd9Sstevel@tonic-gate 	psaddr_t	tdb_events[TD_MAX_EVENT_NUM - TD_MIN_EVENT_NUM + 1];
627c478bd9Sstevel@tonic-gate 	psaddr_t	hash_table_addr;
637c478bd9Sstevel@tonic-gate 	int		hash_size;
647c478bd9Sstevel@tonic-gate 	lwpid_t		single_lwpid;
657c478bd9Sstevel@tonic-gate 	psaddr_t	single_ulwp_addr;
667c478bd9Sstevel@tonic-gate };
677c478bd9Sstevel@tonic-gate 
687c478bd9Sstevel@tonic-gate /*
697c478bd9Sstevel@tonic-gate  * This is the name of the variable in libc that contains
707c478bd9Sstevel@tonic-gate  * the uberdata address that we will need.
717c478bd9Sstevel@tonic-gate  */
727c478bd9Sstevel@tonic-gate #define	TD_BOOTSTRAP_NAME	"_tdb_bootstrap"
737c478bd9Sstevel@tonic-gate /*
747c478bd9Sstevel@tonic-gate  * This is the actual name of uberdata, used in the event
757c478bd9Sstevel@tonic-gate  * that tdb_bootstrap has not yet been initialized.
767c478bd9Sstevel@tonic-gate  */
777c478bd9Sstevel@tonic-gate #define	TD_UBERDATA_NAME	"_uberdata"
787c478bd9Sstevel@tonic-gate /*
797c478bd9Sstevel@tonic-gate  * The library name should end with ".so.1", but older versions of
807c478bd9Sstevel@tonic-gate  * dbx expect the unadorned name and malfunction if ".1" is specified.
817c478bd9Sstevel@tonic-gate  * Unfortunately, if ".1" is not specified, mdb malfunctions when it
827c478bd9Sstevel@tonic-gate  * is applied to another instance of itself (due to the presence of
837c478bd9Sstevel@tonic-gate  * /usr/lib/mdb/proc/libc.so).  So we try it both ways.
847c478bd9Sstevel@tonic-gate  */
857c478bd9Sstevel@tonic-gate #define	TD_LIBRARY_NAME		"libc.so"
867c478bd9Sstevel@tonic-gate #define	TD_LIBRARY_NAME_1	"libc.so.1"
877c478bd9Sstevel@tonic-gate 
887c478bd9Sstevel@tonic-gate td_err_e __td_thr_get_info(td_thrhandle_t *th_p, td_thrinfo_t *ti_p);
897c478bd9Sstevel@tonic-gate 
907c478bd9Sstevel@tonic-gate td_err_e __td_ta_thr_iter(td_thragent_t *ta_p, td_thr_iter_f *cb,
917c478bd9Sstevel@tonic-gate 	void *cbdata_p, td_thr_state_e state, int ti_pri,
927c478bd9Sstevel@tonic-gate 	sigset_t *ti_sigmask_p, unsigned ti_user_flags);
937c478bd9Sstevel@tonic-gate 
947c478bd9Sstevel@tonic-gate /*
957c478bd9Sstevel@tonic-gate  * Initialize threads debugging interface.
967c478bd9Sstevel@tonic-gate  */
977c478bd9Sstevel@tonic-gate #pragma weak td_init = __td_init
987c478bd9Sstevel@tonic-gate td_err_e
997c478bd9Sstevel@tonic-gate __td_init()
1007c478bd9Sstevel@tonic-gate {
1017c478bd9Sstevel@tonic-gate 	return (TD_OK);
1027c478bd9Sstevel@tonic-gate }
1037c478bd9Sstevel@tonic-gate 
1047c478bd9Sstevel@tonic-gate /*
1057c478bd9Sstevel@tonic-gate  * This function does nothing, and never did.
1067c478bd9Sstevel@tonic-gate  * But the symbol is in the ABI, so we can't delete it.
1077c478bd9Sstevel@tonic-gate  */
1087c478bd9Sstevel@tonic-gate #pragma weak td_log = __td_log
1097c478bd9Sstevel@tonic-gate void
1107c478bd9Sstevel@tonic-gate __td_log()
1117c478bd9Sstevel@tonic-gate {
1127c478bd9Sstevel@tonic-gate }
1137c478bd9Sstevel@tonic-gate 
1147c478bd9Sstevel@tonic-gate /*
1157c478bd9Sstevel@tonic-gate  * Short-cut to read just the hash table size from the process,
1167c478bd9Sstevel@tonic-gate  * to avoid repeatedly reading the full uberdata structure when
1177c478bd9Sstevel@tonic-gate  * dealing with a single-threaded process.
1187c478bd9Sstevel@tonic-gate  */
1197c478bd9Sstevel@tonic-gate static uint_t
1207c478bd9Sstevel@tonic-gate td_read_hash_size(td_thragent_t *ta_p)
1217c478bd9Sstevel@tonic-gate {
1227c478bd9Sstevel@tonic-gate 	psaddr_t addr;
1237c478bd9Sstevel@tonic-gate 	uint_t hash_size;
1247c478bd9Sstevel@tonic-gate 
1257c478bd9Sstevel@tonic-gate 	switch (ta_p->initialized) {
1267c478bd9Sstevel@tonic-gate 	default:	/* uninitialized */
1277c478bd9Sstevel@tonic-gate 		return (0);
1287c478bd9Sstevel@tonic-gate 	case 1:		/* partially initialized */
1297c478bd9Sstevel@tonic-gate 		break;
1307c478bd9Sstevel@tonic-gate 	case 2:		/* fully initialized */
1317c478bd9Sstevel@tonic-gate 		return (ta_p->hash_size);
1327c478bd9Sstevel@tonic-gate 	}
1337c478bd9Sstevel@tonic-gate 
1347c478bd9Sstevel@tonic-gate 	if (ta_p->model == PR_MODEL_NATIVE) {
1357c478bd9Sstevel@tonic-gate 		addr = ta_p->uberdata_addr + offsetof(uberdata_t, hash_size);
1367c478bd9Sstevel@tonic-gate 	} else {
1377c478bd9Sstevel@tonic-gate #if defined(_LP64) && defined(_SYSCALL32)
1387c478bd9Sstevel@tonic-gate 		addr = ta_p->uberdata_addr + offsetof(uberdata32_t, hash_size);
1397c478bd9Sstevel@tonic-gate #else
1407c478bd9Sstevel@tonic-gate 		addr = 0;
1417c478bd9Sstevel@tonic-gate #endif
1427c478bd9Sstevel@tonic-gate 	}
1437c478bd9Sstevel@tonic-gate 	if (ps_pdread(ta_p->ph_p, addr, &hash_size, sizeof (hash_size))
1447c478bd9Sstevel@tonic-gate 	    != PS_OK)
1457c478bd9Sstevel@tonic-gate 		return (0);
1467c478bd9Sstevel@tonic-gate 	return (hash_size);
1477c478bd9Sstevel@tonic-gate }
1487c478bd9Sstevel@tonic-gate 
1497c478bd9Sstevel@tonic-gate static td_err_e
1507c478bd9Sstevel@tonic-gate td_read_uberdata(td_thragent_t *ta_p)
1517c478bd9Sstevel@tonic-gate {
1527c478bd9Sstevel@tonic-gate 	struct ps_prochandle *ph_p = ta_p->ph_p;
153*cd8037eeSBryan Cantrill 	int i;
1547c478bd9Sstevel@tonic-gate 
1557c478bd9Sstevel@tonic-gate 	if (ta_p->model == PR_MODEL_NATIVE) {
1567c478bd9Sstevel@tonic-gate 		uberdata_t uberdata;
1577c478bd9Sstevel@tonic-gate 
1587c478bd9Sstevel@tonic-gate 		if (ps_pdread(ph_p, ta_p->uberdata_addr,
1597c478bd9Sstevel@tonic-gate 		    &uberdata, sizeof (uberdata)) != PS_OK)
1607c478bd9Sstevel@tonic-gate 			return (TD_DBERR);
1617c478bd9Sstevel@tonic-gate 		ta_p->primary_map = uberdata.primary_map;
1627c478bd9Sstevel@tonic-gate 		ta_p->tdb_eventmask_addr = ta_p->uberdata_addr +
1637c478bd9Sstevel@tonic-gate 		    offsetof(uberdata_t, tdb.tdb_ev_global_mask);
1647c478bd9Sstevel@tonic-gate 		ta_p->tdb_register_sync_addr = ta_p->uberdata_addr +
1657c478bd9Sstevel@tonic-gate 		    offsetof(uberdata_t, uberflags.uf_tdb_register_sync);
1667c478bd9Sstevel@tonic-gate 		ta_p->hash_table_addr = (psaddr_t)uberdata.thr_hash_table;
1677c478bd9Sstevel@tonic-gate 		ta_p->hash_size = uberdata.hash_size;
1687c478bd9Sstevel@tonic-gate 		if (ps_pdread(ph_p, (psaddr_t)uberdata.tdb.tdb_events,
1697c478bd9Sstevel@tonic-gate 		    ta_p->tdb_events, sizeof (ta_p->tdb_events)) != PS_OK)
1707c478bd9Sstevel@tonic-gate 			return (TD_DBERR);
1717c478bd9Sstevel@tonic-gate 	} else {
1727c478bd9Sstevel@tonic-gate #if defined(_LP64) && defined(_SYSCALL32)
1737c478bd9Sstevel@tonic-gate 		uberdata32_t uberdata;
1747c478bd9Sstevel@tonic-gate 		caddr32_t tdb_events[TD_MAX_EVENT_NUM - TD_MIN_EVENT_NUM + 1];
1757c478bd9Sstevel@tonic-gate 
1767c478bd9Sstevel@tonic-gate 		if (ps_pdread(ph_p, ta_p->uberdata_addr,
1777c478bd9Sstevel@tonic-gate 		    &uberdata, sizeof (uberdata)) != PS_OK)
1787c478bd9Sstevel@tonic-gate 			return (TD_DBERR);
1797c478bd9Sstevel@tonic-gate 		ta_p->primary_map = uberdata.primary_map;
1807c478bd9Sstevel@tonic-gate 		ta_p->tdb_eventmask_addr = ta_p->uberdata_addr +
1817c478bd9Sstevel@tonic-gate 		    offsetof(uberdata32_t, tdb.tdb_ev_global_mask);
1827c478bd9Sstevel@tonic-gate 		ta_p->tdb_register_sync_addr = ta_p->uberdata_addr +
1837c478bd9Sstevel@tonic-gate 		    offsetof(uberdata32_t, uberflags.uf_tdb_register_sync);
1847c478bd9Sstevel@tonic-gate 		ta_p->hash_table_addr = (psaddr_t)uberdata.thr_hash_table;
1857c478bd9Sstevel@tonic-gate 		ta_p->hash_size = uberdata.hash_size;
1867c478bd9Sstevel@tonic-gate 		if (ps_pdread(ph_p, (psaddr_t)uberdata.tdb.tdb_events,
1877c478bd9Sstevel@tonic-gate 		    tdb_events, sizeof (tdb_events)) != PS_OK)
1887c478bd9Sstevel@tonic-gate 			return (TD_DBERR);
1897c478bd9Sstevel@tonic-gate 		for (i = 0; i < TD_MAX_EVENT_NUM - TD_MIN_EVENT_NUM + 1; i++)
1907c478bd9Sstevel@tonic-gate 			ta_p->tdb_events[i] = tdb_events[i];
1917c478bd9Sstevel@tonic-gate #else
1927c478bd9Sstevel@tonic-gate 		return (TD_DBERR);
1937c478bd9Sstevel@tonic-gate #endif
1947c478bd9Sstevel@tonic-gate 	}
195*cd8037eeSBryan Cantrill 
196*cd8037eeSBryan Cantrill 	/*
197*cd8037eeSBryan Cantrill 	 * Unfortunately, we are (implicitly) assuming that our uberdata
198*cd8037eeSBryan Cantrill 	 * definition precisely matches that of our target.  If this is not
199*cd8037eeSBryan Cantrill 	 * true (that is, if we're examining a core file from a foreign
200*cd8037eeSBryan Cantrill 	 * system that has a different definition of uberdata), the failure
201*cd8037eeSBryan Cantrill 	 * modes can be frustratingly non-explicit.  In an effort to catch
202*cd8037eeSBryan Cantrill 	 * this upon initialization (when the debugger may still be able to
203*cd8037eeSBryan Cantrill 	 * opt for another thread model or may be able to fail explicitly), we
204*cd8037eeSBryan Cantrill 	 * check that each of our tdb_events points to valid memory (these are
205*cd8037eeSBryan Cantrill 	 * putatively text upon which a breakpoint can be issued), with the
206*cd8037eeSBryan Cantrill 	 * hope that this is enough of a self-consistency check to lead to
207*cd8037eeSBryan Cantrill 	 * explicit failure on a mismatch.
208*cd8037eeSBryan Cantrill 	 */
209*cd8037eeSBryan Cantrill 	for (i = 0; i < TD_MAX_EVENT_NUM - TD_MIN_EVENT_NUM + 1; i++) {
210*cd8037eeSBryan Cantrill 		uint8_t check;
211*cd8037eeSBryan Cantrill 
212*cd8037eeSBryan Cantrill 		if (ps_pdread(ph_p, (psaddr_t)ta_p->tdb_events[i],
213*cd8037eeSBryan Cantrill 		    &check, sizeof (check)) != PS_OK) {
214*cd8037eeSBryan Cantrill 			return (TD_DBERR);
215*cd8037eeSBryan Cantrill 		}
216*cd8037eeSBryan Cantrill 	}
217*cd8037eeSBryan Cantrill 
2187c478bd9Sstevel@tonic-gate 	if (ta_p->hash_size != 1) {	/* multi-threaded */
2197c478bd9Sstevel@tonic-gate 		ta_p->initialized = 2;
2207c478bd9Sstevel@tonic-gate 		ta_p->single_lwpid = 0;
2217c478bd9Sstevel@tonic-gate 		ta_p->single_ulwp_addr = NULL;
2227c478bd9Sstevel@tonic-gate 	} else {			/* single-threaded */
2237c478bd9Sstevel@tonic-gate 		ta_p->initialized = 1;
2247c478bd9Sstevel@tonic-gate 		/*
2257c478bd9Sstevel@tonic-gate 		 * Get the address and lwpid of the single thread/LWP.
2267c478bd9Sstevel@tonic-gate 		 * It may not be ulwp_one if this is a child of fork1().
2277c478bd9Sstevel@tonic-gate 		 */
2287c478bd9Sstevel@tonic-gate 		if (ta_p->model == PR_MODEL_NATIVE) {
2297c478bd9Sstevel@tonic-gate 			thr_hash_table_t head;
2307c478bd9Sstevel@tonic-gate 			lwpid_t lwpid = 0;
2317c478bd9Sstevel@tonic-gate 
2327c478bd9Sstevel@tonic-gate 			if (ps_pdread(ph_p, ta_p->hash_table_addr,
2337c478bd9Sstevel@tonic-gate 			    &head, sizeof (head)) != PS_OK)
2347c478bd9Sstevel@tonic-gate 				return (TD_DBERR);
2357c478bd9Sstevel@tonic-gate 			if ((psaddr_t)head.hash_bucket == NULL)
2367c478bd9Sstevel@tonic-gate 				ta_p->initialized = 0;
2377c478bd9Sstevel@tonic-gate 			else if (ps_pdread(ph_p, (psaddr_t)head.hash_bucket +
2387c478bd9Sstevel@tonic-gate 			    offsetof(ulwp_t, ul_lwpid),
2397c478bd9Sstevel@tonic-gate 			    &lwpid, sizeof (lwpid)) != PS_OK)
2407c478bd9Sstevel@tonic-gate 				return (TD_DBERR);
2417c478bd9Sstevel@tonic-gate 			ta_p->single_lwpid = lwpid;
2427c478bd9Sstevel@tonic-gate 			ta_p->single_ulwp_addr = (psaddr_t)head.hash_bucket;
2437c478bd9Sstevel@tonic-gate 		} else {
2447c478bd9Sstevel@tonic-gate #if defined(_LP64) && defined(_SYSCALL32)
2457c478bd9Sstevel@tonic-gate 			thr_hash_table32_t head;
2467c478bd9Sstevel@tonic-gate 			lwpid_t lwpid = 0;
2477c478bd9Sstevel@tonic-gate 
2487c478bd9Sstevel@tonic-gate 			if (ps_pdread(ph_p, ta_p->hash_table_addr,
2497c478bd9Sstevel@tonic-gate 			    &head, sizeof (head)) != PS_OK)
2507c478bd9Sstevel@tonic-gate 				return (TD_DBERR);
2517c478bd9Sstevel@tonic-gate 			if ((psaddr_t)head.hash_bucket == NULL)
2527c478bd9Sstevel@tonic-gate 				ta_p->initialized = 0;
2537c478bd9Sstevel@tonic-gate 			else if (ps_pdread(ph_p, (psaddr_t)head.hash_bucket +
2547c478bd9Sstevel@tonic-gate 			    offsetof(ulwp32_t, ul_lwpid),
2557c478bd9Sstevel@tonic-gate 			    &lwpid, sizeof (lwpid)) != PS_OK)
2567c478bd9Sstevel@tonic-gate 				return (TD_DBERR);
2577c478bd9Sstevel@tonic-gate 			ta_p->single_lwpid = lwpid;
2587c478bd9Sstevel@tonic-gate 			ta_p->single_ulwp_addr = (psaddr_t)head.hash_bucket;
2597c478bd9Sstevel@tonic-gate #else
2607c478bd9Sstevel@tonic-gate 			return (TD_DBERR);
2617c478bd9Sstevel@tonic-gate #endif
2627c478bd9Sstevel@tonic-gate 		}
2637c478bd9Sstevel@tonic-gate 	}
2647c478bd9Sstevel@tonic-gate 	if (!ta_p->primary_map)
2657c478bd9Sstevel@tonic-gate 		ta_p->initialized = 0;
2667c478bd9Sstevel@tonic-gate 	return (TD_OK);
2677c478bd9Sstevel@tonic-gate }
2687c478bd9Sstevel@tonic-gate 
2697c478bd9Sstevel@tonic-gate static td_err_e
2707c478bd9Sstevel@tonic-gate td_read_bootstrap_data(td_thragent_t *ta_p)
2717c478bd9Sstevel@tonic-gate {
2727c478bd9Sstevel@tonic-gate 	struct ps_prochandle *ph_p = ta_p->ph_p;
2737c478bd9Sstevel@tonic-gate 	psaddr_t bootstrap_addr;
2747c478bd9Sstevel@tonic-gate 	psaddr_t uberdata_addr;
2757c478bd9Sstevel@tonic-gate 	ps_err_e db_return;
2767c478bd9Sstevel@tonic-gate 	td_err_e return_val;
2777c478bd9Sstevel@tonic-gate 	int do_1;
2787c478bd9Sstevel@tonic-gate 
2797c478bd9Sstevel@tonic-gate 	switch (ta_p->initialized) {
2807c478bd9Sstevel@tonic-gate 	case 2:			/* fully initialized */
2817c478bd9Sstevel@tonic-gate 		return (TD_OK);
2827c478bd9Sstevel@tonic-gate 	case 1:			/* partially initialized */
2837c478bd9Sstevel@tonic-gate 		if (td_read_hash_size(ta_p) == 1)
2847c478bd9Sstevel@tonic-gate 			return (TD_OK);
2857c478bd9Sstevel@tonic-gate 		return (td_read_uberdata(ta_p));
2867c478bd9Sstevel@tonic-gate 	}
2877c478bd9Sstevel@tonic-gate 
2887c478bd9Sstevel@tonic-gate 	/*
2897c478bd9Sstevel@tonic-gate 	 * Uninitialized -- do the startup work.
2907c478bd9Sstevel@tonic-gate 	 * We set ta_p->initialized to -1 to cut off recursive calls
2917c478bd9Sstevel@tonic-gate 	 * into libc_db by code in the provider of ps_pglobal_lookup().
2927c478bd9Sstevel@tonic-gate 	 */
2937c478bd9Sstevel@tonic-gate 	do_1 = 0;
2947c478bd9Sstevel@tonic-gate 	ta_p->initialized = -1;
2957c478bd9Sstevel@tonic-gate 	db_return = ps_pglobal_lookup(ph_p, TD_LIBRARY_NAME,
2967c478bd9Sstevel@tonic-gate 	    TD_BOOTSTRAP_NAME, &bootstrap_addr);
2977c478bd9Sstevel@tonic-gate 	if (db_return == PS_NOSYM) {
2987c478bd9Sstevel@tonic-gate 		do_1 = 1;
2997c478bd9Sstevel@tonic-gate 		db_return = ps_pglobal_lookup(ph_p, TD_LIBRARY_NAME_1,
3007c478bd9Sstevel@tonic-gate 		    TD_BOOTSTRAP_NAME, &bootstrap_addr);
3017c478bd9Sstevel@tonic-gate 	}
3027c478bd9Sstevel@tonic-gate 	if (db_return == PS_NOSYM)	/* libc is not linked yet */
3037c478bd9Sstevel@tonic-gate 		return (TD_NOLIBTHREAD);
3047c478bd9Sstevel@tonic-gate 	if (db_return != PS_OK)
3057c478bd9Sstevel@tonic-gate 		return (TD_ERR);
3067c478bd9Sstevel@tonic-gate 	db_return = ps_pglobal_lookup(ph_p,
3077c478bd9Sstevel@tonic-gate 	    do_1? TD_LIBRARY_NAME_1 : TD_LIBRARY_NAME,
3087c478bd9Sstevel@tonic-gate 	    TD_UBERDATA_NAME, &uberdata_addr);
3097c478bd9Sstevel@tonic-gate 	if (db_return == PS_NOSYM)	/* libc is not linked yet */
3107c478bd9Sstevel@tonic-gate 		return (TD_NOLIBTHREAD);
3117c478bd9Sstevel@tonic-gate 	if (db_return != PS_OK)
3127c478bd9Sstevel@tonic-gate 		return (TD_ERR);
3137c478bd9Sstevel@tonic-gate 
3147c478bd9Sstevel@tonic-gate 	/*
3157c478bd9Sstevel@tonic-gate 	 * Read the uberdata address into the thread agent structure.
3167c478bd9Sstevel@tonic-gate 	 */
3177c478bd9Sstevel@tonic-gate 	if (ta_p->model == PR_MODEL_NATIVE) {
3187c478bd9Sstevel@tonic-gate 		psaddr_t psaddr;
3197c478bd9Sstevel@tonic-gate 		if (ps_pdread(ph_p, bootstrap_addr,
3207c478bd9Sstevel@tonic-gate 		    &psaddr, sizeof (psaddr)) != PS_OK)
3217c478bd9Sstevel@tonic-gate 			return (TD_DBERR);
3227c478bd9Sstevel@tonic-gate 		if ((ta_p->bootstrap_addr = psaddr) == NULL)
3237c478bd9Sstevel@tonic-gate 			psaddr = uberdata_addr;
3247c478bd9Sstevel@tonic-gate 		else if (ps_pdread(ph_p, psaddr,
3257c478bd9Sstevel@tonic-gate 		    &psaddr, sizeof (psaddr)) != PS_OK)
3267c478bd9Sstevel@tonic-gate 			return (TD_DBERR);
327e33bf782SEdward Pilatowicz 		if (psaddr == NULL) {
328e33bf782SEdward Pilatowicz 			/* primary linkmap in the tgt is not initialized */
329e33bf782SEdward Pilatowicz 			ta_p->bootstrap_addr = NULL;
330e33bf782SEdward Pilatowicz 			psaddr = uberdata_addr;
331e33bf782SEdward Pilatowicz 		}
3327c478bd9Sstevel@tonic-gate 		ta_p->uberdata_addr = psaddr;
3337c478bd9Sstevel@tonic-gate 	} else {
3347c478bd9Sstevel@tonic-gate #if defined(_LP64) && defined(_SYSCALL32)
3357c478bd9Sstevel@tonic-gate 		caddr32_t psaddr;
3367c478bd9Sstevel@tonic-gate 		if (ps_pdread(ph_p, bootstrap_addr,
3377c478bd9Sstevel@tonic-gate 		    &psaddr, sizeof (psaddr)) != PS_OK)
3387c478bd9Sstevel@tonic-gate 			return (TD_DBERR);
3397c478bd9Sstevel@tonic-gate 		if ((ta_p->bootstrap_addr = (psaddr_t)psaddr) == NULL)
3407c478bd9Sstevel@tonic-gate 			psaddr = (caddr32_t)uberdata_addr;
3417c478bd9Sstevel@tonic-gate 		else if (ps_pdread(ph_p, (psaddr_t)psaddr,
3427c478bd9Sstevel@tonic-gate 		    &psaddr, sizeof (psaddr)) != PS_OK)
3437c478bd9Sstevel@tonic-gate 			return (TD_DBERR);
344e33bf782SEdward Pilatowicz 		if (psaddr == NULL) {
345e33bf782SEdward Pilatowicz 			/* primary linkmap in the tgt is not initialized */
346e33bf782SEdward Pilatowicz 			ta_p->bootstrap_addr = NULL;
347e33bf782SEdward Pilatowicz 			psaddr = (caddr32_t)uberdata_addr;
348e33bf782SEdward Pilatowicz 		}
3497c478bd9Sstevel@tonic-gate 		ta_p->uberdata_addr = (psaddr_t)psaddr;
3507c478bd9Sstevel@tonic-gate #else
3517c478bd9Sstevel@tonic-gate 		return (TD_DBERR);
3527c478bd9Sstevel@tonic-gate #endif	/* _SYSCALL32 */
3537c478bd9Sstevel@tonic-gate 	}
3547c478bd9Sstevel@tonic-gate 
3557c478bd9Sstevel@tonic-gate 	if ((return_val = td_read_uberdata(ta_p)) != TD_OK)
3567c478bd9Sstevel@tonic-gate 		return (return_val);
3577c478bd9Sstevel@tonic-gate 	if (ta_p->bootstrap_addr == NULL)
3587c478bd9Sstevel@tonic-gate 		ta_p->initialized = 0;
3597c478bd9Sstevel@tonic-gate 	return (TD_OK);
3607c478bd9Sstevel@tonic-gate }
3617c478bd9Sstevel@tonic-gate 
3627c478bd9Sstevel@tonic-gate #pragma weak ps_kill
3637c478bd9Sstevel@tonic-gate #pragma weak ps_lrolltoaddr
3647c478bd9Sstevel@tonic-gate 
3657c478bd9Sstevel@tonic-gate /*
3667c478bd9Sstevel@tonic-gate  * Allocate a new agent process handle ("thread agent").
3677c478bd9Sstevel@tonic-gate  */
3687c478bd9Sstevel@tonic-gate #pragma weak td_ta_new = __td_ta_new
3697c478bd9Sstevel@tonic-gate td_err_e
3707c478bd9Sstevel@tonic-gate __td_ta_new(struct ps_prochandle *ph_p, td_thragent_t **ta_pp)
3717c478bd9Sstevel@tonic-gate {
3727c478bd9Sstevel@tonic-gate 	td_thragent_t *ta_p;
3737c478bd9Sstevel@tonic-gate 	int model;
3747c478bd9Sstevel@tonic-gate 	td_err_e return_val = TD_OK;
3757c478bd9Sstevel@tonic-gate 
3767c478bd9Sstevel@tonic-gate 	if (ph_p == NULL)
3777c478bd9Sstevel@tonic-gate 		return (TD_BADPH);
3787c478bd9Sstevel@tonic-gate 	if (ta_pp == NULL)
3797c478bd9Sstevel@tonic-gate 		return (TD_ERR);
3807c478bd9Sstevel@tonic-gate 	*ta_pp = NULL;
3817c478bd9Sstevel@tonic-gate 	if (ps_pstop(ph_p) != PS_OK)
3827c478bd9Sstevel@tonic-gate 		return (TD_DBERR);
3837c478bd9Sstevel@tonic-gate 	/*
3847c478bd9Sstevel@tonic-gate 	 * ps_pdmodel might not be defined if this is an older client.
3857c478bd9Sstevel@tonic-gate 	 * Make it a weak symbol and test if it exists before calling.
3867c478bd9Sstevel@tonic-gate 	 */
3877c478bd9Sstevel@tonic-gate #pragma weak ps_pdmodel
3887c478bd9Sstevel@tonic-gate 	if (ps_pdmodel == NULL) {
3897c478bd9Sstevel@tonic-gate 		model = PR_MODEL_NATIVE;
3907c478bd9Sstevel@tonic-gate 	} else if (ps_pdmodel(ph_p, &model) != PS_OK) {
3917c478bd9Sstevel@tonic-gate 		(void) ps_pcontinue(ph_p);
3927c478bd9Sstevel@tonic-gate 		return (TD_ERR);
3937c478bd9Sstevel@tonic-gate 	}
3947c478bd9Sstevel@tonic-gate 	if ((ta_p = malloc(sizeof (*ta_p))) == NULL) {
3957c478bd9Sstevel@tonic-gate 		(void) ps_pcontinue(ph_p);
3967c478bd9Sstevel@tonic-gate 		return (TD_MALLOC);
3977c478bd9Sstevel@tonic-gate 	}
3987c478bd9Sstevel@tonic-gate 
3997c478bd9Sstevel@tonic-gate 	/*
4007c478bd9Sstevel@tonic-gate 	 * Initialize the agent process handle.
4017c478bd9Sstevel@tonic-gate 	 * Pick up the symbol value we need from the target process.
4027c478bd9Sstevel@tonic-gate 	 */
4037c478bd9Sstevel@tonic-gate 	(void) memset(ta_p, 0, sizeof (*ta_p));
4047c478bd9Sstevel@tonic-gate 	ta_p->ph_p = ph_p;
4057c478bd9Sstevel@tonic-gate 	(void) rwlock_init(&ta_p->rwlock, USYNC_THREAD, NULL);
4067c478bd9Sstevel@tonic-gate 	ta_p->model = model;
4077c478bd9Sstevel@tonic-gate 	return_val = td_read_bootstrap_data(ta_p);
4087c478bd9Sstevel@tonic-gate 
4097c478bd9Sstevel@tonic-gate 	/*
4107c478bd9Sstevel@tonic-gate 	 * Because the old libthread_db enabled lock tracking by default,
4117c478bd9Sstevel@tonic-gate 	 * we must also do it.  However, we do it only if the application
4127c478bd9Sstevel@tonic-gate 	 * provides the ps_kill() and ps_lrolltoaddr() interfaces.
4137c478bd9Sstevel@tonic-gate 	 * (dbx provides the ps_kill() and ps_lrolltoaddr() interfaces.)
4147c478bd9Sstevel@tonic-gate 	 */
4157c478bd9Sstevel@tonic-gate 	if (return_val == TD_OK && ps_kill != NULL && ps_lrolltoaddr != NULL) {
4167c478bd9Sstevel@tonic-gate 		register_sync_t oldenable;
4177c478bd9Sstevel@tonic-gate 		register_sync_t enable = REGISTER_SYNC_ENABLE;
4187c478bd9Sstevel@tonic-gate 		psaddr_t psaddr = ta_p->tdb_register_sync_addr;
4197c478bd9Sstevel@tonic-gate 
4207c478bd9Sstevel@tonic-gate 		if (ps_pdread(ph_p, psaddr,
4217c478bd9Sstevel@tonic-gate 		    &oldenable, sizeof (oldenable)) != PS_OK)
4227c478bd9Sstevel@tonic-gate 			return_val = TD_DBERR;
4237c478bd9Sstevel@tonic-gate 		else if (oldenable != REGISTER_SYNC_OFF ||
4247c478bd9Sstevel@tonic-gate 		    ps_pdwrite(ph_p, psaddr,
4257c478bd9Sstevel@tonic-gate 		    &enable, sizeof (enable)) != PS_OK) {
4267c478bd9Sstevel@tonic-gate 			/*
4277c478bd9Sstevel@tonic-gate 			 * Lock tracking was already enabled or we
4287c478bd9Sstevel@tonic-gate 			 * failed to enable it, probably because we
4297c478bd9Sstevel@tonic-gate 			 * are examining a core file.  In either case
4307c478bd9Sstevel@tonic-gate 			 * set the sync_tracking flag non-zero to
4317c478bd9Sstevel@tonic-gate 			 * indicate that we should not attempt to
4327c478bd9Sstevel@tonic-gate 			 * disable lock tracking when we delete the
4337c478bd9Sstevel@tonic-gate 			 * agent process handle in td_ta_delete().
4347c478bd9Sstevel@tonic-gate 			 */
4357c478bd9Sstevel@tonic-gate 			ta_p->sync_tracking = 1;
4367c478bd9Sstevel@tonic-gate 		}
4377c478bd9Sstevel@tonic-gate 	}
4387c478bd9Sstevel@tonic-gate 
4397c478bd9Sstevel@tonic-gate 	if (return_val == TD_OK)
4407c478bd9Sstevel@tonic-gate 		*ta_pp = ta_p;
4417c478bd9Sstevel@tonic-gate 	else
4427c478bd9Sstevel@tonic-gate 		free(ta_p);
4437c478bd9Sstevel@tonic-gate 
4447c478bd9Sstevel@tonic-gate 	(void) ps_pcontinue(ph_p);
4457c478bd9Sstevel@tonic-gate 	return (return_val);
4467c478bd9Sstevel@tonic-gate }
4477c478bd9Sstevel@tonic-gate 
4487c478bd9Sstevel@tonic-gate /*
4497c478bd9Sstevel@tonic-gate  * Utility function to grab the readers lock and return the prochandle,
4507c478bd9Sstevel@tonic-gate  * given an agent process handle.  Performs standard error checking.
4517c478bd9Sstevel@tonic-gate  * Returns non-NULL with the lock held, or NULL with the lock not held.
4527c478bd9Sstevel@tonic-gate  */
4537c478bd9Sstevel@tonic-gate static struct ps_prochandle *
4547c478bd9Sstevel@tonic-gate ph_lock_ta(td_thragent_t *ta_p, td_err_e *err)
4557c478bd9Sstevel@tonic-gate {
4567c478bd9Sstevel@tonic-gate 	struct ps_prochandle *ph_p = NULL;
4577c478bd9Sstevel@tonic-gate 	td_err_e error;
4587c478bd9Sstevel@tonic-gate 
4597c478bd9Sstevel@tonic-gate 	if (ta_p == NULL || ta_p->initialized == -1) {
4607c478bd9Sstevel@tonic-gate 		*err = TD_BADTA;
4617c478bd9Sstevel@tonic-gate 	} else if (rw_rdlock(&ta_p->rwlock) != 0) {	/* can't happen? */
4627c478bd9Sstevel@tonic-gate 		*err = TD_BADTA;
4637c478bd9Sstevel@tonic-gate 	} else if ((ph_p = ta_p->ph_p) == NULL) {
4647c478bd9Sstevel@tonic-gate 		(void) rw_unlock(&ta_p->rwlock);
4657c478bd9Sstevel@tonic-gate 		*err = TD_BADPH;
4667c478bd9Sstevel@tonic-gate 	} else if (ta_p->initialized != 2 &&
4677c478bd9Sstevel@tonic-gate 	    (error = td_read_bootstrap_data(ta_p)) != TD_OK) {
4687c478bd9Sstevel@tonic-gate 		(void) rw_unlock(&ta_p->rwlock);
4697c478bd9Sstevel@tonic-gate 		ph_p = NULL;
4707c478bd9Sstevel@tonic-gate 		*err = error;
4717c478bd9Sstevel@tonic-gate 	} else {
4727c478bd9Sstevel@tonic-gate 		*err = TD_OK;
4737c478bd9Sstevel@tonic-gate 	}
4747c478bd9Sstevel@tonic-gate 
4757c478bd9Sstevel@tonic-gate 	return (ph_p);
4767c478bd9Sstevel@tonic-gate }
4777c478bd9Sstevel@tonic-gate 
4787c478bd9Sstevel@tonic-gate /*
4797c478bd9Sstevel@tonic-gate  * Utility function to grab the readers lock and return the prochandle,
4807c478bd9Sstevel@tonic-gate  * given an agent thread handle.  Performs standard error checking.
4817c478bd9Sstevel@tonic-gate  * Returns non-NULL with the lock held, or NULL with the lock not held.
4827c478bd9Sstevel@tonic-gate  */
4837c478bd9Sstevel@tonic-gate static struct ps_prochandle *
4847c478bd9Sstevel@tonic-gate ph_lock_th(const td_thrhandle_t *th_p, td_err_e *err)
4857c478bd9Sstevel@tonic-gate {
4867c478bd9Sstevel@tonic-gate 	if (th_p == NULL || th_p->th_unique == NULL) {
4877c478bd9Sstevel@tonic-gate 		*err = TD_BADTH;
4887c478bd9Sstevel@tonic-gate 		return (NULL);
4897c478bd9Sstevel@tonic-gate 	}
4907c478bd9Sstevel@tonic-gate 	return (ph_lock_ta(th_p->th_ta_p, err));
4917c478bd9Sstevel@tonic-gate }
4927c478bd9Sstevel@tonic-gate 
4937c478bd9Sstevel@tonic-gate /*
4947c478bd9Sstevel@tonic-gate  * Utility function to grab the readers lock and return the prochandle,
4957c478bd9Sstevel@tonic-gate  * given a synchronization object handle.  Performs standard error checking.
4967c478bd9Sstevel@tonic-gate  * Returns non-NULL with the lock held, or NULL with the lock not held.
4977c478bd9Sstevel@tonic-gate  */
4987c478bd9Sstevel@tonic-gate static struct ps_prochandle *
4997c478bd9Sstevel@tonic-gate ph_lock_sh(const td_synchandle_t *sh_p, td_err_e *err)
5007c478bd9Sstevel@tonic-gate {
5017c478bd9Sstevel@tonic-gate 	if (sh_p == NULL || sh_p->sh_unique == NULL) {
5027c478bd9Sstevel@tonic-gate 		*err = TD_BADSH;
5037c478bd9Sstevel@tonic-gate 		return (NULL);
5047c478bd9Sstevel@tonic-gate 	}
5057c478bd9Sstevel@tonic-gate 	return (ph_lock_ta(sh_p->sh_ta_p, err));
5067c478bd9Sstevel@tonic-gate }
5077c478bd9Sstevel@tonic-gate 
5087c478bd9Sstevel@tonic-gate /*
5097c478bd9Sstevel@tonic-gate  * Unlock the agent process handle obtained from ph_lock_*().
5107c478bd9Sstevel@tonic-gate  */
5117c478bd9Sstevel@tonic-gate static void
5127c478bd9Sstevel@tonic-gate ph_unlock(td_thragent_t *ta_p)
5137c478bd9Sstevel@tonic-gate {
5147c478bd9Sstevel@tonic-gate 	(void) rw_unlock(&ta_p->rwlock);
5157c478bd9Sstevel@tonic-gate }
5167c478bd9Sstevel@tonic-gate 
5177c478bd9Sstevel@tonic-gate /*
5187c478bd9Sstevel@tonic-gate  * De-allocate an agent process handle,
5197c478bd9Sstevel@tonic-gate  * releasing all related resources.
5207c478bd9Sstevel@tonic-gate  *
5217c478bd9Sstevel@tonic-gate  * XXX -- This is hopelessly broken ---
5227c478bd9Sstevel@tonic-gate  * Storage for thread agent is not deallocated.  The prochandle
5237c478bd9Sstevel@tonic-gate  * in the thread agent is set to NULL so that future uses of
5247c478bd9Sstevel@tonic-gate  * the thread agent can be detected and an error value returned.
5257c478bd9Sstevel@tonic-gate  * All functions in the external user interface that make
5267c478bd9Sstevel@tonic-gate  * use of the thread agent are expected
5277c478bd9Sstevel@tonic-gate  * to check for a NULL prochandle in the thread agent.
5287c478bd9Sstevel@tonic-gate  * All such functions are also expected to obtain a
5297c478bd9Sstevel@tonic-gate  * reader lock on the thread agent while it is using it.
5307c478bd9Sstevel@tonic-gate  */
5317c478bd9Sstevel@tonic-gate #pragma weak td_ta_delete = __td_ta_delete
5327c478bd9Sstevel@tonic-gate td_err_e
5337c478bd9Sstevel@tonic-gate __td_ta_delete(td_thragent_t *ta_p)
5347c478bd9Sstevel@tonic-gate {
5357c478bd9Sstevel@tonic-gate 	struct ps_prochandle *ph_p;
5367c478bd9Sstevel@tonic-gate 
5377c478bd9Sstevel@tonic-gate 	/*
5387c478bd9Sstevel@tonic-gate 	 * This is the only place we grab the writer lock.
5397c478bd9Sstevel@tonic-gate 	 * We are going to NULL out the prochandle.
5407c478bd9Sstevel@tonic-gate 	 */
5417c478bd9Sstevel@tonic-gate 	if (ta_p == NULL || rw_wrlock(&ta_p->rwlock) != 0)
5427c478bd9Sstevel@tonic-gate 		return (TD_BADTA);
5437c478bd9Sstevel@tonic-gate 	if ((ph_p = ta_p->ph_p) == NULL) {
5447c478bd9Sstevel@tonic-gate 		(void) rw_unlock(&ta_p->rwlock);
5457c478bd9Sstevel@tonic-gate 		return (TD_BADPH);
5467c478bd9Sstevel@tonic-gate 	}
5477c478bd9Sstevel@tonic-gate 	/*
5487c478bd9Sstevel@tonic-gate 	 * If synch. tracking was disabled when td_ta_new() was called and
5497c478bd9Sstevel@tonic-gate 	 * if td_ta_sync_tracking_enable() was never called, then disable
5507c478bd9Sstevel@tonic-gate 	 * synch. tracking (it was enabled by default in td_ta_new()).
5517c478bd9Sstevel@tonic-gate 	 */
5527c478bd9Sstevel@tonic-gate 	if (ta_p->sync_tracking == 0 &&
5537c478bd9Sstevel@tonic-gate 	    ps_kill != NULL && ps_lrolltoaddr != NULL) {
5547c478bd9Sstevel@tonic-gate 		register_sync_t enable = REGISTER_SYNC_DISABLE;
5557c478bd9Sstevel@tonic-gate 
5567c478bd9Sstevel@tonic-gate 		(void) ps_pdwrite(ph_p, ta_p->tdb_register_sync_addr,
5577c478bd9Sstevel@tonic-gate 		    &enable, sizeof (enable));
5587c478bd9Sstevel@tonic-gate 	}
5597c478bd9Sstevel@tonic-gate 	ta_p->ph_p = NULL;
5607c478bd9Sstevel@tonic-gate 	(void) rw_unlock(&ta_p->rwlock);
5617c478bd9Sstevel@tonic-gate 	return (TD_OK);
5627c478bd9Sstevel@tonic-gate }
5637c478bd9Sstevel@tonic-gate 
5647c478bd9Sstevel@tonic-gate /*
5657c478bd9Sstevel@tonic-gate  * Map an agent process handle to a client prochandle.
5667c478bd9Sstevel@tonic-gate  * Currently unused by dbx.
5677c478bd9Sstevel@tonic-gate  */
5687c478bd9Sstevel@tonic-gate #pragma weak td_ta_get_ph = __td_ta_get_ph
5697c478bd9Sstevel@tonic-gate td_err_e
5707c478bd9Sstevel@tonic-gate __td_ta_get_ph(td_thragent_t *ta_p, struct ps_prochandle **ph_pp)
5717c478bd9Sstevel@tonic-gate {
5727c478bd9Sstevel@tonic-gate 	td_err_e return_val;
5737c478bd9Sstevel@tonic-gate 
5747c478bd9Sstevel@tonic-gate 	if (ph_pp != NULL)	/* protect stupid callers */
5757c478bd9Sstevel@tonic-gate 		*ph_pp = NULL;
5767c478bd9Sstevel@tonic-gate 	if (ph_pp == NULL)
5777c478bd9Sstevel@tonic-gate 		return (TD_ERR);
5787c478bd9Sstevel@tonic-gate 	if ((*ph_pp = ph_lock_ta(ta_p, &return_val)) == NULL)
5797c478bd9Sstevel@tonic-gate 		return (return_val);
5807c478bd9Sstevel@tonic-gate 	ph_unlock(ta_p);
5817c478bd9Sstevel@tonic-gate 	return (TD_OK);
5827c478bd9Sstevel@tonic-gate }
5837c478bd9Sstevel@tonic-gate 
5847c478bd9Sstevel@tonic-gate /*
5857c478bd9Sstevel@tonic-gate  * Set the process's suggested concurrency level.
5867c478bd9Sstevel@tonic-gate  * This is a no-op in a one-level model.
5877c478bd9Sstevel@tonic-gate  * Currently unused by dbx.
5887c478bd9Sstevel@tonic-gate  */
5897c478bd9Sstevel@tonic-gate #pragma weak td_ta_setconcurrency = __td_ta_setconcurrency
5907c478bd9Sstevel@tonic-gate /* ARGSUSED1 */
5917c478bd9Sstevel@tonic-gate td_err_e
5927c478bd9Sstevel@tonic-gate __td_ta_setconcurrency(const td_thragent_t *ta_p, int level)
5937c478bd9Sstevel@tonic-gate {
5947c478bd9Sstevel@tonic-gate 	if (ta_p == NULL)
5957c478bd9Sstevel@tonic-gate 		return (TD_BADTA);
5967c478bd9Sstevel@tonic-gate 	if (ta_p->ph_p == NULL)
5977c478bd9Sstevel@tonic-gate 		return (TD_BADPH);
5987c478bd9Sstevel@tonic-gate 	return (TD_OK);
5997c478bd9Sstevel@tonic-gate }
6007c478bd9Sstevel@tonic-gate 
6017c478bd9Sstevel@tonic-gate /*
6027c478bd9Sstevel@tonic-gate  * Get the number of threads in the process.
6037c478bd9Sstevel@tonic-gate  */
6047c478bd9Sstevel@tonic-gate #pragma weak td_ta_get_nthreads = __td_ta_get_nthreads
6057c478bd9Sstevel@tonic-gate td_err_e
6067c478bd9Sstevel@tonic-gate __td_ta_get_nthreads(td_thragent_t *ta_p, int *nthread_p)
6077c478bd9Sstevel@tonic-gate {
6087c478bd9Sstevel@tonic-gate 	struct ps_prochandle *ph_p;
6097c478bd9Sstevel@tonic-gate 	td_err_e return_val;
6107c478bd9Sstevel@tonic-gate 	int nthreads;
6117c478bd9Sstevel@tonic-gate 	int nzombies;
6127c478bd9Sstevel@tonic-gate 	psaddr_t nthreads_addr;
6137c478bd9Sstevel@tonic-gate 	psaddr_t nzombies_addr;
6147c478bd9Sstevel@tonic-gate 
6157c478bd9Sstevel@tonic-gate 	if (ta_p->model == PR_MODEL_NATIVE) {
6167c478bd9Sstevel@tonic-gate 		nthreads_addr = ta_p->uberdata_addr +
6177c478bd9Sstevel@tonic-gate 		    offsetof(uberdata_t, nthreads);
6187c478bd9Sstevel@tonic-gate 		nzombies_addr = ta_p->uberdata_addr +
6197c478bd9Sstevel@tonic-gate 		    offsetof(uberdata_t, nzombies);
6207c478bd9Sstevel@tonic-gate 	} else {
6217c478bd9Sstevel@tonic-gate #if defined(_LP64) && defined(_SYSCALL32)
6227c478bd9Sstevel@tonic-gate 		nthreads_addr = ta_p->uberdata_addr +
6237c478bd9Sstevel@tonic-gate 		    offsetof(uberdata32_t, nthreads);
6247c478bd9Sstevel@tonic-gate 		nzombies_addr = ta_p->uberdata_addr +
6257c478bd9Sstevel@tonic-gate 		    offsetof(uberdata32_t, nzombies);
6267c478bd9Sstevel@tonic-gate #else
6277c478bd9Sstevel@tonic-gate 		nthreads_addr = 0;
6287c478bd9Sstevel@tonic-gate 		nzombies_addr = 0;
6297c478bd9Sstevel@tonic-gate #endif	/* _SYSCALL32 */
6307c478bd9Sstevel@tonic-gate 	}
6317c478bd9Sstevel@tonic-gate 
6327c478bd9Sstevel@tonic-gate 	if (nthread_p == NULL)
6337c478bd9Sstevel@tonic-gate 		return (TD_ERR);
6347c478bd9Sstevel@tonic-gate 	if ((ph_p = ph_lock_ta(ta_p, &return_val)) == NULL)
6357c478bd9Sstevel@tonic-gate 		return (return_val);
6367c478bd9Sstevel@tonic-gate 	if (ps_pdread(ph_p, nthreads_addr, &nthreads, sizeof (int)) != PS_OK)
6377c478bd9Sstevel@tonic-gate 		return_val = TD_DBERR;
6387c478bd9Sstevel@tonic-gate 	if (ps_pdread(ph_p, nzombies_addr, &nzombies, sizeof (int)) != PS_OK)
6397c478bd9Sstevel@tonic-gate 		return_val = TD_DBERR;
6407c478bd9Sstevel@tonic-gate 	ph_unlock(ta_p);
6417c478bd9Sstevel@tonic-gate 	if (return_val == TD_OK)
6427c478bd9Sstevel@tonic-gate 		*nthread_p = nthreads + nzombies;
6437c478bd9Sstevel@tonic-gate 	return (return_val);
6447c478bd9Sstevel@tonic-gate }
6457c478bd9Sstevel@tonic-gate 
6467c478bd9Sstevel@tonic-gate typedef struct {
6477c478bd9Sstevel@tonic-gate 	thread_t	tid;
6487c478bd9Sstevel@tonic-gate 	int		found;
6497c478bd9Sstevel@tonic-gate 	td_thrhandle_t	th;
6507c478bd9Sstevel@tonic-gate } td_mapper_param_t;
6517c478bd9Sstevel@tonic-gate 
6527c478bd9Sstevel@tonic-gate /*
6537c478bd9Sstevel@tonic-gate  * Check the value in data against the thread id.
6547c478bd9Sstevel@tonic-gate  * If it matches, return 1 to terminate iterations.
6557c478bd9Sstevel@tonic-gate  * This function is used by td_ta_map_id2thr() to map a tid to a thread handle.
6567c478bd9Sstevel@tonic-gate  */
6577c478bd9Sstevel@tonic-gate static int
6587c478bd9Sstevel@tonic-gate td_mapper_id2thr(td_thrhandle_t *th_p, td_mapper_param_t *data)
6597c478bd9Sstevel@tonic-gate {
6607c478bd9Sstevel@tonic-gate 	td_thrinfo_t ti;
6617c478bd9Sstevel@tonic-gate 
6627c478bd9Sstevel@tonic-gate 	if (__td_thr_get_info(th_p, &ti) == TD_OK &&
6637c478bd9Sstevel@tonic-gate 	    data->tid == ti.ti_tid) {
6647c478bd9Sstevel@tonic-gate 		data->found = 1;
6657c478bd9Sstevel@tonic-gate 		data->th = *th_p;
6667c478bd9Sstevel@tonic-gate 		return (1);
6677c478bd9Sstevel@tonic-gate 	}
6687c478bd9Sstevel@tonic-gate 	return (0);
6697c478bd9Sstevel@tonic-gate }
6707c478bd9Sstevel@tonic-gate 
6717c478bd9Sstevel@tonic-gate /*
6727c478bd9Sstevel@tonic-gate  * Given a thread identifier, return the corresponding thread handle.
6737c478bd9Sstevel@tonic-gate  */
6747c478bd9Sstevel@tonic-gate #pragma weak td_ta_map_id2thr = __td_ta_map_id2thr
6757c478bd9Sstevel@tonic-gate td_err_e
6767c478bd9Sstevel@tonic-gate __td_ta_map_id2thr(td_thragent_t *ta_p, thread_t tid,
6777c478bd9Sstevel@tonic-gate 	td_thrhandle_t *th_p)
6787c478bd9Sstevel@tonic-gate {
6797c478bd9Sstevel@tonic-gate 	td_err_e		return_val;
6807c478bd9Sstevel@tonic-gate 	td_mapper_param_t	data;
6817c478bd9Sstevel@tonic-gate 
6827c478bd9Sstevel@tonic-gate 	if (th_p != NULL &&	/* optimize for a single thread */
6837c478bd9Sstevel@tonic-gate 	    ta_p != NULL &&
6847c478bd9Sstevel@tonic-gate 	    ta_p->initialized == 1 &&
6857c478bd9Sstevel@tonic-gate 	    (td_read_hash_size(ta_p) == 1 ||
6867c478bd9Sstevel@tonic-gate 	    td_read_uberdata(ta_p) == TD_OK) &&
6877c478bd9Sstevel@tonic-gate 	    ta_p->initialized == 1 &&
6887c478bd9Sstevel@tonic-gate 	    ta_p->single_lwpid == tid) {
6897c478bd9Sstevel@tonic-gate 		th_p->th_ta_p = ta_p;
6907c478bd9Sstevel@tonic-gate 		if ((th_p->th_unique = ta_p->single_ulwp_addr) == 0)
6917c478bd9Sstevel@tonic-gate 			return (TD_NOTHR);
6927c478bd9Sstevel@tonic-gate 		return (TD_OK);
6937c478bd9Sstevel@tonic-gate 	}
6947c478bd9Sstevel@tonic-gate 
6957c478bd9Sstevel@tonic-gate 	/*
6967c478bd9Sstevel@tonic-gate 	 * LOCKING EXCEPTION - Locking is not required here because
6977c478bd9Sstevel@tonic-gate 	 * the locking and checking will be done in __td_ta_thr_iter.
6987c478bd9Sstevel@tonic-gate 	 */
6997c478bd9Sstevel@tonic-gate 
7007c478bd9Sstevel@tonic-gate 	if (ta_p == NULL)
7017c478bd9Sstevel@tonic-gate 		return (TD_BADTA);
7027c478bd9Sstevel@tonic-gate 	if (th_p == NULL)
7037c478bd9Sstevel@tonic-gate 		return (TD_BADTH);
7047c478bd9Sstevel@tonic-gate 	if (tid == 0)
7057c478bd9Sstevel@tonic-gate 		return (TD_NOTHR);
7067c478bd9Sstevel@tonic-gate 
7077c478bd9Sstevel@tonic-gate 	data.tid = tid;
7087c478bd9Sstevel@tonic-gate 	data.found = 0;
7097c478bd9Sstevel@tonic-gate 	return_val = __td_ta_thr_iter(ta_p,
7107c478bd9Sstevel@tonic-gate 	    (td_thr_iter_f *)td_mapper_id2thr, (void *)&data,
7117c478bd9Sstevel@tonic-gate 	    TD_THR_ANY_STATE, TD_THR_LOWEST_PRIORITY,
7127c478bd9Sstevel@tonic-gate 	    TD_SIGNO_MASK, TD_THR_ANY_USER_FLAGS);
7137c478bd9Sstevel@tonic-gate 	if (return_val == TD_OK) {
7147c478bd9Sstevel@tonic-gate 		if (data.found == 0)
7157c478bd9Sstevel@tonic-gate 			return_val = TD_NOTHR;
7167c478bd9Sstevel@tonic-gate 		else
7177c478bd9Sstevel@tonic-gate 			*th_p = data.th;
7187c478bd9Sstevel@tonic-gate 	}
7197c478bd9Sstevel@tonic-gate 
7207c478bd9Sstevel@tonic-gate 	return (return_val);
7217c478bd9Sstevel@tonic-gate }
7227c478bd9Sstevel@tonic-gate 
7237c478bd9Sstevel@tonic-gate /*
7247c478bd9Sstevel@tonic-gate  * Map the address of a synchronization object to a sync. object handle.
7257c478bd9Sstevel@tonic-gate  */
7267c478bd9Sstevel@tonic-gate #pragma weak td_ta_map_addr2sync = __td_ta_map_addr2sync
7277c478bd9Sstevel@tonic-gate td_err_e
7287c478bd9Sstevel@tonic-gate __td_ta_map_addr2sync(td_thragent_t *ta_p, psaddr_t addr, td_synchandle_t *sh_p)
7297c478bd9Sstevel@tonic-gate {
7307c478bd9Sstevel@tonic-gate 	struct ps_prochandle *ph_p;
7317c478bd9Sstevel@tonic-gate 	td_err_e return_val;
7327c478bd9Sstevel@tonic-gate 	uint16_t sync_magic;
7337c478bd9Sstevel@tonic-gate 
7347c478bd9Sstevel@tonic-gate 	if (sh_p == NULL)
7357c478bd9Sstevel@tonic-gate 		return (TD_BADSH);
7367c478bd9Sstevel@tonic-gate 	if (addr == NULL)
7377c478bd9Sstevel@tonic-gate 		return (TD_ERR);
7387c478bd9Sstevel@tonic-gate 	if ((ph_p = ph_lock_ta(ta_p, &return_val)) == NULL)
7397c478bd9Sstevel@tonic-gate 		return (return_val);
7407c478bd9Sstevel@tonic-gate 	/*
7417c478bd9Sstevel@tonic-gate 	 * Check the magic number of the sync. object to make sure it's valid.
7427c478bd9Sstevel@tonic-gate 	 * The magic number is at the same offset for all sync. objects.
7437c478bd9Sstevel@tonic-gate 	 */
7447c478bd9Sstevel@tonic-gate 	if (ps_pdread(ph_p, (psaddr_t)&((mutex_t *)addr)->mutex_magic,
7457c478bd9Sstevel@tonic-gate 	    &sync_magic, sizeof (sync_magic)) != PS_OK) {
7467c478bd9Sstevel@tonic-gate 		ph_unlock(ta_p);
7477c478bd9Sstevel@tonic-gate 		return (TD_BADSH);
7487c478bd9Sstevel@tonic-gate 	}
7497c478bd9Sstevel@tonic-gate 	ph_unlock(ta_p);
7507c478bd9Sstevel@tonic-gate 	if (sync_magic != MUTEX_MAGIC && sync_magic != COND_MAGIC &&
7517c478bd9Sstevel@tonic-gate 	    sync_magic != SEMA_MAGIC && sync_magic != RWL_MAGIC)
7527c478bd9Sstevel@tonic-gate 		return (TD_BADSH);
7537c478bd9Sstevel@tonic-gate 	/*
7547c478bd9Sstevel@tonic-gate 	 * Just fill in the appropriate fields of the sync. handle.
7557c478bd9Sstevel@tonic-gate 	 */
7567c478bd9Sstevel@tonic-gate 	sh_p->sh_ta_p = (td_thragent_t *)ta_p;
7577c478bd9Sstevel@tonic-gate 	sh_p->sh_unique = addr;
7587c478bd9Sstevel@tonic-gate 	return (TD_OK);
7597c478bd9Sstevel@tonic-gate }
7607c478bd9Sstevel@tonic-gate 
7617c478bd9Sstevel@tonic-gate /*
7627c478bd9Sstevel@tonic-gate  * Iterate over the set of global TSD keys.
7637c478bd9Sstevel@tonic-gate  * The call back function is called with three arguments,
7647c478bd9Sstevel@tonic-gate  * a key, a pointer to the destructor function, and the cbdata pointer.
7657c478bd9Sstevel@tonic-gate  * Currently unused by dbx.
7667c478bd9Sstevel@tonic-gate  */
7677c478bd9Sstevel@tonic-gate #pragma weak td_ta_tsd_iter = __td_ta_tsd_iter
7687c478bd9Sstevel@tonic-gate td_err_e
7697c478bd9Sstevel@tonic-gate __td_ta_tsd_iter(td_thragent_t *ta_p, td_key_iter_f *cb, void *cbdata_p)
7707c478bd9Sstevel@tonic-gate {
7717c478bd9Sstevel@tonic-gate 	struct ps_prochandle *ph_p;
7727c478bd9Sstevel@tonic-gate 	td_err_e	return_val;
7737c478bd9Sstevel@tonic-gate 	int		key;
7747c478bd9Sstevel@tonic-gate 	int		numkeys;
7757c478bd9Sstevel@tonic-gate 	psaddr_t	dest_addr;
7767c478bd9Sstevel@tonic-gate 	psaddr_t	*destructors = NULL;
7777c478bd9Sstevel@tonic-gate 	PFrV		destructor;
7787c478bd9Sstevel@tonic-gate 
7797c478bd9Sstevel@tonic-gate 	if (cb == NULL)
7807c478bd9Sstevel@tonic-gate 		return (TD_ERR);
7817c478bd9Sstevel@tonic-gate 	if ((ph_p = ph_lock_ta(ta_p, &return_val)) == NULL)
7827c478bd9Sstevel@tonic-gate 		return (return_val);
7837c478bd9Sstevel@tonic-gate 	if (ps_pstop(ph_p) != PS_OK) {
7847c478bd9Sstevel@tonic-gate 		ph_unlock(ta_p);
7857c478bd9Sstevel@tonic-gate 		return (TD_DBERR);
7867c478bd9Sstevel@tonic-gate 	}
7877c478bd9Sstevel@tonic-gate 
7887c478bd9Sstevel@tonic-gate 	if (ta_p->model == PR_MODEL_NATIVE) {
7897c478bd9Sstevel@tonic-gate 		tsd_metadata_t tsdm;
7907c478bd9Sstevel@tonic-gate 
7917c478bd9Sstevel@tonic-gate 		if (ps_pdread(ph_p,
7927c478bd9Sstevel@tonic-gate 		    ta_p->uberdata_addr + offsetof(uberdata_t, tsd_metadata),
7937c478bd9Sstevel@tonic-gate 		    &tsdm, sizeof (tsdm)) != PS_OK)
7947c478bd9Sstevel@tonic-gate 			return_val = TD_DBERR;
7957c478bd9Sstevel@tonic-gate 		else {
7967c478bd9Sstevel@tonic-gate 			numkeys = tsdm.tsdm_nused;
7977c478bd9Sstevel@tonic-gate 			dest_addr = (psaddr_t)tsdm.tsdm_destro;
7987c478bd9Sstevel@tonic-gate 			if (numkeys > 0)
7997c478bd9Sstevel@tonic-gate 				destructors =
8007c478bd9Sstevel@tonic-gate 				    malloc(numkeys * sizeof (psaddr_t));
8017c478bd9Sstevel@tonic-gate 		}
8027c478bd9Sstevel@tonic-gate 	} else {
8037c478bd9Sstevel@tonic-gate #if defined(_LP64) && defined(_SYSCALL32)
8047c478bd9Sstevel@tonic-gate 		tsd_metadata32_t tsdm;
8057c478bd9Sstevel@tonic-gate 
8067c478bd9Sstevel@tonic-gate 		if (ps_pdread(ph_p,
8077c478bd9Sstevel@tonic-gate 		    ta_p->uberdata_addr + offsetof(uberdata32_t, tsd_metadata),
8087c478bd9Sstevel@tonic-gate 		    &tsdm, sizeof (tsdm)) != PS_OK)
8097c478bd9Sstevel@tonic-gate 			return_val = TD_DBERR;
8107c478bd9Sstevel@tonic-gate 		else {
8117c478bd9Sstevel@tonic-gate 			numkeys = tsdm.tsdm_nused;
8127c478bd9Sstevel@tonic-gate 			dest_addr = (psaddr_t)tsdm.tsdm_destro;
8137c478bd9Sstevel@tonic-gate 			if (numkeys > 0)
8147c478bd9Sstevel@tonic-gate 				destructors =
8157c478bd9Sstevel@tonic-gate 				    malloc(numkeys * sizeof (caddr32_t));
8167c478bd9Sstevel@tonic-gate 		}
8177c478bd9Sstevel@tonic-gate #else
8187c478bd9Sstevel@tonic-gate 		return_val = TD_DBERR;
8197c478bd9Sstevel@tonic-gate #endif	/* _SYSCALL32 */
8207c478bd9Sstevel@tonic-gate 	}
8217c478bd9Sstevel@tonic-gate 
8227c478bd9Sstevel@tonic-gate 	if (return_val != TD_OK || numkeys <= 0) {
8237c478bd9Sstevel@tonic-gate 		(void) ps_pcontinue(ph_p);
8247c478bd9Sstevel@tonic-gate 		ph_unlock(ta_p);
8257c478bd9Sstevel@tonic-gate 		return (return_val);
8267c478bd9Sstevel@tonic-gate 	}
8277c478bd9Sstevel@tonic-gate 
8287c478bd9Sstevel@tonic-gate 	if (destructors == NULL)
8297c478bd9Sstevel@tonic-gate 		return_val = TD_MALLOC;
8307c478bd9Sstevel@tonic-gate 	else if (ta_p->model == PR_MODEL_NATIVE) {
8317c478bd9Sstevel@tonic-gate 		if (ps_pdread(ph_p, dest_addr,
8327c478bd9Sstevel@tonic-gate 		    destructors, numkeys * sizeof (psaddr_t)) != PS_OK)
8337c478bd9Sstevel@tonic-gate 			return_val = TD_DBERR;
8347c478bd9Sstevel@tonic-gate 		else {
8357c478bd9Sstevel@tonic-gate 			for (key = 1; key < numkeys; key++) {
8367c478bd9Sstevel@tonic-gate 				destructor = (PFrV)destructors[key];
8377c478bd9Sstevel@tonic-gate 				if (destructor != TSD_UNALLOCATED &&
8387c478bd9Sstevel@tonic-gate 				    (*cb)(key, destructor, cbdata_p))
8397c478bd9Sstevel@tonic-gate 					break;
8407c478bd9Sstevel@tonic-gate 			}
8417c478bd9Sstevel@tonic-gate 		}
8427c478bd9Sstevel@tonic-gate #if defined(_LP64) && defined(_SYSCALL32)
8437c478bd9Sstevel@tonic-gate 	} else {
8447c478bd9Sstevel@tonic-gate 		caddr32_t *destructors32 = (caddr32_t *)destructors;
8457c478bd9Sstevel@tonic-gate 		caddr32_t destruct32;
8467c478bd9Sstevel@tonic-gate 
8477c478bd9Sstevel@tonic-gate 		if (ps_pdread(ph_p, dest_addr,
8487c478bd9Sstevel@tonic-gate 		    destructors32, numkeys * sizeof (caddr32_t)) != PS_OK)
8497c478bd9Sstevel@tonic-gate 			return_val = TD_DBERR;
8507c478bd9Sstevel@tonic-gate 		else {
8517c478bd9Sstevel@tonic-gate 			for (key = 1; key < numkeys; key++) {
8527c478bd9Sstevel@tonic-gate 				destruct32 = destructors32[key];
853b30a53d0SRichard Lowe 				if ((destruct32 !=
854b30a53d0SRichard Lowe 				    (caddr32_t)(uintptr_t)TSD_UNALLOCATED) &&
8557c478bd9Sstevel@tonic-gate 				    (*cb)(key, (PFrV)(uintptr_t)destruct32,
8567c478bd9Sstevel@tonic-gate 				    cbdata_p))
8577c478bd9Sstevel@tonic-gate 					break;
8587c478bd9Sstevel@tonic-gate 			}
8597c478bd9Sstevel@tonic-gate 		}
8607c478bd9Sstevel@tonic-gate #endif	/* _SYSCALL32 */
8617c478bd9Sstevel@tonic-gate 	}
8627c478bd9Sstevel@tonic-gate 
8637c478bd9Sstevel@tonic-gate 	if (destructors)
8647c478bd9Sstevel@tonic-gate 		free(destructors);
8657c478bd9Sstevel@tonic-gate 	(void) ps_pcontinue(ph_p);
8667c478bd9Sstevel@tonic-gate 	ph_unlock(ta_p);
8677c478bd9Sstevel@tonic-gate 	return (return_val);
8687c478bd9Sstevel@tonic-gate }
8697c478bd9Sstevel@tonic-gate 
8707c478bd9Sstevel@tonic-gate int
8717c478bd9Sstevel@tonic-gate sigequalset(const sigset_t *s1, const sigset_t *s2)
8727c478bd9Sstevel@tonic-gate {
873d4204c85Sraf 	return (
874d4204c85Sraf 	    s1->__sigbits[0] == s2->__sigbits[0] &&
8757c478bd9Sstevel@tonic-gate 	    s1->__sigbits[1] == s2->__sigbits[1] &&
8767c478bd9Sstevel@tonic-gate 	    s1->__sigbits[2] == s2->__sigbits[2] &&
8777c478bd9Sstevel@tonic-gate 	    s1->__sigbits[3] == s2->__sigbits[3]);
8787c478bd9Sstevel@tonic-gate }
8797c478bd9Sstevel@tonic-gate 
8807c478bd9Sstevel@tonic-gate /*
8817c478bd9Sstevel@tonic-gate  * Description:
8827c478bd9Sstevel@tonic-gate  *   Iterate over all threads. For each thread call
8837c478bd9Sstevel@tonic-gate  * the function pointed to by "cb" with a pointer
8847c478bd9Sstevel@tonic-gate  * to a thread handle, and a pointer to data which
8857c478bd9Sstevel@tonic-gate  * can be NULL. Only call td_thr_iter_f() on threads
8867c478bd9Sstevel@tonic-gate  * which match the properties of state, ti_pri,
8877c478bd9Sstevel@tonic-gate  * ti_sigmask_p, and ti_user_flags.  If cb returns
8887c478bd9Sstevel@tonic-gate  * a non-zero value, terminate iterations.
8897c478bd9Sstevel@tonic-gate  *
8907c478bd9Sstevel@tonic-gate  * Input:
8917c478bd9Sstevel@tonic-gate  *   *ta_p - thread agent
8927c478bd9Sstevel@tonic-gate  *   *cb - call back function defined by user.
8937c478bd9Sstevel@tonic-gate  * td_thr_iter_f() takes a thread handle and
8947c478bd9Sstevel@tonic-gate  * cbdata_p as a parameter.
8957c478bd9Sstevel@tonic-gate  *   cbdata_p - parameter for td_thr_iter_f().
8967c478bd9Sstevel@tonic-gate  *
8977c478bd9Sstevel@tonic-gate  *   state - state of threads of interest.  A value of
8987c478bd9Sstevel@tonic-gate  * TD_THR_ANY_STATE from enum td_thr_state_e
8997c478bd9Sstevel@tonic-gate  * does not restrict iterations by state.
9007c478bd9Sstevel@tonic-gate  *   ti_pri - lower bound of priorities of threads of
9017c478bd9Sstevel@tonic-gate  * interest.  A value of TD_THR_LOWEST_PRIORITY
9027c478bd9Sstevel@tonic-gate  * defined in thread_db.h does not restrict
9037c478bd9Sstevel@tonic-gate  * iterations by priority.  A thread with priority
9047c478bd9Sstevel@tonic-gate  * less than ti_pri will NOT be passed to the callback
9057c478bd9Sstevel@tonic-gate  * function.
9067c478bd9Sstevel@tonic-gate  *   ti_sigmask_p - signal mask of threads of interest.
9077c478bd9Sstevel@tonic-gate  * A value of TD_SIGNO_MASK defined in thread_db.h
9087c478bd9Sstevel@tonic-gate  * does not restrict iterations by signal mask.
9097c478bd9Sstevel@tonic-gate  *   ti_user_flags - user flags of threads of interest.  A
9107c478bd9Sstevel@tonic-gate  * value of TD_THR_ANY_USER_FLAGS defined in thread_db.h
9117c478bd9Sstevel@tonic-gate  * does not restrict iterations by user flags.
9127c478bd9Sstevel@tonic-gate  */
9137c478bd9Sstevel@tonic-gate #pragma weak td_ta_thr_iter = __td_ta_thr_iter
9147c478bd9Sstevel@tonic-gate td_err_e
9157c478bd9Sstevel@tonic-gate __td_ta_thr_iter(td_thragent_t *ta_p, td_thr_iter_f *cb,
9167c478bd9Sstevel@tonic-gate 	void *cbdata_p, td_thr_state_e state, int ti_pri,
9177c478bd9Sstevel@tonic-gate 	sigset_t *ti_sigmask_p, unsigned ti_user_flags)
9187c478bd9Sstevel@tonic-gate {
9197c478bd9Sstevel@tonic-gate 	struct ps_prochandle *ph_p;
9207c478bd9Sstevel@tonic-gate 	psaddr_t	first_lwp_addr;
9217c478bd9Sstevel@tonic-gate 	psaddr_t	first_zombie_addr;
9227c478bd9Sstevel@tonic-gate 	psaddr_t	curr_lwp_addr;
9237c478bd9Sstevel@tonic-gate 	psaddr_t	next_lwp_addr;
9247c478bd9Sstevel@tonic-gate 	td_thrhandle_t	th;
9257c478bd9Sstevel@tonic-gate 	ps_err_e	db_return;
9267c478bd9Sstevel@tonic-gate 	ps_err_e	db_return2;
9277c478bd9Sstevel@tonic-gate 	td_err_e	return_val;
9287c478bd9Sstevel@tonic-gate 
9297c478bd9Sstevel@tonic-gate 	if (cb == NULL)
9307c478bd9Sstevel@tonic-gate 		return (TD_ERR);
9317c478bd9Sstevel@tonic-gate 	/*
9327c478bd9Sstevel@tonic-gate 	 * If state is not within bound, short circuit.
9337c478bd9Sstevel@tonic-gate 	 */
9347c478bd9Sstevel@tonic-gate 	if (state < TD_THR_ANY_STATE || state > TD_THR_STOPPED_ASLEEP)
9357c478bd9Sstevel@tonic-gate 		return (TD_OK);
9367c478bd9Sstevel@tonic-gate 
9377c478bd9Sstevel@tonic-gate 	if ((ph_p = ph_lock_ta(ta_p, &return_val)) == NULL)
9387c478bd9Sstevel@tonic-gate 		return (return_val);
9397c478bd9Sstevel@tonic-gate 	if (ps_pstop(ph_p) != PS_OK) {
9407c478bd9Sstevel@tonic-gate 		ph_unlock(ta_p);
9417c478bd9Sstevel@tonic-gate 		return (TD_DBERR);
9427c478bd9Sstevel@tonic-gate 	}
9437c478bd9Sstevel@tonic-gate 
9447c478bd9Sstevel@tonic-gate 	/*
9457c478bd9Sstevel@tonic-gate 	 * For each ulwp_t in the circular linked lists pointed
9467c478bd9Sstevel@tonic-gate 	 * to by "all_lwps" and "all_zombies":
9477c478bd9Sstevel@tonic-gate 	 * (1) Filter each thread.
9487c478bd9Sstevel@tonic-gate 	 * (2) Create the thread_object for each thread that passes.
9497c478bd9Sstevel@tonic-gate 	 * (3) Call the call back function on each thread.
9507c478bd9Sstevel@tonic-gate 	 */
9517c478bd9Sstevel@tonic-gate 
9527c478bd9Sstevel@tonic-gate 	if (ta_p->model == PR_MODEL_NATIVE) {
9537c478bd9Sstevel@tonic-gate 		db_return = ps_pdread(ph_p,
9547c478bd9Sstevel@tonic-gate 		    ta_p->uberdata_addr + offsetof(uberdata_t, all_lwps),
9557c478bd9Sstevel@tonic-gate 		    &first_lwp_addr, sizeof (first_lwp_addr));
9567c478bd9Sstevel@tonic-gate 		db_return2 = ps_pdread(ph_p,
9577c478bd9Sstevel@tonic-gate 		    ta_p->uberdata_addr + offsetof(uberdata_t, all_zombies),
9587c478bd9Sstevel@tonic-gate 		    &first_zombie_addr, sizeof (first_zombie_addr));
9597c478bd9Sstevel@tonic-gate 	} else {
9607c478bd9Sstevel@tonic-gate #if defined(_LP64) && defined(_SYSCALL32)
9617c478bd9Sstevel@tonic-gate 		caddr32_t addr32;
9627c478bd9Sstevel@tonic-gate 
9637c478bd9Sstevel@tonic-gate 		db_return = ps_pdread(ph_p,
9647c478bd9Sstevel@tonic-gate 		    ta_p->uberdata_addr + offsetof(uberdata32_t, all_lwps),
9657c478bd9Sstevel@tonic-gate 		    &addr32, sizeof (addr32));
9667c478bd9Sstevel@tonic-gate 		first_lwp_addr = addr32;
9677c478bd9Sstevel@tonic-gate 		db_return2 = ps_pdread(ph_p,
9687c478bd9Sstevel@tonic-gate 		    ta_p->uberdata_addr + offsetof(uberdata32_t, all_zombies),
9697c478bd9Sstevel@tonic-gate 		    &addr32, sizeof (addr32));
9707c478bd9Sstevel@tonic-gate 		first_zombie_addr = addr32;
9717c478bd9Sstevel@tonic-gate #else	/* _SYSCALL32 */
9727c478bd9Sstevel@tonic-gate 		db_return = PS_ERR;
9737c478bd9Sstevel@tonic-gate 		db_return2 = PS_ERR;
9747c478bd9Sstevel@tonic-gate #endif	/* _SYSCALL32 */
9757c478bd9Sstevel@tonic-gate 	}
9767c478bd9Sstevel@tonic-gate 	if (db_return == PS_OK)
9777c478bd9Sstevel@tonic-gate 		db_return = db_return2;
9787c478bd9Sstevel@tonic-gate 
9797c478bd9Sstevel@tonic-gate 	/*
9807c478bd9Sstevel@tonic-gate 	 * If first_lwp_addr and first_zombie_addr are both NULL,
9817c478bd9Sstevel@tonic-gate 	 * libc must not yet be initialized or all threads have
9827c478bd9Sstevel@tonic-gate 	 * exited.  Return TD_NOTHR and all will be well.
9837c478bd9Sstevel@tonic-gate 	 */
9847c478bd9Sstevel@tonic-gate 	if (db_return == PS_OK &&
9857c478bd9Sstevel@tonic-gate 	    first_lwp_addr == NULL && first_zombie_addr == NULL) {
9867c478bd9Sstevel@tonic-gate 		(void) ps_pcontinue(ph_p);
9877c478bd9Sstevel@tonic-gate 		ph_unlock(ta_p);
9887c478bd9Sstevel@tonic-gate 		return (TD_NOTHR);
9897c478bd9Sstevel@tonic-gate 	}
9907c478bd9Sstevel@tonic-gate 	if (db_return != PS_OK) {
9917c478bd9Sstevel@tonic-gate 		(void) ps_pcontinue(ph_p);
9927c478bd9Sstevel@tonic-gate 		ph_unlock(ta_p);
9937c478bd9Sstevel@tonic-gate 		return (TD_DBERR);
9947c478bd9Sstevel@tonic-gate 	}
9957c478bd9Sstevel@tonic-gate 
9967c478bd9Sstevel@tonic-gate 	/*
9977c478bd9Sstevel@tonic-gate 	 * Run down the lists of all living and dead lwps.
9987c478bd9Sstevel@tonic-gate 	 */
9997c478bd9Sstevel@tonic-gate 	if (first_lwp_addr == NULL)
10007c478bd9Sstevel@tonic-gate 		first_lwp_addr = first_zombie_addr;
10017c478bd9Sstevel@tonic-gate 	curr_lwp_addr = first_lwp_addr;
10027c478bd9Sstevel@tonic-gate 	for (;;) {
10037c478bd9Sstevel@tonic-gate 		td_thr_state_e ts_state;
10047c478bd9Sstevel@tonic-gate 		int userpri;
10057c478bd9Sstevel@tonic-gate 		unsigned userflags;
10067c478bd9Sstevel@tonic-gate 		sigset_t mask;
10077c478bd9Sstevel@tonic-gate 
10087c478bd9Sstevel@tonic-gate 		/*
10097c478bd9Sstevel@tonic-gate 		 * Read the ulwp struct.
10107c478bd9Sstevel@tonic-gate 		 */
10117c478bd9Sstevel@tonic-gate 		if (ta_p->model == PR_MODEL_NATIVE) {
10127c478bd9Sstevel@tonic-gate 			ulwp_t ulwp;
10137c478bd9Sstevel@tonic-gate 
10147c478bd9Sstevel@tonic-gate 			if (ps_pdread(ph_p, curr_lwp_addr,
10157c478bd9Sstevel@tonic-gate 			    &ulwp, sizeof (ulwp)) != PS_OK &&
10167c478bd9Sstevel@tonic-gate 			    ((void) memset(&ulwp, 0, sizeof (ulwp)),
10177c478bd9Sstevel@tonic-gate 			    ps_pdread(ph_p, curr_lwp_addr,
10187c478bd9Sstevel@tonic-gate 			    &ulwp, REPLACEMENT_SIZE)) != PS_OK) {
10197c478bd9Sstevel@tonic-gate 				return_val = TD_DBERR;
10207c478bd9Sstevel@tonic-gate 				break;
10217c478bd9Sstevel@tonic-gate 			}
10227c478bd9Sstevel@tonic-gate 			next_lwp_addr = (psaddr_t)ulwp.ul_forw;
10237c478bd9Sstevel@tonic-gate 
10247c478bd9Sstevel@tonic-gate 			ts_state = ulwp.ul_dead? TD_THR_ZOMBIE :
10257c478bd9Sstevel@tonic-gate 			    ulwp.ul_stop? TD_THR_STOPPED :
10267c478bd9Sstevel@tonic-gate 			    ulwp.ul_wchan? TD_THR_SLEEP :
10277c478bd9Sstevel@tonic-gate 			    TD_THR_ACTIVE;
10287c478bd9Sstevel@tonic-gate 			userpri = ulwp.ul_pri;
10297c478bd9Sstevel@tonic-gate 			userflags = ulwp.ul_usropts;
10307c478bd9Sstevel@tonic-gate 			if (ulwp.ul_dead)
10317c478bd9Sstevel@tonic-gate 				(void) sigemptyset(&mask);
10327c478bd9Sstevel@tonic-gate 			else
10337c478bd9Sstevel@tonic-gate 				mask = *(sigset_t *)&ulwp.ul_sigmask;
10347c478bd9Sstevel@tonic-gate 		} else {
10357c478bd9Sstevel@tonic-gate #if defined(_LP64) && defined(_SYSCALL32)
10367c478bd9Sstevel@tonic-gate 			ulwp32_t ulwp;
10377c478bd9Sstevel@tonic-gate 
10387c478bd9Sstevel@tonic-gate 			if (ps_pdread(ph_p, curr_lwp_addr,
10397c478bd9Sstevel@tonic-gate 			    &ulwp, sizeof (ulwp)) != PS_OK &&
10407c478bd9Sstevel@tonic-gate 			    ((void) memset(&ulwp, 0, sizeof (ulwp)),
10417c478bd9Sstevel@tonic-gate 			    ps_pdread(ph_p, curr_lwp_addr,
10427c478bd9Sstevel@tonic-gate 			    &ulwp, REPLACEMENT_SIZE32)) != PS_OK) {
10437c478bd9Sstevel@tonic-gate 				return_val = TD_DBERR;
10447c478bd9Sstevel@tonic-gate 				break;
10457c478bd9Sstevel@tonic-gate 			}
10467c478bd9Sstevel@tonic-gate 			next_lwp_addr = (psaddr_t)ulwp.ul_forw;
10477c478bd9Sstevel@tonic-gate 
10487c478bd9Sstevel@tonic-gate 			ts_state = ulwp.ul_dead? TD_THR_ZOMBIE :
10497c478bd9Sstevel@tonic-gate 			    ulwp.ul_stop? TD_THR_STOPPED :
10507c478bd9Sstevel@tonic-gate 			    ulwp.ul_wchan? TD_THR_SLEEP :
10517c478bd9Sstevel@tonic-gate 			    TD_THR_ACTIVE;
10527c478bd9Sstevel@tonic-gate 			userpri = ulwp.ul_pri;
10537c478bd9Sstevel@tonic-gate 			userflags = ulwp.ul_usropts;
10547c478bd9Sstevel@tonic-gate 			if (ulwp.ul_dead)
10557c478bd9Sstevel@tonic-gate 				(void) sigemptyset(&mask);
10567c478bd9Sstevel@tonic-gate 			else
10577c478bd9Sstevel@tonic-gate 				mask = *(sigset_t *)&ulwp.ul_sigmask;
10587c478bd9Sstevel@tonic-gate #else	/* _SYSCALL32 */
10597c478bd9Sstevel@tonic-gate 			return_val = TD_ERR;
10607c478bd9Sstevel@tonic-gate 			break;
10617c478bd9Sstevel@tonic-gate #endif	/* _SYSCALL32 */
10627c478bd9Sstevel@tonic-gate 		}
10637c478bd9Sstevel@tonic-gate 
10647c478bd9Sstevel@tonic-gate 		/*
10657c478bd9Sstevel@tonic-gate 		 * Filter on state, priority, sigmask, and user flags.
10667c478bd9Sstevel@tonic-gate 		 */
10677c478bd9Sstevel@tonic-gate 
10687c478bd9Sstevel@tonic-gate 		if ((state != ts_state) &&
10697c478bd9Sstevel@tonic-gate 		    (state != TD_THR_ANY_STATE))
10707c478bd9Sstevel@tonic-gate 			goto advance;
10717c478bd9Sstevel@tonic-gate 
10727c478bd9Sstevel@tonic-gate 		if (ti_pri > userpri)
10737c478bd9Sstevel@tonic-gate 			goto advance;
10747c478bd9Sstevel@tonic-gate 
10757c478bd9Sstevel@tonic-gate 		if (ti_sigmask_p != TD_SIGNO_MASK &&
10767c478bd9Sstevel@tonic-gate 		    !sigequalset(ti_sigmask_p, &mask))
10777c478bd9Sstevel@tonic-gate 			goto advance;
10787c478bd9Sstevel@tonic-gate 
10797c478bd9Sstevel@tonic-gate 		if (ti_user_flags != userflags &&
10807c478bd9Sstevel@tonic-gate 		    ti_user_flags != (unsigned)TD_THR_ANY_USER_FLAGS)
10817c478bd9Sstevel@tonic-gate 			goto advance;
10827c478bd9Sstevel@tonic-gate 
10837c478bd9Sstevel@tonic-gate 		/*
10847c478bd9Sstevel@tonic-gate 		 * Call back - break if the return
10857c478bd9Sstevel@tonic-gate 		 * from the call back is non-zero.
10867c478bd9Sstevel@tonic-gate 		 */
10877c478bd9Sstevel@tonic-gate 		th.th_ta_p = (td_thragent_t *)ta_p;
10887c478bd9Sstevel@tonic-gate 		th.th_unique = curr_lwp_addr;
10897c478bd9Sstevel@tonic-gate 		if ((*cb)(&th, cbdata_p))
10907c478bd9Sstevel@tonic-gate 			break;
10917c478bd9Sstevel@tonic-gate 
10927c478bd9Sstevel@tonic-gate advance:
10937c478bd9Sstevel@tonic-gate 		if ((curr_lwp_addr = next_lwp_addr) == first_lwp_addr) {
10947c478bd9Sstevel@tonic-gate 			/*
10957c478bd9Sstevel@tonic-gate 			 * Switch to the zombie list, unless it is NULL
10967c478bd9Sstevel@tonic-gate 			 * or we have already been doing the zombie list,
10977c478bd9Sstevel@tonic-gate 			 * in which case terminate the loop.
10987c478bd9Sstevel@tonic-gate 			 */
10997c478bd9Sstevel@tonic-gate 			if (first_zombie_addr == NULL ||
11007c478bd9Sstevel@tonic-gate 			    first_lwp_addr == first_zombie_addr)
11017c478bd9Sstevel@tonic-gate 				break;
11027c478bd9Sstevel@tonic-gate 			curr_lwp_addr = first_lwp_addr = first_zombie_addr;
11037c478bd9Sstevel@tonic-gate 		}
11047c478bd9Sstevel@tonic-gate 	}
11057c478bd9Sstevel@tonic-gate 
11067c478bd9Sstevel@tonic-gate 	(void) ps_pcontinue(ph_p);
11077c478bd9Sstevel@tonic-gate 	ph_unlock(ta_p);
11087c478bd9Sstevel@tonic-gate 	return (return_val);
11097c478bd9Sstevel@tonic-gate }
11107c478bd9Sstevel@tonic-gate 
11117c478bd9Sstevel@tonic-gate /*
11127c478bd9Sstevel@tonic-gate  * Enable or disable process synchronization object tracking.
11137c478bd9Sstevel@tonic-gate  * Currently unused by dbx.
11147c478bd9Sstevel@tonic-gate  */
11157c478bd9Sstevel@tonic-gate #pragma weak td_ta_sync_tracking_enable = __td_ta_sync_tracking_enable
11167c478bd9Sstevel@tonic-gate td_err_e
11177c478bd9Sstevel@tonic-gate __td_ta_sync_tracking_enable(td_thragent_t *ta_p, int onoff)
11187c478bd9Sstevel@tonic-gate {
11197c478bd9Sstevel@tonic-gate 	struct ps_prochandle *ph_p;
11207c478bd9Sstevel@tonic-gate 	td_err_e return_val;
11217c478bd9Sstevel@tonic-gate 	register_sync_t enable;
11227c478bd9Sstevel@tonic-gate 
11237c478bd9Sstevel@tonic-gate 	if ((ph_p = ph_lock_ta(ta_p, &return_val)) == NULL)
11247c478bd9Sstevel@tonic-gate 		return (return_val);
11257c478bd9Sstevel@tonic-gate 	/*
11267c478bd9Sstevel@tonic-gate 	 * Values of tdb_register_sync in the victim process:
11277c478bd9Sstevel@tonic-gate 	 *	REGISTER_SYNC_ENABLE	enables registration of synch objects
11287c478bd9Sstevel@tonic-gate 	 *	REGISTER_SYNC_DISABLE	disables registration of synch objects
11297c478bd9Sstevel@tonic-gate 	 * These cause the table to be cleared and tdb_register_sync set to:
11307c478bd9Sstevel@tonic-gate 	 *	REGISTER_SYNC_ON	registration in effect
11317c478bd9Sstevel@tonic-gate 	 *	REGISTER_SYNC_OFF	registration not in effect
11327c478bd9Sstevel@tonic-gate 	 */
11337c478bd9Sstevel@tonic-gate 	enable = onoff? REGISTER_SYNC_ENABLE : REGISTER_SYNC_DISABLE;
11347c478bd9Sstevel@tonic-gate 	if (ps_pdwrite(ph_p, ta_p->tdb_register_sync_addr,
11357c478bd9Sstevel@tonic-gate 	    &enable, sizeof (enable)) != PS_OK)
11367c478bd9Sstevel@tonic-gate 		return_val = TD_DBERR;
11377c478bd9Sstevel@tonic-gate 	/*
11387c478bd9Sstevel@tonic-gate 	 * Remember that this interface was called (see td_ta_delete()).
11397c478bd9Sstevel@tonic-gate 	 */
11407c478bd9Sstevel@tonic-gate 	ta_p->sync_tracking = 1;
11417c478bd9Sstevel@tonic-gate 	ph_unlock(ta_p);
11427c478bd9Sstevel@tonic-gate 	return (return_val);
11437c478bd9Sstevel@tonic-gate }
11447c478bd9Sstevel@tonic-gate 
11457c478bd9Sstevel@tonic-gate /*
11467c478bd9Sstevel@tonic-gate  * Iterate over all known synchronization variables.
11477c478bd9Sstevel@tonic-gate  * It is very possible that the list generated is incomplete,
11487c478bd9Sstevel@tonic-gate  * because the iterator can only find synchronization variables
11497c478bd9Sstevel@tonic-gate  * that have been registered by the process since synchronization
11507c478bd9Sstevel@tonic-gate  * object registration was enabled.
11517c478bd9Sstevel@tonic-gate  * The call back function cb is called for each synchronization
11527c478bd9Sstevel@tonic-gate  * variable with two arguments: a pointer to the synchronization
11537c478bd9Sstevel@tonic-gate  * handle and the passed-in argument cbdata.
11547c478bd9Sstevel@tonic-gate  * If cb returns a non-zero value, iterations are terminated.
11557c478bd9Sstevel@tonic-gate  */
11567c478bd9Sstevel@tonic-gate #pragma weak td_ta_sync_iter = __td_ta_sync_iter
11577c478bd9Sstevel@tonic-gate td_err_e
11587c478bd9Sstevel@tonic-gate __td_ta_sync_iter(td_thragent_t *ta_p, td_sync_iter_f *cb, void *cbdata)
11597c478bd9Sstevel@tonic-gate {
11607c478bd9Sstevel@tonic-gate 	struct ps_prochandle *ph_p;
11617c478bd9Sstevel@tonic-gate 	td_err_e	return_val;
11627c478bd9Sstevel@tonic-gate 	int		i;
11637c478bd9Sstevel@tonic-gate 	register_sync_t	enable;
11647c478bd9Sstevel@tonic-gate 	psaddr_t	next_desc;
11657c478bd9Sstevel@tonic-gate 	tdb_sync_stats_t sync_stats;
11667c478bd9Sstevel@tonic-gate 	td_synchandle_t	synchandle;
11677c478bd9Sstevel@tonic-gate 	psaddr_t	psaddr;
11687c478bd9Sstevel@tonic-gate 	void		*vaddr;
11697c478bd9Sstevel@tonic-gate 	uint64_t	*sync_addr_hash = NULL;
11707c478bd9Sstevel@tonic-gate 
11717c478bd9Sstevel@tonic-gate 	if (cb == NULL)
11727c478bd9Sstevel@tonic-gate 		return (TD_ERR);
11737c478bd9Sstevel@tonic-gate 	if ((ph_p = ph_lock_ta(ta_p, &return_val)) == NULL)
11747c478bd9Sstevel@tonic-gate 		return (return_val);
11757c478bd9Sstevel@tonic-gate 	if (ps_pstop(ph_p) != PS_OK) {
11767c478bd9Sstevel@tonic-gate 		ph_unlock(ta_p);
11777c478bd9Sstevel@tonic-gate 		return (TD_DBERR);
11787c478bd9Sstevel@tonic-gate 	}
11797c478bd9Sstevel@tonic-gate 	if (ps_pdread(ph_p, ta_p->tdb_register_sync_addr,
11807c478bd9Sstevel@tonic-gate 	    &enable, sizeof (enable)) != PS_OK) {
11817c478bd9Sstevel@tonic-gate 		return_val = TD_DBERR;
11827c478bd9Sstevel@tonic-gate 		goto out;
11837c478bd9Sstevel@tonic-gate 	}
11847c478bd9Sstevel@tonic-gate 	if (enable != REGISTER_SYNC_ON)
11857c478bd9Sstevel@tonic-gate 		goto out;
11867c478bd9Sstevel@tonic-gate 
11877c478bd9Sstevel@tonic-gate 	/*
11887c478bd9Sstevel@tonic-gate 	 * First read the hash table.
11897c478bd9Sstevel@tonic-gate 	 * The hash table is large; allocate with mmap().
11907c478bd9Sstevel@tonic-gate 	 */
11917c478bd9Sstevel@tonic-gate 	if ((vaddr = mmap(NULL, TDB_HASH_SIZE * sizeof (uint64_t),
11927c478bd9Sstevel@tonic-gate 	    PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANON, -1, (off_t)0))
11937c478bd9Sstevel@tonic-gate 	    == MAP_FAILED) {
11947c478bd9Sstevel@tonic-gate 		return_val = TD_MALLOC;
11957c478bd9Sstevel@tonic-gate 		goto out;
11967c478bd9Sstevel@tonic-gate 	}
11977c478bd9Sstevel@tonic-gate 	sync_addr_hash = vaddr;
11987c478bd9Sstevel@tonic-gate 
11997c478bd9Sstevel@tonic-gate 	if (ta_p->model == PR_MODEL_NATIVE) {
12007c478bd9Sstevel@tonic-gate 		if (ps_pdread(ph_p, ta_p->uberdata_addr +
12017c478bd9Sstevel@tonic-gate 		    offsetof(uberdata_t, tdb.tdb_sync_addr_hash),
12027c478bd9Sstevel@tonic-gate 		    &psaddr, sizeof (&psaddr)) != PS_OK) {
12037c478bd9Sstevel@tonic-gate 			return_val = TD_DBERR;
12047c478bd9Sstevel@tonic-gate 			goto out;
12057c478bd9Sstevel@tonic-gate 		}
12067c478bd9Sstevel@tonic-gate 	} else {
12077c478bd9Sstevel@tonic-gate #ifdef  _SYSCALL32
12087c478bd9Sstevel@tonic-gate 		caddr32_t addr;
12097c478bd9Sstevel@tonic-gate 
12107c478bd9Sstevel@tonic-gate 		if (ps_pdread(ph_p, ta_p->uberdata_addr +
12117c478bd9Sstevel@tonic-gate 		    offsetof(uberdata32_t, tdb.tdb_sync_addr_hash),
12127c478bd9Sstevel@tonic-gate 		    &addr, sizeof (addr)) != PS_OK) {
12137c478bd9Sstevel@tonic-gate 			return_val = TD_DBERR;
12147c478bd9Sstevel@tonic-gate 			goto out;
12157c478bd9Sstevel@tonic-gate 		}
12167c478bd9Sstevel@tonic-gate 		psaddr = addr;
12177c478bd9Sstevel@tonic-gate #else
12187c478bd9Sstevel@tonic-gate 		return_val = TD_ERR;
12197c478bd9Sstevel@tonic-gate 		goto out;
12207c478bd9Sstevel@tonic-gate #endif /* _SYSCALL32 */
12217c478bd9Sstevel@tonic-gate 	}
12227c478bd9Sstevel@tonic-gate 
12237c478bd9Sstevel@tonic-gate 	if (psaddr == NULL)
12247c478bd9Sstevel@tonic-gate 		goto out;
12257c478bd9Sstevel@tonic-gate 	if (ps_pdread(ph_p, psaddr, sync_addr_hash,
12267c478bd9Sstevel@tonic-gate 	    TDB_HASH_SIZE * sizeof (uint64_t)) != PS_OK) {
12277c478bd9Sstevel@tonic-gate 		return_val = TD_DBERR;
12287c478bd9Sstevel@tonic-gate 		goto out;
12297c478bd9Sstevel@tonic-gate 	}
12307c478bd9Sstevel@tonic-gate 
12317c478bd9Sstevel@tonic-gate 	/*
12327c478bd9Sstevel@tonic-gate 	 * Now scan the hash table.
12337c478bd9Sstevel@tonic-gate 	 */
12347c478bd9Sstevel@tonic-gate 	for (i = 0; i < TDB_HASH_SIZE; i++) {
12357c478bd9Sstevel@tonic-gate 		for (next_desc = (psaddr_t)sync_addr_hash[i];
12367c478bd9Sstevel@tonic-gate 		    next_desc != NULL;
12377c478bd9Sstevel@tonic-gate 		    next_desc = (psaddr_t)sync_stats.next) {
12387c478bd9Sstevel@tonic-gate 			if (ps_pdread(ph_p, next_desc,
12397c478bd9Sstevel@tonic-gate 			    &sync_stats, sizeof (sync_stats)) != PS_OK) {
12407c478bd9Sstevel@tonic-gate 				return_val = TD_DBERR;
12417c478bd9Sstevel@tonic-gate 				goto out;
12427c478bd9Sstevel@tonic-gate 			}
12437c478bd9Sstevel@tonic-gate 			if (sync_stats.un.type == TDB_NONE) {
12447c478bd9Sstevel@tonic-gate 				/* not registered since registration enabled */
12457c478bd9Sstevel@tonic-gate 				continue;
12467c478bd9Sstevel@tonic-gate 			}
12477c478bd9Sstevel@tonic-gate 			synchandle.sh_ta_p = ta_p;
12487c478bd9Sstevel@tonic-gate 			synchandle.sh_unique = (psaddr_t)sync_stats.sync_addr;
12497c478bd9Sstevel@tonic-gate 			if ((*cb)(&synchandle, cbdata) != 0)
12507c478bd9Sstevel@tonic-gate 				goto out;
12517c478bd9Sstevel@tonic-gate 		}
12527c478bd9Sstevel@tonic-gate 	}
12537c478bd9Sstevel@tonic-gate 
12547c478bd9Sstevel@tonic-gate out:
12557c478bd9Sstevel@tonic-gate 	if (sync_addr_hash != NULL)
12567c478bd9Sstevel@tonic-gate 		(void) munmap((void *)sync_addr_hash,
12577c478bd9Sstevel@tonic-gate 		    TDB_HASH_SIZE * sizeof (uint64_t));
12587c478bd9Sstevel@tonic-gate 	(void) ps_pcontinue(ph_p);
12597c478bd9Sstevel@tonic-gate 	ph_unlock(ta_p);
12607c478bd9Sstevel@tonic-gate 	return (return_val);
12617c478bd9Sstevel@tonic-gate }
12627c478bd9Sstevel@tonic-gate 
12637c478bd9Sstevel@tonic-gate /*
12647c478bd9Sstevel@tonic-gate  * Enable process statistics collection.
12657c478bd9Sstevel@tonic-gate  */
12667c478bd9Sstevel@tonic-gate #pragma weak td_ta_enable_stats = __td_ta_enable_stats
12677c478bd9Sstevel@tonic-gate /* ARGSUSED */
12687c478bd9Sstevel@tonic-gate td_err_e
12697c478bd9Sstevel@tonic-gate __td_ta_enable_stats(const td_thragent_t *ta_p, int onoff)
12707c478bd9Sstevel@tonic-gate {
12717c478bd9Sstevel@tonic-gate 	return (TD_NOCAPAB);
12727c478bd9Sstevel@tonic-gate }
12737c478bd9Sstevel@tonic-gate 
12747c478bd9Sstevel@tonic-gate /*
12757c478bd9Sstevel@tonic-gate  * Reset process statistics.
12767c478bd9Sstevel@tonic-gate  */
12777c478bd9Sstevel@tonic-gate #pragma weak td_ta_reset_stats = __td_ta_reset_stats
12787c478bd9Sstevel@tonic-gate /* ARGSUSED */
12797c478bd9Sstevel@tonic-gate td_err_e
12807c478bd9Sstevel@tonic-gate __td_ta_reset_stats(const td_thragent_t *ta_p)
12817c478bd9Sstevel@tonic-gate {
12827c478bd9Sstevel@tonic-gate 	return (TD_NOCAPAB);
12837c478bd9Sstevel@tonic-gate }
12847c478bd9Sstevel@tonic-gate 
12857c478bd9Sstevel@tonic-gate /*
12867c478bd9Sstevel@tonic-gate  * Read process statistics.
12877c478bd9Sstevel@tonic-gate  */
12887c478bd9Sstevel@tonic-gate #pragma weak td_ta_get_stats = __td_ta_get_stats
12897c478bd9Sstevel@tonic-gate /* ARGSUSED */
12907c478bd9Sstevel@tonic-gate td_err_e
12917c478bd9Sstevel@tonic-gate __td_ta_get_stats(const td_thragent_t *ta_p, td_ta_stats_t *tstats)
12927c478bd9Sstevel@tonic-gate {
12937c478bd9Sstevel@tonic-gate 	return (TD_NOCAPAB);
12947c478bd9Sstevel@tonic-gate }
12957c478bd9Sstevel@tonic-gate 
12967c478bd9Sstevel@tonic-gate /*
12977c478bd9Sstevel@tonic-gate  * Transfer information from lwp struct to thread information struct.
12987c478bd9Sstevel@tonic-gate  * XXX -- lots of this needs cleaning up.
12997c478bd9Sstevel@tonic-gate  */
13007c478bd9Sstevel@tonic-gate static void
13017c478bd9Sstevel@tonic-gate td_thr2to(td_thragent_t *ta_p, psaddr_t ts_addr,
13027c478bd9Sstevel@tonic-gate 	ulwp_t *ulwp, td_thrinfo_t *ti_p)
13037c478bd9Sstevel@tonic-gate {
13047c478bd9Sstevel@tonic-gate 	lwpid_t lwpid;
13057c478bd9Sstevel@tonic-gate 
13067c478bd9Sstevel@tonic-gate 	if ((lwpid = ulwp->ul_lwpid) == 0)
13077c478bd9Sstevel@tonic-gate 		lwpid = 1;
13087c478bd9Sstevel@tonic-gate 	(void) memset(ti_p, 0, sizeof (*ti_p));
13097c478bd9Sstevel@tonic-gate 	ti_p->ti_ta_p = ta_p;
13107c478bd9Sstevel@tonic-gate 	ti_p->ti_user_flags = ulwp->ul_usropts;
13117c478bd9Sstevel@tonic-gate 	ti_p->ti_tid = lwpid;
13127c478bd9Sstevel@tonic-gate 	ti_p->ti_exitval = ulwp->ul_rval;
13137c478bd9Sstevel@tonic-gate 	ti_p->ti_startfunc = (psaddr_t)ulwp->ul_startpc;
13147c478bd9Sstevel@tonic-gate 	if (!ulwp->ul_dead) {
13157c478bd9Sstevel@tonic-gate 		/*
13167c478bd9Sstevel@tonic-gate 		 * The bloody fools got this backwards!
13177c478bd9Sstevel@tonic-gate 		 */
13187c478bd9Sstevel@tonic-gate 		ti_p->ti_stkbase = (psaddr_t)ulwp->ul_stktop;
13197c478bd9Sstevel@tonic-gate 		ti_p->ti_stksize = ulwp->ul_stksiz;
13207c478bd9Sstevel@tonic-gate 	}
13217c478bd9Sstevel@tonic-gate 	ti_p->ti_ro_area = ts_addr;
13227c478bd9Sstevel@tonic-gate 	ti_p->ti_ro_size = ulwp->ul_replace?
13237c478bd9Sstevel@tonic-gate 	    REPLACEMENT_SIZE : sizeof (ulwp_t);
13247c478bd9Sstevel@tonic-gate 	ti_p->ti_state = ulwp->ul_dead? TD_THR_ZOMBIE :
13257c478bd9Sstevel@tonic-gate 	    ulwp->ul_stop? TD_THR_STOPPED :
13267c478bd9Sstevel@tonic-gate 	    ulwp->ul_wchan? TD_THR_SLEEP :
13277c478bd9Sstevel@tonic-gate 	    TD_THR_ACTIVE;
13287c478bd9Sstevel@tonic-gate 	ti_p->ti_db_suspended = 0;
13297c478bd9Sstevel@tonic-gate 	ti_p->ti_type = TD_THR_USER;
13307c478bd9Sstevel@tonic-gate 	ti_p->ti_sp = ulwp->ul_sp;
13317c478bd9Sstevel@tonic-gate 	ti_p->ti_flags = 0;
13327c478bd9Sstevel@tonic-gate 	ti_p->ti_pri = ulwp->ul_pri;
13337c478bd9Sstevel@tonic-gate 	ti_p->ti_lid = lwpid;
13347c478bd9Sstevel@tonic-gate 	if (!ulwp->ul_dead)
13357c478bd9Sstevel@tonic-gate 		ti_p->ti_sigmask = ulwp->ul_sigmask;
13367c478bd9Sstevel@tonic-gate 	ti_p->ti_traceme = 0;
13377c478bd9Sstevel@tonic-gate 	ti_p->ti_preemptflag = 0;
13387c478bd9Sstevel@tonic-gate 	ti_p->ti_pirecflag = 0;
13397c478bd9Sstevel@tonic-gate 	(void) sigemptyset(&ti_p->ti_pending);
13407c478bd9Sstevel@tonic-gate 	ti_p->ti_events = ulwp->ul_td_evbuf.eventmask;
13417c478bd9Sstevel@tonic-gate }
13427c478bd9Sstevel@tonic-gate 
13437c478bd9Sstevel@tonic-gate #if defined(_LP64) && defined(_SYSCALL32)
13447c478bd9Sstevel@tonic-gate static void
13457c478bd9Sstevel@tonic-gate td_thr2to32(td_thragent_t *ta_p, psaddr_t ts_addr,
13467c478bd9Sstevel@tonic-gate 	ulwp32_t *ulwp, td_thrinfo_t *ti_p)
13477c478bd9Sstevel@tonic-gate {
13487c478bd9Sstevel@tonic-gate 	lwpid_t lwpid;
13497c478bd9Sstevel@tonic-gate 
13507c478bd9Sstevel@tonic-gate 	if ((lwpid = ulwp->ul_lwpid) == 0)
13517c478bd9Sstevel@tonic-gate 		lwpid = 1;
13527c478bd9Sstevel@tonic-gate 	(void) memset(ti_p, 0, sizeof (*ti_p));
13537c478bd9Sstevel@tonic-gate 	ti_p->ti_ta_p = ta_p;
13547c478bd9Sstevel@tonic-gate 	ti_p->ti_user_flags = ulwp->ul_usropts;
13557c478bd9Sstevel@tonic-gate 	ti_p->ti_tid = lwpid;
13567c478bd9Sstevel@tonic-gate 	ti_p->ti_exitval = (void *)(uintptr_t)ulwp->ul_rval;
13577c478bd9Sstevel@tonic-gate 	ti_p->ti_startfunc = (psaddr_t)ulwp->ul_startpc;
13587c478bd9Sstevel@tonic-gate 	if (!ulwp->ul_dead) {
13597c478bd9Sstevel@tonic-gate 		/*
13607c478bd9Sstevel@tonic-gate 		 * The bloody fools got this backwards!
13617c478bd9Sstevel@tonic-gate 		 */
13627c478bd9Sstevel@tonic-gate 		ti_p->ti_stkbase = (psaddr_t)ulwp->ul_stktop;
13637c478bd9Sstevel@tonic-gate 		ti_p->ti_stksize = ulwp->ul_stksiz;
13647c478bd9Sstevel@tonic-gate 	}
13657c478bd9Sstevel@tonic-gate 	ti_p->ti_ro_area = ts_addr;
13667c478bd9Sstevel@tonic-gate 	ti_p->ti_ro_size = ulwp->ul_replace?
13677c478bd9Sstevel@tonic-gate 	    REPLACEMENT_SIZE32 : sizeof (ulwp32_t);
13687c478bd9Sstevel@tonic-gate 	ti_p->ti_state = ulwp->ul_dead? TD_THR_ZOMBIE :
13697c478bd9Sstevel@tonic-gate 	    ulwp->ul_stop? TD_THR_STOPPED :
13707c478bd9Sstevel@tonic-gate 	    ulwp->ul_wchan? TD_THR_SLEEP :
13717c478bd9Sstevel@tonic-gate 	    TD_THR_ACTIVE;
13727c478bd9Sstevel@tonic-gate 	ti_p->ti_db_suspended = 0;
13737c478bd9Sstevel@tonic-gate 	ti_p->ti_type = TD_THR_USER;
13747c478bd9Sstevel@tonic-gate 	ti_p->ti_sp = (uint32_t)ulwp->ul_sp;
13757c478bd9Sstevel@tonic-gate 	ti_p->ti_flags = 0;
13767c478bd9Sstevel@tonic-gate 	ti_p->ti_pri = ulwp->ul_pri;
13777c478bd9Sstevel@tonic-gate 	ti_p->ti_lid = lwpid;
13787c478bd9Sstevel@tonic-gate 	if (!ulwp->ul_dead)
13797c478bd9Sstevel@tonic-gate 		ti_p->ti_sigmask = *(sigset_t *)&ulwp->ul_sigmask;
13807c478bd9Sstevel@tonic-gate 	ti_p->ti_traceme = 0;
13817c478bd9Sstevel@tonic-gate 	ti_p->ti_preemptflag = 0;
13827c478bd9Sstevel@tonic-gate 	ti_p->ti_pirecflag = 0;
13837c478bd9Sstevel@tonic-gate 	(void) sigemptyset(&ti_p->ti_pending);
13847c478bd9Sstevel@tonic-gate 	ti_p->ti_events = ulwp->ul_td_evbuf.eventmask;
13857c478bd9Sstevel@tonic-gate }
13867c478bd9Sstevel@tonic-gate #endif	/* _SYSCALL32 */
13877c478bd9Sstevel@tonic-gate 
13887c478bd9Sstevel@tonic-gate /*
13897c478bd9Sstevel@tonic-gate  * Get thread information.
13907c478bd9Sstevel@tonic-gate  */
13917c478bd9Sstevel@tonic-gate #pragma weak td_thr_get_info = __td_thr_get_info
13927c478bd9Sstevel@tonic-gate td_err_e
13937c478bd9Sstevel@tonic-gate __td_thr_get_info(td_thrhandle_t *th_p, td_thrinfo_t *ti_p)
13947c478bd9Sstevel@tonic-gate {
13957c478bd9Sstevel@tonic-gate 	struct ps_prochandle *ph_p;
13967c478bd9Sstevel@tonic-gate 	td_thragent_t	*ta_p;
13977c478bd9Sstevel@tonic-gate 	td_err_e	return_val;
13987c478bd9Sstevel@tonic-gate 	psaddr_t	psaddr;
13997c478bd9Sstevel@tonic-gate 
14007c478bd9Sstevel@tonic-gate 	if (ti_p == NULL)
14017c478bd9Sstevel@tonic-gate 		return (TD_ERR);
14027c478bd9Sstevel@tonic-gate 	(void) memset(ti_p, NULL, sizeof (*ti_p));
14037c478bd9Sstevel@tonic-gate 
14047c478bd9Sstevel@tonic-gate 	if ((ph_p = ph_lock_th(th_p, &return_val)) == NULL)
14057c478bd9Sstevel@tonic-gate 		return (return_val);
14067c478bd9Sstevel@tonic-gate 	ta_p = th_p->th_ta_p;
14077c478bd9Sstevel@tonic-gate 	if (ps_pstop(ph_p) != PS_OK) {
14087c478bd9Sstevel@tonic-gate 		ph_unlock(ta_p);
14097c478bd9Sstevel@tonic-gate 		return (TD_DBERR);
14107c478bd9Sstevel@tonic-gate 	}
14117c478bd9Sstevel@tonic-gate 
14127c478bd9Sstevel@tonic-gate 	/*
14137c478bd9Sstevel@tonic-gate 	 * Read the ulwp struct from the process.
14147c478bd9Sstevel@tonic-gate 	 * Transfer the ulwp struct to the thread information struct.
14157c478bd9Sstevel@tonic-gate 	 */
14167c478bd9Sstevel@tonic-gate 	psaddr = th_p->th_unique;
14177c478bd9Sstevel@tonic-gate 	if (ta_p->model == PR_MODEL_NATIVE) {
14187c478bd9Sstevel@tonic-gate 		ulwp_t ulwp;
14197c478bd9Sstevel@tonic-gate 
14207c478bd9Sstevel@tonic-gate 		if (ps_pdread(ph_p, psaddr, &ulwp, sizeof (ulwp)) != PS_OK &&
14217c478bd9Sstevel@tonic-gate 		    ((void) memset(&ulwp, 0, sizeof (ulwp)),
14227c478bd9Sstevel@tonic-gate 		    ps_pdread(ph_p, psaddr, &ulwp, REPLACEMENT_SIZE)) != PS_OK)
14237c478bd9Sstevel@tonic-gate 			return_val = TD_DBERR;
14247c478bd9Sstevel@tonic-gate 		else
14257c478bd9Sstevel@tonic-gate 			td_thr2to(ta_p, psaddr, &ulwp, ti_p);
14267c478bd9Sstevel@tonic-gate 	} else {
14277c478bd9Sstevel@tonic-gate #if defined(_LP64) && defined(_SYSCALL32)
14287c478bd9Sstevel@tonic-gate 		ulwp32_t ulwp;
14297c478bd9Sstevel@tonic-gate 
14307c478bd9Sstevel@tonic-gate 		if (ps_pdread(ph_p, psaddr, &ulwp, sizeof (ulwp)) != PS_OK &&
14317c478bd9Sstevel@tonic-gate 		    ((void) memset(&ulwp, 0, sizeof (ulwp)),
14327c478bd9Sstevel@tonic-gate 		    ps_pdread(ph_p, psaddr, &ulwp, REPLACEMENT_SIZE32)) !=
14337c478bd9Sstevel@tonic-gate 		    PS_OK)
14347c478bd9Sstevel@tonic-gate 			return_val = TD_DBERR;
14357c478bd9Sstevel@tonic-gate 		else
14367c478bd9Sstevel@tonic-gate 			td_thr2to32(ta_p, psaddr, &ulwp, ti_p);
14377c478bd9Sstevel@tonic-gate #else
14387c478bd9Sstevel@tonic-gate 		return_val = TD_ERR;
14397c478bd9Sstevel@tonic-gate #endif	/* _SYSCALL32 */
14407c478bd9Sstevel@tonic-gate 	}
14417c478bd9Sstevel@tonic-gate 
14427c478bd9Sstevel@tonic-gate 	(void) ps_pcontinue(ph_p);
14437c478bd9Sstevel@tonic-gate 	ph_unlock(ta_p);
14447c478bd9Sstevel@tonic-gate 	return (return_val);
14457c478bd9Sstevel@tonic-gate }
14467c478bd9Sstevel@tonic-gate 
14477c478bd9Sstevel@tonic-gate /*
14487c478bd9Sstevel@tonic-gate  * Given a process and an event number, return information about
14497c478bd9Sstevel@tonic-gate  * an address in the process or at which a breakpoint can be set
14507c478bd9Sstevel@tonic-gate  * to monitor the event.
14517c478bd9Sstevel@tonic-gate  */
14527c478bd9Sstevel@tonic-gate #pragma weak td_ta_event_addr = __td_ta_event_addr
14537c478bd9Sstevel@tonic-gate td_err_e
14547c478bd9Sstevel@tonic-gate __td_ta_event_addr(td_thragent_t *ta_p, td_event_e event, td_notify_t *notify_p)
14557c478bd9Sstevel@tonic-gate {
14567c478bd9Sstevel@tonic-gate 	if (ta_p == NULL)
14577c478bd9Sstevel@tonic-gate 		return (TD_BADTA);
14587c478bd9Sstevel@tonic-gate 	if (event < TD_MIN_EVENT_NUM || event > TD_MAX_EVENT_NUM)
14597c478bd9Sstevel@tonic-gate 		return (TD_NOEVENT);
14607c478bd9Sstevel@tonic-gate 	if (notify_p == NULL)
14617c478bd9Sstevel@tonic-gate 		return (TD_ERR);
14627c478bd9Sstevel@tonic-gate 
14637c478bd9Sstevel@tonic-gate 	notify_p->type = NOTIFY_BPT;
14647c478bd9Sstevel@tonic-gate 	notify_p->u.bptaddr = ta_p->tdb_events[event - TD_MIN_EVENT_NUM];
14657c478bd9Sstevel@tonic-gate 
14667c478bd9Sstevel@tonic-gate 	return (TD_OK);
14677c478bd9Sstevel@tonic-gate }
14687c478bd9Sstevel@tonic-gate 
14697c478bd9Sstevel@tonic-gate /*
14707c478bd9Sstevel@tonic-gate  * Add the events in eventset 2 to eventset 1.
14717c478bd9Sstevel@tonic-gate  */
14727c478bd9Sstevel@tonic-gate static void
14737c478bd9Sstevel@tonic-gate eventsetaddset(td_thr_events_t *event1_p, td_thr_events_t *event2_p)
14747c478bd9Sstevel@tonic-gate {
14757c478bd9Sstevel@tonic-gate 	int	i;
14767c478bd9Sstevel@tonic-gate 
14777c478bd9Sstevel@tonic-gate 	for (i = 0; i < TD_EVENTSIZE; i++)
14787c478bd9Sstevel@tonic-gate 		event1_p->event_bits[i] |= event2_p->event_bits[i];
14797c478bd9Sstevel@tonic-gate }
14807c478bd9Sstevel@tonic-gate 
14817c478bd9Sstevel@tonic-gate /*
14827c478bd9Sstevel@tonic-gate  * Delete the events in eventset 2 from eventset 1.
14837c478bd9Sstevel@tonic-gate  */
14847c478bd9Sstevel@tonic-gate static void
14857c478bd9Sstevel@tonic-gate eventsetdelset(td_thr_events_t *event1_p, td_thr_events_t *event2_p)
14867c478bd9Sstevel@tonic-gate {
14877c478bd9Sstevel@tonic-gate 	int	i;
14887c478bd9Sstevel@tonic-gate 
14897c478bd9Sstevel@tonic-gate 	for (i = 0; i < TD_EVENTSIZE; i++)
14907c478bd9Sstevel@tonic-gate 		event1_p->event_bits[i] &= ~event2_p->event_bits[i];
14917c478bd9Sstevel@tonic-gate }
14927c478bd9Sstevel@tonic-gate 
14937c478bd9Sstevel@tonic-gate /*
14947c478bd9Sstevel@tonic-gate  * Either add or delete the given event set from a thread's event mask.
14957c478bd9Sstevel@tonic-gate  */
14967c478bd9Sstevel@tonic-gate static td_err_e
14977c478bd9Sstevel@tonic-gate mod_eventset(td_thrhandle_t *th_p, td_thr_events_t *events, int onoff)
14987c478bd9Sstevel@tonic-gate {
14997c478bd9Sstevel@tonic-gate 	struct ps_prochandle *ph_p;
15007c478bd9Sstevel@tonic-gate 	td_err_e	return_val = TD_OK;
15017c478bd9Sstevel@tonic-gate 	char		enable;
15027c478bd9Sstevel@tonic-gate 	td_thr_events_t	evset;
15037c478bd9Sstevel@tonic-gate 	psaddr_t	psaddr_evset;
15047c478bd9Sstevel@tonic-gate 	psaddr_t	psaddr_enab;
15057c478bd9Sstevel@tonic-gate 
15067c478bd9Sstevel@tonic-gate 	if ((ph_p = ph_lock_th(th_p, &return_val)) == NULL)
15077c478bd9Sstevel@tonic-gate 		return (return_val);
15087c478bd9Sstevel@tonic-gate 	if (th_p->th_ta_p->model == PR_MODEL_NATIVE) {
15097c478bd9Sstevel@tonic-gate 		ulwp_t *ulwp = (ulwp_t *)th_p->th_unique;
15107c478bd9Sstevel@tonic-gate 		psaddr_evset = (psaddr_t)&ulwp->ul_td_evbuf.eventmask;
15117c478bd9Sstevel@tonic-gate 		psaddr_enab = (psaddr_t)&ulwp->ul_td_events_enable;
15127c478bd9Sstevel@tonic-gate 	} else {
15137c478bd9Sstevel@tonic-gate #if defined(_LP64) && defined(_SYSCALL32)
15147c478bd9Sstevel@tonic-gate 		ulwp32_t *ulwp = (ulwp32_t *)th_p->th_unique;
15157c478bd9Sstevel@tonic-gate 		psaddr_evset = (psaddr_t)&ulwp->ul_td_evbuf.eventmask;
15167c478bd9Sstevel@tonic-gate 		psaddr_enab = (psaddr_t)&ulwp->ul_td_events_enable;
15177c478bd9Sstevel@tonic-gate #else
15187c478bd9Sstevel@tonic-gate 		ph_unlock(th_p->th_ta_p);
15197c478bd9Sstevel@tonic-gate 		return (TD_ERR);
15207c478bd9Sstevel@tonic-gate #endif	/* _SYSCALL32 */
15217c478bd9Sstevel@tonic-gate 	}
15227c478bd9Sstevel@tonic-gate 	if (ps_pstop(ph_p) != PS_OK) {
15237c478bd9Sstevel@tonic-gate 		ph_unlock(th_p->th_ta_p);
15247c478bd9Sstevel@tonic-gate 		return (TD_DBERR);
15257c478bd9Sstevel@tonic-gate 	}
15267c478bd9Sstevel@tonic-gate 
15277c478bd9Sstevel@tonic-gate 	if (ps_pdread(ph_p, psaddr_evset, &evset, sizeof (evset)) != PS_OK)
15287c478bd9Sstevel@tonic-gate 		return_val = TD_DBERR;
15297c478bd9Sstevel@tonic-gate 	else {
15307c478bd9Sstevel@tonic-gate 		if (onoff)
15317c478bd9Sstevel@tonic-gate 			eventsetaddset(&evset, events);
15327c478bd9Sstevel@tonic-gate 		else
15337c478bd9Sstevel@tonic-gate 			eventsetdelset(&evset, events);
15347c478bd9Sstevel@tonic-gate 		if (ps_pdwrite(ph_p, psaddr_evset, &evset, sizeof (evset))
15357c478bd9Sstevel@tonic-gate 		    != PS_OK)
15367c478bd9Sstevel@tonic-gate 			return_val = TD_DBERR;
15377c478bd9Sstevel@tonic-gate 		else {
15387c478bd9Sstevel@tonic-gate 			enable = 0;
15397c478bd9Sstevel@tonic-gate 			if (td_eventismember(&evset, TD_EVENTS_ENABLE))
15407c478bd9Sstevel@tonic-gate 				enable = 1;
15417c478bd9Sstevel@tonic-gate 			if (ps_pdwrite(ph_p, psaddr_enab,
15427c478bd9Sstevel@tonic-gate 			    &enable, sizeof (enable)) != PS_OK)
15437c478bd9Sstevel@tonic-gate 				return_val = TD_DBERR;
15447c478bd9Sstevel@tonic-gate 		}
15457c478bd9Sstevel@tonic-gate 	}
15467c478bd9Sstevel@tonic-gate 
15477c478bd9Sstevel@tonic-gate 	(void) ps_pcontinue(ph_p);
15487c478bd9Sstevel@tonic-gate 	ph_unlock(th_p->th_ta_p);
15497c478bd9Sstevel@tonic-gate 	return (return_val);
15507c478bd9Sstevel@tonic-gate }
15517c478bd9Sstevel@tonic-gate 
15527c478bd9Sstevel@tonic-gate /*
15537c478bd9Sstevel@tonic-gate  * Enable or disable tracing for a given thread.  Tracing
15547c478bd9Sstevel@tonic-gate  * is filtered based on the event mask of each thread.  Tracing
15557c478bd9Sstevel@tonic-gate  * can be turned on/off for the thread without changing thread
15567c478bd9Sstevel@tonic-gate  * event mask.
15577c478bd9Sstevel@tonic-gate  * Currently unused by dbx.
15587c478bd9Sstevel@tonic-gate  */
15597c478bd9Sstevel@tonic-gate #pragma weak td_thr_event_enable = __td_thr_event_enable
15607c478bd9Sstevel@tonic-gate td_err_e
15617c478bd9Sstevel@tonic-gate __td_thr_event_enable(td_thrhandle_t *th_p, int onoff)
15627c478bd9Sstevel@tonic-gate {
15637c478bd9Sstevel@tonic-gate 	td_thr_events_t	evset;
15647c478bd9Sstevel@tonic-gate 
15657c478bd9Sstevel@tonic-gate 	td_event_emptyset(&evset);
15667c478bd9Sstevel@tonic-gate 	td_event_addset(&evset, TD_EVENTS_ENABLE);
15677c478bd9Sstevel@tonic-gate 	return (mod_eventset(th_p, &evset, onoff));
15687c478bd9Sstevel@tonic-gate }
15697c478bd9Sstevel@tonic-gate 
15707c478bd9Sstevel@tonic-gate /*
15717c478bd9Sstevel@tonic-gate  * Set event mask to enable event. event is turned on in
15727c478bd9Sstevel@tonic-gate  * event mask for thread.  If a thread encounters an event
15737c478bd9Sstevel@tonic-gate  * for which its event mask is on, notification will be sent
15747c478bd9Sstevel@tonic-gate  * to the debugger.
15757c478bd9Sstevel@tonic-gate  * Addresses for each event are provided to the
15767c478bd9Sstevel@tonic-gate  * debugger.  It is assumed that a breakpoint of some type will
15777c478bd9Sstevel@tonic-gate  * be placed at that address.  If the event mask for the thread
15787c478bd9Sstevel@tonic-gate  * is on, the instruction at the address will be executed.
15797c478bd9Sstevel@tonic-gate  * Otherwise, the instruction will be skipped.
15807c478bd9Sstevel@tonic-gate  */
15817c478bd9Sstevel@tonic-gate #pragma weak td_thr_set_event = __td_thr_set_event
15827c478bd9Sstevel@tonic-gate td_err_e
15837c478bd9Sstevel@tonic-gate __td_thr_set_event(td_thrhandle_t *th_p, td_thr_events_t *events)
15847c478bd9Sstevel@tonic-gate {
15857c478bd9Sstevel@tonic-gate 	return (mod_eventset(th_p, events, 1));
15867c478bd9Sstevel@tonic-gate }
15877c478bd9Sstevel@tonic-gate 
15887c478bd9Sstevel@tonic-gate /*
15897c478bd9Sstevel@tonic-gate  * Enable or disable a set of events in the process-global event mask,
15907c478bd9Sstevel@tonic-gate  * depending on the value of onoff.
15917c478bd9Sstevel@tonic-gate  */
15927c478bd9Sstevel@tonic-gate static td_err_e
15937c478bd9Sstevel@tonic-gate td_ta_mod_event(td_thragent_t *ta_p, td_thr_events_t *events, int onoff)
15947c478bd9Sstevel@tonic-gate {
15957c478bd9Sstevel@tonic-gate 	struct ps_prochandle *ph_p;
15967c478bd9Sstevel@tonic-gate 	td_thr_events_t targ_eventset;
15977c478bd9Sstevel@tonic-gate 	td_err_e	return_val;
15987c478bd9Sstevel@tonic-gate 
15997c478bd9Sstevel@tonic-gate 	if ((ph_p = ph_lock_ta(ta_p, &return_val)) == NULL)
16007c478bd9Sstevel@tonic-gate 		return (return_val);
16017c478bd9Sstevel@tonic-gate 	if (ps_pstop(ph_p) != PS_OK) {
16027c478bd9Sstevel@tonic-gate 		ph_unlock(ta_p);
16037c478bd9Sstevel@tonic-gate 		return (TD_DBERR);
16047c478bd9Sstevel@tonic-gate 	}
16057c478bd9Sstevel@tonic-gate 	if (ps_pdread(ph_p, ta_p->tdb_eventmask_addr,
16067c478bd9Sstevel@tonic-gate 	    &targ_eventset, sizeof (targ_eventset)) != PS_OK)
16077c478bd9Sstevel@tonic-gate 		return_val = TD_DBERR;
16087c478bd9Sstevel@tonic-gate 	else {
16097c478bd9Sstevel@tonic-gate 		if (onoff)
16107c478bd9Sstevel@tonic-gate 			eventsetaddset(&targ_eventset, events);
16117c478bd9Sstevel@tonic-gate 		else
16127c478bd9Sstevel@tonic-gate 			eventsetdelset(&targ_eventset, events);
16137c478bd9Sstevel@tonic-gate 		if (ps_pdwrite(ph_p, ta_p->tdb_eventmask_addr,
16147c478bd9Sstevel@tonic-gate 		    &targ_eventset, sizeof (targ_eventset)) != PS_OK)
16157c478bd9Sstevel@tonic-gate 			return_val = TD_DBERR;
16167c478bd9Sstevel@tonic-gate 	}
16177c478bd9Sstevel@tonic-gate 	(void) ps_pcontinue(ph_p);
16187c478bd9Sstevel@tonic-gate 	ph_unlock(ta_p);
16197c478bd9Sstevel@tonic-gate 	return (return_val);
16207c478bd9Sstevel@tonic-gate }
16217c478bd9Sstevel@tonic-gate 
16227c478bd9Sstevel@tonic-gate /*
16237c478bd9Sstevel@tonic-gate  * Enable a set of events in the process-global event mask.
16247c478bd9Sstevel@tonic-gate  */
16257c478bd9Sstevel@tonic-gate #pragma weak td_ta_set_event = __td_ta_set_event
16267c478bd9Sstevel@tonic-gate td_err_e
16277c478bd9Sstevel@tonic-gate __td_ta_set_event(td_thragent_t *ta_p, td_thr_events_t *events)
16287c478bd9Sstevel@tonic-gate {
16297c478bd9Sstevel@tonic-gate 	return (td_ta_mod_event(ta_p, events, 1));
16307c478bd9Sstevel@tonic-gate }
16317c478bd9Sstevel@tonic-gate 
16327c478bd9Sstevel@tonic-gate /*
16337c478bd9Sstevel@tonic-gate  * Set event mask to disable the given event set; these events are cleared
16347c478bd9Sstevel@tonic-gate  * from the event mask of the thread.  Events that occur for a thread
16357c478bd9Sstevel@tonic-gate  * with the event masked off will not cause notification to be
16367c478bd9Sstevel@tonic-gate  * sent to the debugger (see td_thr_set_event for fuller description).
16377c478bd9Sstevel@tonic-gate  */
16387c478bd9Sstevel@tonic-gate #pragma weak td_thr_clear_event = __td_thr_clear_event
16397c478bd9Sstevel@tonic-gate td_err_e
16407c478bd9Sstevel@tonic-gate __td_thr_clear_event(td_thrhandle_t *th_p, td_thr_events_t *events)
16417c478bd9Sstevel@tonic-gate {
16427c478bd9Sstevel@tonic-gate 	return (mod_eventset(th_p, events, 0));
16437c478bd9Sstevel@tonic-gate }
16447c478bd9Sstevel@tonic-gate 
16457c478bd9Sstevel@tonic-gate /*
16467c478bd9Sstevel@tonic-gate  * Disable a set of events in the process-global event mask.
16477c478bd9Sstevel@tonic-gate  */
16487c478bd9Sstevel@tonic-gate #pragma weak td_ta_clear_event = __td_ta_clear_event
16497c478bd9Sstevel@tonic-gate td_err_e
16507c478bd9Sstevel@tonic-gate __td_ta_clear_event(td_thragent_t *ta_p, td_thr_events_t *events)
16517c478bd9Sstevel@tonic-gate {
16527c478bd9Sstevel@tonic-gate 	return (td_ta_mod_event(ta_p, events, 0));
16537c478bd9Sstevel@tonic-gate }
16547c478bd9Sstevel@tonic-gate 
16557c478bd9Sstevel@tonic-gate /*
16567c478bd9Sstevel@tonic-gate  * This function returns the most recent event message, if any,
16577c478bd9Sstevel@tonic-gate  * associated with a thread.  Given a thread handle, return the message
16587c478bd9Sstevel@tonic-gate  * corresponding to the event encountered by the thread.  Only one
16597c478bd9Sstevel@tonic-gate  * message per thread is saved.  Messages from earlier events are lost
16607c478bd9Sstevel@tonic-gate  * when later events occur.
16617c478bd9Sstevel@tonic-gate  */
16627c478bd9Sstevel@tonic-gate #pragma weak td_thr_event_getmsg = __td_thr_event_getmsg
16637c478bd9Sstevel@tonic-gate td_err_e
16647c478bd9Sstevel@tonic-gate __td_thr_event_getmsg(td_thrhandle_t *th_p, td_event_msg_t *msg)
16657c478bd9Sstevel@tonic-gate {
16667c478bd9Sstevel@tonic-gate 	struct ps_prochandle *ph_p;
16677c478bd9Sstevel@tonic-gate 	td_err_e	return_val = TD_OK;
16687c478bd9Sstevel@tonic-gate 	psaddr_t	psaddr;
16697c478bd9Sstevel@tonic-gate 
16707c478bd9Sstevel@tonic-gate 	if ((ph_p = ph_lock_th(th_p, &return_val)) == NULL)
16717c478bd9Sstevel@tonic-gate 		return (return_val);
16727c478bd9Sstevel@tonic-gate 	if (ps_pstop(ph_p) != PS_OK) {
16737c478bd9Sstevel@tonic-gate 		ph_unlock(th_p->th_ta_p);
16747c478bd9Sstevel@tonic-gate 		return (TD_BADTA);
16757c478bd9Sstevel@tonic-gate 	}
16767c478bd9Sstevel@tonic-gate 	if (th_p->th_ta_p->model == PR_MODEL_NATIVE) {
16777c478bd9Sstevel@tonic-gate 		ulwp_t *ulwp = (ulwp_t *)th_p->th_unique;
16787c478bd9Sstevel@tonic-gate 		td_evbuf_t evbuf;
16797c478bd9Sstevel@tonic-gate 
16807c478bd9Sstevel@tonic-gate 		psaddr = (psaddr_t)&ulwp->ul_td_evbuf;
16817c478bd9Sstevel@tonic-gate 		if (ps_pdread(ph_p, psaddr, &evbuf, sizeof (evbuf)) != PS_OK) {
16827c478bd9Sstevel@tonic-gate 			return_val = TD_DBERR;
16837c478bd9Sstevel@tonic-gate 		} else if (evbuf.eventnum == TD_EVENT_NONE) {
16847c478bd9Sstevel@tonic-gate 			return_val = TD_NOEVENT;
16857c478bd9Sstevel@tonic-gate 		} else {
16867c478bd9Sstevel@tonic-gate 			msg->event = evbuf.eventnum;
16877c478bd9Sstevel@tonic-gate 			msg->th_p = (td_thrhandle_t *)th_p;
16887c478bd9Sstevel@tonic-gate 			msg->msg.data = (uintptr_t)evbuf.eventdata;
16897c478bd9Sstevel@tonic-gate 			/* "Consume" the message */
16907c478bd9Sstevel@tonic-gate 			evbuf.eventnum = TD_EVENT_NONE;
16917c478bd9Sstevel@tonic-gate 			evbuf.eventdata = NULL;
16927c478bd9Sstevel@tonic-gate 			if (ps_pdwrite(ph_p, psaddr, &evbuf, sizeof (evbuf))
16937c478bd9Sstevel@tonic-gate 			    != PS_OK)
16947c478bd9Sstevel@tonic-gate 				return_val = TD_DBERR;
16957c478bd9Sstevel@tonic-gate 		}
16967c478bd9Sstevel@tonic-gate 	} else {
16977c478bd9Sstevel@tonic-gate #if defined(_LP64) && defined(_SYSCALL32)
16987c478bd9Sstevel@tonic-gate 		ulwp32_t *ulwp = (ulwp32_t *)th_p->th_unique;
16997c478bd9Sstevel@tonic-gate 		td_evbuf32_t evbuf;
17007c478bd9Sstevel@tonic-gate 
17017c478bd9Sstevel@tonic-gate 		psaddr = (psaddr_t)&ulwp->ul_td_evbuf;
17027c478bd9Sstevel@tonic-gate 		if (ps_pdread(ph_p, psaddr, &evbuf, sizeof (evbuf)) != PS_OK) {
17037c478bd9Sstevel@tonic-gate 			return_val = TD_DBERR;
17047c478bd9Sstevel@tonic-gate 		} else if (evbuf.eventnum == TD_EVENT_NONE) {
17057c478bd9Sstevel@tonic-gate 			return_val = TD_NOEVENT;
17067c478bd9Sstevel@tonic-gate 		} else {
17077c478bd9Sstevel@tonic-gate 			msg->event = evbuf.eventnum;
17087c478bd9Sstevel@tonic-gate 			msg->th_p = (td_thrhandle_t *)th_p;
17097c478bd9Sstevel@tonic-gate 			msg->msg.data = (uintptr_t)evbuf.eventdata;
17107c478bd9Sstevel@tonic-gate 			/* "Consume" the message */
17117c478bd9Sstevel@tonic-gate 			evbuf.eventnum = TD_EVENT_NONE;
17127c478bd9Sstevel@tonic-gate 			evbuf.eventdata = NULL;
17137c478bd9Sstevel@tonic-gate 			if (ps_pdwrite(ph_p, psaddr, &evbuf, sizeof (evbuf))
17147c478bd9Sstevel@tonic-gate 			    != PS_OK)
17157c478bd9Sstevel@tonic-gate 				return_val = TD_DBERR;
17167c478bd9Sstevel@tonic-gate 		}
17177c478bd9Sstevel@tonic-gate #else
17187c478bd9Sstevel@tonic-gate 		return_val = TD_ERR;
17197c478bd9Sstevel@tonic-gate #endif	/* _SYSCALL32 */
17207c478bd9Sstevel@tonic-gate 	}
17217c478bd9Sstevel@tonic-gate 
17227c478bd9Sstevel@tonic-gate 	(void) ps_pcontinue(ph_p);
17237c478bd9Sstevel@tonic-gate 	ph_unlock(th_p->th_ta_p);
17247c478bd9Sstevel@tonic-gate 	return (return_val);
17257c478bd9Sstevel@tonic-gate }
17267c478bd9Sstevel@tonic-gate 
17277c478bd9Sstevel@tonic-gate /*
17287c478bd9Sstevel@tonic-gate  * The callback function td_ta_event_getmsg uses when looking for
17297c478bd9Sstevel@tonic-gate  * a thread with an event.  A thin wrapper around td_thr_event_getmsg.
17307c478bd9Sstevel@tonic-gate  */
17317c478bd9Sstevel@tonic-gate static int
17327c478bd9Sstevel@tonic-gate event_msg_cb(const td_thrhandle_t *th_p, void *arg)
17337c478bd9Sstevel@tonic-gate {
17347c478bd9Sstevel@tonic-gate 	static td_thrhandle_t th;
17357c478bd9Sstevel@tonic-gate 	td_event_msg_t *msg = arg;
17367c478bd9Sstevel@tonic-gate 
17377c478bd9Sstevel@tonic-gate 	if (__td_thr_event_getmsg((td_thrhandle_t *)th_p, msg) == TD_OK) {
17387c478bd9Sstevel@tonic-gate 		/*
17397c478bd9Sstevel@tonic-gate 		 * Got an event, stop iterating.
17407c478bd9Sstevel@tonic-gate 		 *
17417c478bd9Sstevel@tonic-gate 		 * Because of past mistakes in interface definition,
17427c478bd9Sstevel@tonic-gate 		 * we are forced to pass back a static local variable
17437c478bd9Sstevel@tonic-gate 		 * for the thread handle because th_p is a pointer
17447c478bd9Sstevel@tonic-gate 		 * to a local variable in __td_ta_thr_iter().
17457c478bd9Sstevel@tonic-gate 		 * Grr...
17467c478bd9Sstevel@tonic-gate 		 */
17477c478bd9Sstevel@tonic-gate 		th = *th_p;
17487c478bd9Sstevel@tonic-gate 		msg->th_p = &th;
17497c478bd9Sstevel@tonic-gate 		return (1);
17507c478bd9Sstevel@tonic-gate 	}
17517c478bd9Sstevel@tonic-gate 	return (0);
17527c478bd9Sstevel@tonic-gate }
17537c478bd9Sstevel@tonic-gate 
17547c478bd9Sstevel@tonic-gate /*
17557c478bd9Sstevel@tonic-gate  * This function is just like td_thr_event_getmsg, except that it is
17567c478bd9Sstevel@tonic-gate  * passed a process handle rather than a thread handle, and returns
17577c478bd9Sstevel@tonic-gate  * an event message for some thread in the process that has an event
17587c478bd9Sstevel@tonic-gate  * message pending.  If no thread has an event message pending, this
17597c478bd9Sstevel@tonic-gate  * routine returns TD_NOEVENT.  Thus, all pending event messages may
17607c478bd9Sstevel@tonic-gate  * be collected from a process by repeatedly calling this routine
17617c478bd9Sstevel@tonic-gate  * until it returns TD_NOEVENT.
17627c478bd9Sstevel@tonic-gate  */
17637c478bd9Sstevel@tonic-gate #pragma weak td_ta_event_getmsg = __td_ta_event_getmsg
17647c478bd9Sstevel@tonic-gate td_err_e
17657c478bd9Sstevel@tonic-gate __td_ta_event_getmsg(td_thragent_t *ta_p, td_event_msg_t *msg)
17667c478bd9Sstevel@tonic-gate {
17677c478bd9Sstevel@tonic-gate 	td_err_e return_val;
17687c478bd9Sstevel@tonic-gate 
17697c478bd9Sstevel@tonic-gate 	if (ta_p == NULL)
17707c478bd9Sstevel@tonic-gate 		return (TD_BADTA);
17717c478bd9Sstevel@tonic-gate 	if (ta_p->ph_p == NULL)
17727c478bd9Sstevel@tonic-gate 		return (TD_BADPH);
17737c478bd9Sstevel@tonic-gate 	if (msg == NULL)
17747c478bd9Sstevel@tonic-gate 		return (TD_ERR);
17757c478bd9Sstevel@tonic-gate 	msg->event = TD_EVENT_NONE;
17767c478bd9Sstevel@tonic-gate 	if ((return_val = __td_ta_thr_iter(ta_p, event_msg_cb, msg,
17777c478bd9Sstevel@tonic-gate 	    TD_THR_ANY_STATE, TD_THR_LOWEST_PRIORITY, TD_SIGNO_MASK,
17787c478bd9Sstevel@tonic-gate 	    TD_THR_ANY_USER_FLAGS)) != TD_OK)
17797c478bd9Sstevel@tonic-gate 		return (return_val);
17807c478bd9Sstevel@tonic-gate 	if (msg->event == TD_EVENT_NONE)
17817c478bd9Sstevel@tonic-gate 		return (TD_NOEVENT);
17827c478bd9Sstevel@tonic-gate 	return (TD_OK);
17837c478bd9Sstevel@tonic-gate }
17847c478bd9Sstevel@tonic-gate 
17857c478bd9Sstevel@tonic-gate static lwpid_t
17867c478bd9Sstevel@tonic-gate thr_to_lwpid(const td_thrhandle_t *th_p)
17877c478bd9Sstevel@tonic-gate {
17887c478bd9Sstevel@tonic-gate 	struct ps_prochandle *ph_p = th_p->th_ta_p->ph_p;
17897c478bd9Sstevel@tonic-gate 	lwpid_t lwpid;
17907c478bd9Sstevel@tonic-gate 
17917c478bd9Sstevel@tonic-gate 	/*
17927c478bd9Sstevel@tonic-gate 	 * The caller holds the prochandle lock
17937c478bd9Sstevel@tonic-gate 	 * and has already verfied everything.
17947c478bd9Sstevel@tonic-gate 	 */
17957c478bd9Sstevel@tonic-gate 	if (th_p->th_ta_p->model == PR_MODEL_NATIVE) {
17967c478bd9Sstevel@tonic-gate 		ulwp_t *ulwp = (ulwp_t *)th_p->th_unique;
17977c478bd9Sstevel@tonic-gate 
17987c478bd9Sstevel@tonic-gate 		if (ps_pdread(ph_p, (psaddr_t)&ulwp->ul_lwpid,
17997c478bd9Sstevel@tonic-gate 		    &lwpid, sizeof (lwpid)) != PS_OK)
18007c478bd9Sstevel@tonic-gate 			lwpid = 0;
18017c478bd9Sstevel@tonic-gate 		else if (lwpid == 0)
18027c478bd9Sstevel@tonic-gate 			lwpid = 1;
18037c478bd9Sstevel@tonic-gate 	} else {
18047c478bd9Sstevel@tonic-gate #if defined(_LP64) && defined(_SYSCALL32)
18057c478bd9Sstevel@tonic-gate 		ulwp32_t *ulwp = (ulwp32_t *)th_p->th_unique;
18067c478bd9Sstevel@tonic-gate 
18077c478bd9Sstevel@tonic-gate 		if (ps_pdread(ph_p, (psaddr_t)&ulwp->ul_lwpid,
18087c478bd9Sstevel@tonic-gate 		    &lwpid, sizeof (lwpid)) != PS_OK)
18097c478bd9Sstevel@tonic-gate 			lwpid = 0;
18107c478bd9Sstevel@tonic-gate 		else if (lwpid == 0)
18117c478bd9Sstevel@tonic-gate 			lwpid = 1;
18127c478bd9Sstevel@tonic-gate #else
18137c478bd9Sstevel@tonic-gate 		lwpid = 0;
18147c478bd9Sstevel@tonic-gate #endif	/* _SYSCALL32 */
18157c478bd9Sstevel@tonic-gate 	}
18167c478bd9Sstevel@tonic-gate 
18177c478bd9Sstevel@tonic-gate 	return (lwpid);
18187c478bd9Sstevel@tonic-gate }
18197c478bd9Sstevel@tonic-gate 
18207c478bd9Sstevel@tonic-gate /*
18217c478bd9Sstevel@tonic-gate  * Suspend a thread.
18227c478bd9Sstevel@tonic-gate  * XXX: What does this mean in a one-level model?
18237c478bd9Sstevel@tonic-gate  */
18247c478bd9Sstevel@tonic-gate #pragma weak td_thr_dbsuspend = __td_thr_dbsuspend
18257c478bd9Sstevel@tonic-gate td_err_e
18267c478bd9Sstevel@tonic-gate __td_thr_dbsuspend(const td_thrhandle_t *th_p)
18277c478bd9Sstevel@tonic-gate {
18287c478bd9Sstevel@tonic-gate 	struct ps_prochandle *ph_p;
18297c478bd9Sstevel@tonic-gate 	td_err_e return_val;
18307c478bd9Sstevel@tonic-gate 
18317c478bd9Sstevel@tonic-gate 	if ((ph_p = ph_lock_th(th_p, &return_val)) == NULL)
18327c478bd9Sstevel@tonic-gate 		return (return_val);
18337c478bd9Sstevel@tonic-gate 	if (ps_lstop(ph_p, thr_to_lwpid(th_p)) != PS_OK)
18347c478bd9Sstevel@tonic-gate 		return_val = TD_DBERR;
18357c478bd9Sstevel@tonic-gate 	ph_unlock(th_p->th_ta_p);
18367c478bd9Sstevel@tonic-gate 	return (return_val);
18377c478bd9Sstevel@tonic-gate }
18387c478bd9Sstevel@tonic-gate 
18397c478bd9Sstevel@tonic-gate /*
18407c478bd9Sstevel@tonic-gate  * Resume a suspended thread.
18417c478bd9Sstevel@tonic-gate  * XXX: What does this mean in a one-level model?
18427c478bd9Sstevel@tonic-gate  */
18437c478bd9Sstevel@tonic-gate #pragma weak td_thr_dbresume = __td_thr_dbresume
18447c478bd9Sstevel@tonic-gate td_err_e
18457c478bd9Sstevel@tonic-gate __td_thr_dbresume(const td_thrhandle_t *th_p)
18467c478bd9Sstevel@tonic-gate {
18477c478bd9Sstevel@tonic-gate 	struct ps_prochandle *ph_p;
18487c478bd9Sstevel@tonic-gate 	td_err_e return_val;
18497c478bd9Sstevel@tonic-gate 
18507c478bd9Sstevel@tonic-gate 	if ((ph_p = ph_lock_th(th_p, &return_val)) == NULL)
18517c478bd9Sstevel@tonic-gate 		return (return_val);
18527c478bd9Sstevel@tonic-gate 	if (ps_lcontinue(ph_p, thr_to_lwpid(th_p)) != PS_OK)
18537c478bd9Sstevel@tonic-gate 		return_val = TD_DBERR;
18547c478bd9Sstevel@tonic-gate 	ph_unlock(th_p->th_ta_p);
18557c478bd9Sstevel@tonic-gate 	return (return_val);
18567c478bd9Sstevel@tonic-gate }
18577c478bd9Sstevel@tonic-gate 
18587c478bd9Sstevel@tonic-gate /*
18597c478bd9Sstevel@tonic-gate  * Set a thread's signal mask.
18607c478bd9Sstevel@tonic-gate  * Currently unused by dbx.
18617c478bd9Sstevel@tonic-gate  */
18627c478bd9Sstevel@tonic-gate #pragma weak td_thr_sigsetmask = __td_thr_sigsetmask
18637c478bd9Sstevel@tonic-gate /* ARGSUSED */
18647c478bd9Sstevel@tonic-gate td_err_e
18657c478bd9Sstevel@tonic-gate __td_thr_sigsetmask(const td_thrhandle_t *th_p, const sigset_t ti_sigmask)
18667c478bd9Sstevel@tonic-gate {
18677c478bd9Sstevel@tonic-gate 	return (TD_NOCAPAB);
18687c478bd9Sstevel@tonic-gate }
18697c478bd9Sstevel@tonic-gate 
18707c478bd9Sstevel@tonic-gate /*
18717c478bd9Sstevel@tonic-gate  * Set a thread's "signals-pending" set.
18727c478bd9Sstevel@tonic-gate  * Currently unused by dbx.
18737c478bd9Sstevel@tonic-gate  */
18747c478bd9Sstevel@tonic-gate #pragma weak td_thr_setsigpending = __td_thr_setsigpending
18757c478bd9Sstevel@tonic-gate /* ARGSUSED */
18767c478bd9Sstevel@tonic-gate td_err_e
18777c478bd9Sstevel@tonic-gate __td_thr_setsigpending(const td_thrhandle_t *th_p,
18787c478bd9Sstevel@tonic-gate 	uchar_t ti_pending_flag, const sigset_t ti_pending)
18797c478bd9Sstevel@tonic-gate {
18807c478bd9Sstevel@tonic-gate 	return (TD_NOCAPAB);
18817c478bd9Sstevel@tonic-gate }
18827c478bd9Sstevel@tonic-gate 
18837c478bd9Sstevel@tonic-gate /*
18847c478bd9Sstevel@tonic-gate  * Get a thread's general register set.
18857c478bd9Sstevel@tonic-gate  */
18867c478bd9Sstevel@tonic-gate #pragma weak td_thr_getgregs = __td_thr_getgregs
18877c478bd9Sstevel@tonic-gate td_err_e
18887c478bd9Sstevel@tonic-gate __td_thr_getgregs(td_thrhandle_t *th_p, prgregset_t regset)
18897c478bd9Sstevel@tonic-gate {
18907c478bd9Sstevel@tonic-gate 	struct ps_prochandle *ph_p;
18917c478bd9Sstevel@tonic-gate 	td_err_e return_val;
18927c478bd9Sstevel@tonic-gate 
18937c478bd9Sstevel@tonic-gate 	if ((ph_p = ph_lock_th(th_p, &return_val)) == NULL)
18947c478bd9Sstevel@tonic-gate 		return (return_val);
18957c478bd9Sstevel@tonic-gate 	if (ps_pstop(ph_p) != PS_OK) {
18967c478bd9Sstevel@tonic-gate 		ph_unlock(th_p->th_ta_p);
18977c478bd9Sstevel@tonic-gate 		return (TD_DBERR);
18987c478bd9Sstevel@tonic-gate 	}
18997c478bd9Sstevel@tonic-gate 
19007c478bd9Sstevel@tonic-gate 	if (ps_lgetregs(ph_p, thr_to_lwpid(th_p), regset) != PS_OK)
19017c478bd9Sstevel@tonic-gate 		return_val = TD_DBERR;
19027c478bd9Sstevel@tonic-gate 
19037c478bd9Sstevel@tonic-gate 	(void) ps_pcontinue(ph_p);
19047c478bd9Sstevel@tonic-gate 	ph_unlock(th_p->th_ta_p);
19057c478bd9Sstevel@tonic-gate 	return (return_val);
19067c478bd9Sstevel@tonic-gate }
19077c478bd9Sstevel@tonic-gate 
19087c478bd9Sstevel@tonic-gate /*
19097c478bd9Sstevel@tonic-gate  * Set a thread's general register set.
19107c478bd9Sstevel@tonic-gate  */
19117c478bd9Sstevel@tonic-gate #pragma weak td_thr_setgregs = __td_thr_setgregs
19127c478bd9Sstevel@tonic-gate td_err_e
19137c478bd9Sstevel@tonic-gate __td_thr_setgregs(td_thrhandle_t *th_p, const prgregset_t regset)
19147c478bd9Sstevel@tonic-gate {
19157c478bd9Sstevel@tonic-gate 	struct ps_prochandle *ph_p;
19167c478bd9Sstevel@tonic-gate 	td_err_e return_val;
19177c478bd9Sstevel@tonic-gate 
19187c478bd9Sstevel@tonic-gate 	if ((ph_p = ph_lock_th(th_p, &return_val)) == NULL)
19197c478bd9Sstevel@tonic-gate 		return (return_val);
19207c478bd9Sstevel@tonic-gate 	if (ps_pstop(ph_p) != PS_OK) {
19217c478bd9Sstevel@tonic-gate 		ph_unlock(th_p->th_ta_p);
19227c478bd9Sstevel@tonic-gate 		return (TD_DBERR);
19237c478bd9Sstevel@tonic-gate 	}
19247c478bd9Sstevel@tonic-gate 
19257c478bd9Sstevel@tonic-gate 	if (ps_lsetregs(ph_p, thr_to_lwpid(th_p), regset) != PS_OK)
19267c478bd9Sstevel@tonic-gate 		return_val = TD_DBERR;
19277c478bd9Sstevel@tonic-gate 
19287c478bd9Sstevel@tonic-gate 	(void) ps_pcontinue(ph_p);
19297c478bd9Sstevel@tonic-gate 	ph_unlock(th_p->th_ta_p);
19307c478bd9Sstevel@tonic-gate 	return (return_val);
19317c478bd9Sstevel@tonic-gate }
19327c478bd9Sstevel@tonic-gate 
19337c478bd9Sstevel@tonic-gate /*
19347c478bd9Sstevel@tonic-gate  * Get a thread's floating-point register set.
19357c478bd9Sstevel@tonic-gate  */
19367c478bd9Sstevel@tonic-gate #pragma weak td_thr_getfpregs = __td_thr_getfpregs
19377c478bd9Sstevel@tonic-gate td_err_e
19387c478bd9Sstevel@tonic-gate __td_thr_getfpregs(td_thrhandle_t *th_p, prfpregset_t *fpregset)
19397c478bd9Sstevel@tonic-gate {
19407c478bd9Sstevel@tonic-gate 	struct ps_prochandle *ph_p;
19417c478bd9Sstevel@tonic-gate 	td_err_e return_val;
19427c478bd9Sstevel@tonic-gate 
19437c478bd9Sstevel@tonic-gate 	if ((ph_p = ph_lock_th(th_p, &return_val)) == NULL)
19447c478bd9Sstevel@tonic-gate 		return (return_val);
19457c478bd9Sstevel@tonic-gate 	if (ps_pstop(ph_p) != PS_OK) {
19467c478bd9Sstevel@tonic-gate 		ph_unlock(th_p->th_ta_p);
19477c478bd9Sstevel@tonic-gate 		return (TD_DBERR);
19487c478bd9Sstevel@tonic-gate 	}
19497c478bd9Sstevel@tonic-gate 
19507c478bd9Sstevel@tonic-gate 	if (ps_lgetfpregs(ph_p, thr_to_lwpid(th_p), fpregset) != PS_OK)
19517c478bd9Sstevel@tonic-gate 		return_val = TD_DBERR;
19527c478bd9Sstevel@tonic-gate 
19537c478bd9Sstevel@tonic-gate 	(void) ps_pcontinue(ph_p);
19547c478bd9Sstevel@tonic-gate 	ph_unlock(th_p->th_ta_p);
19557c478bd9Sstevel@tonic-gate 	return (return_val);
19567c478bd9Sstevel@tonic-gate }
19577c478bd9Sstevel@tonic-gate 
19587c478bd9Sstevel@tonic-gate /*
19597c478bd9Sstevel@tonic-gate  * Set a thread's floating-point register set.
19607c478bd9Sstevel@tonic-gate  */
19617c478bd9Sstevel@tonic-gate #pragma weak td_thr_setfpregs = __td_thr_setfpregs
19627c478bd9Sstevel@tonic-gate td_err_e
19637c478bd9Sstevel@tonic-gate __td_thr_setfpregs(td_thrhandle_t *th_p, const prfpregset_t *fpregset)
19647c478bd9Sstevel@tonic-gate {
19657c478bd9Sstevel@tonic-gate 	struct ps_prochandle *ph_p;
19667c478bd9Sstevel@tonic-gate 	td_err_e return_val;
19677c478bd9Sstevel@tonic-gate 
19687c478bd9Sstevel@tonic-gate 	if ((ph_p = ph_lock_th(th_p, &return_val)) == NULL)
19697c478bd9Sstevel@tonic-gate 		return (return_val);
19707c478bd9Sstevel@tonic-gate 	if (ps_pstop(ph_p) != PS_OK) {
19717c478bd9Sstevel@tonic-gate 		ph_unlock(th_p->th_ta_p);
19727c478bd9Sstevel@tonic-gate 		return (TD_DBERR);
19737c478bd9Sstevel@tonic-gate 	}
19747c478bd9Sstevel@tonic-gate 
19757c478bd9Sstevel@tonic-gate 	if (ps_lsetfpregs(ph_p, thr_to_lwpid(th_p), fpregset) != PS_OK)
19767c478bd9Sstevel@tonic-gate 		return_val = TD_DBERR;
19777c478bd9Sstevel@tonic-gate 
19787c478bd9Sstevel@tonic-gate 	(void) ps_pcontinue(ph_p);
19797c478bd9Sstevel@tonic-gate 	ph_unlock(th_p->th_ta_p);
19807c478bd9Sstevel@tonic-gate 	return (return_val);
19817c478bd9Sstevel@tonic-gate }
19827c478bd9Sstevel@tonic-gate 
19837c478bd9Sstevel@tonic-gate /*
19847c478bd9Sstevel@tonic-gate  * Get the size of the extra state register set for this architecture.
19857c478bd9Sstevel@tonic-gate  * Currently unused by dbx.
19867c478bd9Sstevel@tonic-gate  */
19877c478bd9Sstevel@tonic-gate #pragma weak td_thr_getxregsize = __td_thr_getxregsize
19887c478bd9Sstevel@tonic-gate /* ARGSUSED */
19897c478bd9Sstevel@tonic-gate td_err_e
19907c478bd9Sstevel@tonic-gate __td_thr_getxregsize(td_thrhandle_t *th_p, int *xregsize)
19917c478bd9Sstevel@tonic-gate {
19927c478bd9Sstevel@tonic-gate #if defined(__sparc)
19937c478bd9Sstevel@tonic-gate 	struct ps_prochandle *ph_p;
19947c478bd9Sstevel@tonic-gate 	td_err_e return_val;
19957c478bd9Sstevel@tonic-gate 
19967c478bd9Sstevel@tonic-gate 	if ((ph_p = ph_lock_th(th_p, &return_val)) == NULL)
19977c478bd9Sstevel@tonic-gate 		return (return_val);
19987c478bd9Sstevel@tonic-gate 	if (ps_pstop(ph_p) != PS_OK) {
19997c478bd9Sstevel@tonic-gate 		ph_unlock(th_p->th_ta_p);
20007c478bd9Sstevel@tonic-gate 		return (TD_DBERR);
20017c478bd9Sstevel@tonic-gate 	}
20027c478bd9Sstevel@tonic-gate 
20037c478bd9Sstevel@tonic-gate 	if (ps_lgetxregsize(ph_p, thr_to_lwpid(th_p), xregsize) != PS_OK)
20047c478bd9Sstevel@tonic-gate 		return_val = TD_DBERR;
20057c478bd9Sstevel@tonic-gate 
20067c478bd9Sstevel@tonic-gate 	(void) ps_pcontinue(ph_p);
20077c478bd9Sstevel@tonic-gate 	ph_unlock(th_p->th_ta_p);
20087c478bd9Sstevel@tonic-gate 	return (return_val);
20097c478bd9Sstevel@tonic-gate #else	/* __sparc */
20107c478bd9Sstevel@tonic-gate 	return (TD_NOXREGS);
20117c478bd9Sstevel@tonic-gate #endif	/* __sparc */
20127c478bd9Sstevel@tonic-gate }
20137c478bd9Sstevel@tonic-gate 
20147c478bd9Sstevel@tonic-gate /*
20157c478bd9Sstevel@tonic-gate  * Get a thread's extra state register set.
20167c478bd9Sstevel@tonic-gate  */
20177c478bd9Sstevel@tonic-gate #pragma weak td_thr_getxregs = __td_thr_getxregs
20187c478bd9Sstevel@tonic-gate /* ARGSUSED */
20197c478bd9Sstevel@tonic-gate td_err_e
20207c478bd9Sstevel@tonic-gate __td_thr_getxregs(td_thrhandle_t *th_p, void *xregset)
20217c478bd9Sstevel@tonic-gate {
20227c478bd9Sstevel@tonic-gate #if defined(__sparc)
20237c478bd9Sstevel@tonic-gate 	struct ps_prochandle *ph_p;
20247c478bd9Sstevel@tonic-gate 	td_err_e return_val;
20257c478bd9Sstevel@tonic-gate 
20267c478bd9Sstevel@tonic-gate 	if ((ph_p = ph_lock_th(th_p, &return_val)) == NULL)
20277c478bd9Sstevel@tonic-gate 		return (return_val);
20287c478bd9Sstevel@tonic-gate 	if (ps_pstop(ph_p) != PS_OK) {
20297c478bd9Sstevel@tonic-gate 		ph_unlock(th_p->th_ta_p);
20307c478bd9Sstevel@tonic-gate 		return (TD_DBERR);
20317c478bd9Sstevel@tonic-gate 	}
20327c478bd9Sstevel@tonic-gate 
20337c478bd9Sstevel@tonic-gate 	if (ps_lgetxregs(ph_p, thr_to_lwpid(th_p), (caddr_t)xregset) != PS_OK)
20347c478bd9Sstevel@tonic-gate 		return_val = TD_DBERR;
20357c478bd9Sstevel@tonic-gate 
20367c478bd9Sstevel@tonic-gate 	(void) ps_pcontinue(ph_p);
20377c478bd9Sstevel@tonic-gate 	ph_unlock(th_p->th_ta_p);
20387c478bd9Sstevel@tonic-gate 	return (return_val);
20397c478bd9Sstevel@tonic-gate #else	/* __sparc */
20407c478bd9Sstevel@tonic-gate 	return (TD_NOXREGS);
20417c478bd9Sstevel@tonic-gate #endif	/* __sparc */
20427c478bd9Sstevel@tonic-gate }
20437c478bd9Sstevel@tonic-gate 
20447c478bd9Sstevel@tonic-gate /*
20457c478bd9Sstevel@tonic-gate  * Set a thread's extra state register set.
20467c478bd9Sstevel@tonic-gate  */
20477c478bd9Sstevel@tonic-gate #pragma weak td_thr_setxregs = __td_thr_setxregs
20487c478bd9Sstevel@tonic-gate /* ARGSUSED */
20497c478bd9Sstevel@tonic-gate td_err_e
20507c478bd9Sstevel@tonic-gate __td_thr_setxregs(td_thrhandle_t *th_p, const void *xregset)
20517c478bd9Sstevel@tonic-gate {
20527c478bd9Sstevel@tonic-gate #if defined(__sparc)
20537c478bd9Sstevel@tonic-gate 	struct ps_prochandle *ph_p;
20547c478bd9Sstevel@tonic-gate 	td_err_e return_val;
20557c478bd9Sstevel@tonic-gate 
20567c478bd9Sstevel@tonic-gate 	if ((ph_p = ph_lock_th(th_p, &return_val)) == NULL)
20577c478bd9Sstevel@tonic-gate 		return (return_val);
20587c478bd9Sstevel@tonic-gate 	if (ps_pstop(ph_p) != PS_OK) {
20597c478bd9Sstevel@tonic-gate 		ph_unlock(th_p->th_ta_p);
20607c478bd9Sstevel@tonic-gate 		return (TD_DBERR);
20617c478bd9Sstevel@tonic-gate 	}
20627c478bd9Sstevel@tonic-gate 
20637c478bd9Sstevel@tonic-gate 	if (ps_lsetxregs(ph_p, thr_to_lwpid(th_p), (caddr_t)xregset) != PS_OK)
20647c478bd9Sstevel@tonic-gate 		return_val = TD_DBERR;
20657c478bd9Sstevel@tonic-gate 
20667c478bd9Sstevel@tonic-gate 	(void) ps_pcontinue(ph_p);
20677c478bd9Sstevel@tonic-gate 	ph_unlock(th_p->th_ta_p);
20687c478bd9Sstevel@tonic-gate 	return (return_val);
20697c478bd9Sstevel@tonic-gate #else	/* __sparc */
20707c478bd9Sstevel@tonic-gate 	return (TD_NOXREGS);
20717c478bd9Sstevel@tonic-gate #endif	/* __sparc */
20727c478bd9Sstevel@tonic-gate }
20737c478bd9Sstevel@tonic-gate 
20747c478bd9Sstevel@tonic-gate struct searcher {
20757c478bd9Sstevel@tonic-gate 	psaddr_t	addr;
20767c478bd9Sstevel@tonic-gate 	int		status;
20777c478bd9Sstevel@tonic-gate };
20787c478bd9Sstevel@tonic-gate 
20797c478bd9Sstevel@tonic-gate /*
20807c478bd9Sstevel@tonic-gate  * Check the struct thread address in *th_p again first
20817c478bd9Sstevel@tonic-gate  * value in "data".  If value in data is found, set second value
20827c478bd9Sstevel@tonic-gate  * in "data" to 1 and return 1 to terminate iterations.
20837c478bd9Sstevel@tonic-gate  * This function is used by td_thr_validate() to verify that
20847c478bd9Sstevel@tonic-gate  * a thread handle is valid.
20857c478bd9Sstevel@tonic-gate  */
20867c478bd9Sstevel@tonic-gate static int
20877c478bd9Sstevel@tonic-gate td_searcher(const td_thrhandle_t *th_p, void *data)
20887c478bd9Sstevel@tonic-gate {
20897c478bd9Sstevel@tonic-gate 	struct searcher *searcher_data = (struct searcher *)data;
20907c478bd9Sstevel@tonic-gate 
20917c478bd9Sstevel@tonic-gate 	if (searcher_data->addr == th_p->th_unique) {
20927c478bd9Sstevel@tonic-gate 		searcher_data->status = 1;
20937c478bd9Sstevel@tonic-gate 		return (1);
20947c478bd9Sstevel@tonic-gate 	}
20957c478bd9Sstevel@tonic-gate 	return (0);
20967c478bd9Sstevel@tonic-gate }
20977c478bd9Sstevel@tonic-gate 
20987c478bd9Sstevel@tonic-gate /*
20997c478bd9Sstevel@tonic-gate  * Validate the thread handle.  Check that
21007c478bd9Sstevel@tonic-gate  * a thread exists in the thread agent/process that
21017c478bd9Sstevel@tonic-gate  * corresponds to thread with handle *th_p.
21027c478bd9Sstevel@tonic-gate  * Currently unused by dbx.
21037c478bd9Sstevel@tonic-gate  */
21047c478bd9Sstevel@tonic-gate #pragma weak td_thr_validate = __td_thr_validate
21057c478bd9Sstevel@tonic-gate td_err_e
21067c478bd9Sstevel@tonic-gate __td_thr_validate(const td_thrhandle_t *th_p)
21077c478bd9Sstevel@tonic-gate {
21087c478bd9Sstevel@tonic-gate 	td_err_e return_val;
21097c478bd9Sstevel@tonic-gate 	struct searcher searcher_data = {0, 0};
21107c478bd9Sstevel@tonic-gate 
21117c478bd9Sstevel@tonic-gate 	if (th_p == NULL)
21127c478bd9Sstevel@tonic-gate 		return (TD_BADTH);
21137c478bd9Sstevel@tonic-gate 	if (th_p->th_unique == NULL || th_p->th_ta_p == NULL)
21147c478bd9Sstevel@tonic-gate 		return (TD_BADTH);
21157c478bd9Sstevel@tonic-gate 
21167c478bd9Sstevel@tonic-gate 	/*
21177c478bd9Sstevel@tonic-gate 	 * LOCKING EXCEPTION - Locking is not required
21187c478bd9Sstevel@tonic-gate 	 * here because no use of the thread agent is made (other
21197c478bd9Sstevel@tonic-gate 	 * than the sanity check) and checking of the thread
21207c478bd9Sstevel@tonic-gate 	 * agent will be done in __td_ta_thr_iter.
21217c478bd9Sstevel@tonic-gate 	 */
21227c478bd9Sstevel@tonic-gate 
21237c478bd9Sstevel@tonic-gate 	searcher_data.addr = th_p->th_unique;
21247c478bd9Sstevel@tonic-gate 	return_val = __td_ta_thr_iter(th_p->th_ta_p,
21257c478bd9Sstevel@tonic-gate 	    td_searcher, &searcher_data,
21267c478bd9Sstevel@tonic-gate 	    TD_THR_ANY_STATE, TD_THR_LOWEST_PRIORITY,
21277c478bd9Sstevel@tonic-gate 	    TD_SIGNO_MASK, TD_THR_ANY_USER_FLAGS);
21287c478bd9Sstevel@tonic-gate 
21297c478bd9Sstevel@tonic-gate 	if (return_val == TD_OK && searcher_data.status == 0)
21307c478bd9Sstevel@tonic-gate 		return_val = TD_NOTHR;
21317c478bd9Sstevel@tonic-gate 
21327c478bd9Sstevel@tonic-gate 	return (return_val);
21337c478bd9Sstevel@tonic-gate }
21347c478bd9Sstevel@tonic-gate 
21357c478bd9Sstevel@tonic-gate /*
21367c478bd9Sstevel@tonic-gate  * Get a thread's private binding to a given thread specific
21377c478bd9Sstevel@tonic-gate  * data(TSD) key(see thr_getspecific(3T).  If the thread doesn't
21387c478bd9Sstevel@tonic-gate  * have a binding for a particular key, then NULL is returned.
21397c478bd9Sstevel@tonic-gate  */
21407c478bd9Sstevel@tonic-gate #pragma weak td_thr_tsd = __td_thr_tsd
21417c478bd9Sstevel@tonic-gate td_err_e
21427c478bd9Sstevel@tonic-gate __td_thr_tsd(td_thrhandle_t *th_p, thread_key_t key, void **data_pp)
21437c478bd9Sstevel@tonic-gate {
21447c478bd9Sstevel@tonic-gate 	struct ps_prochandle *ph_p;
21457c478bd9Sstevel@tonic-gate 	td_thragent_t	*ta_p;
21467c478bd9Sstevel@tonic-gate 	td_err_e	return_val;
21477c478bd9Sstevel@tonic-gate 	int		maxkey;
21487c478bd9Sstevel@tonic-gate 	int		nkey;
21497c478bd9Sstevel@tonic-gate 	psaddr_t	tsd_paddr;
21507c478bd9Sstevel@tonic-gate 
21517c478bd9Sstevel@tonic-gate 	if (data_pp == NULL)
21527c478bd9Sstevel@tonic-gate 		return (TD_ERR);
21537c478bd9Sstevel@tonic-gate 	*data_pp = NULL;
21547c478bd9Sstevel@tonic-gate 	if ((ph_p = ph_lock_th(th_p, &return_val)) == NULL)
21557c478bd9Sstevel@tonic-gate 		return (return_val);
21567c478bd9Sstevel@tonic-gate 	ta_p = th_p->th_ta_p;
21577c478bd9Sstevel@tonic-gate 	if (ps_pstop(ph_p) != PS_OK) {
21587c478bd9Sstevel@tonic-gate 		ph_unlock(ta_p);
21597c478bd9Sstevel@tonic-gate 		return (TD_DBERR);
21607c478bd9Sstevel@tonic-gate 	}
21617c478bd9Sstevel@tonic-gate 
21627c478bd9Sstevel@tonic-gate 	if (ta_p->model == PR_MODEL_NATIVE) {
21637c478bd9Sstevel@tonic-gate 		ulwp_t *ulwp = (ulwp_t *)th_p->th_unique;
21647c478bd9Sstevel@tonic-gate 		tsd_metadata_t tsdm;
21657c478bd9Sstevel@tonic-gate 		tsd_t stsd;
21667c478bd9Sstevel@tonic-gate 
21677c478bd9Sstevel@tonic-gate 		if (ps_pdread(ph_p,
21687c478bd9Sstevel@tonic-gate 		    ta_p->uberdata_addr + offsetof(uberdata_t, tsd_metadata),
21697c478bd9Sstevel@tonic-gate 		    &tsdm, sizeof (tsdm)) != PS_OK)
21707c478bd9Sstevel@tonic-gate 			return_val = TD_DBERR;
21717c478bd9Sstevel@tonic-gate 		else if (ps_pdread(ph_p, (psaddr_t)&ulwp->ul_stsd,
21727c478bd9Sstevel@tonic-gate 		    &tsd_paddr, sizeof (tsd_paddr)) != PS_OK)
21737c478bd9Sstevel@tonic-gate 			return_val = TD_DBERR;
21747c478bd9Sstevel@tonic-gate 		else if (tsd_paddr != NULL &&
21757c478bd9Sstevel@tonic-gate 		    ps_pdread(ph_p, tsd_paddr, &stsd, sizeof (stsd)) != PS_OK)
21767c478bd9Sstevel@tonic-gate 			return_val = TD_DBERR;
21777c478bd9Sstevel@tonic-gate 		else {
21787c478bd9Sstevel@tonic-gate 			maxkey = tsdm.tsdm_nused;
21797c478bd9Sstevel@tonic-gate 			nkey = tsd_paddr == NULL ? TSD_NFAST : stsd.tsd_nalloc;
21807c478bd9Sstevel@tonic-gate 
21817c478bd9Sstevel@tonic-gate 			if (key < TSD_NFAST)
21827c478bd9Sstevel@tonic-gate 				tsd_paddr = (psaddr_t)&ulwp->ul_ftsd[0];
21837c478bd9Sstevel@tonic-gate 		}
21847c478bd9Sstevel@tonic-gate 	} else {
21857c478bd9Sstevel@tonic-gate #if defined(_LP64) && defined(_SYSCALL32)
21867c478bd9Sstevel@tonic-gate 		ulwp32_t *ulwp = (ulwp32_t *)th_p->th_unique;
21877c478bd9Sstevel@tonic-gate 		tsd_metadata32_t tsdm;
21887c478bd9Sstevel@tonic-gate 		tsd32_t stsd;
21897c478bd9Sstevel@tonic-gate 		caddr32_t addr;
21907c478bd9Sstevel@tonic-gate 
21917c478bd9Sstevel@tonic-gate 		if (ps_pdread(ph_p,
21927c478bd9Sstevel@tonic-gate 		    ta_p->uberdata_addr + offsetof(uberdata32_t, tsd_metadata),
21937c478bd9Sstevel@tonic-gate 		    &tsdm, sizeof (tsdm)) != PS_OK)
21947c478bd9Sstevel@tonic-gate 			return_val = TD_DBERR;
21957c478bd9Sstevel@tonic-gate 		else if (ps_pdread(ph_p, (psaddr_t)&ulwp->ul_stsd,
21967c478bd9Sstevel@tonic-gate 		    &addr, sizeof (addr)) != PS_OK)
21977c478bd9Sstevel@tonic-gate 			return_val = TD_DBERR;
21987c478bd9Sstevel@tonic-gate 		else if (addr != NULL &&
21997c478bd9Sstevel@tonic-gate 		    ps_pdread(ph_p, addr, &stsd, sizeof (stsd)) != PS_OK)
22007c478bd9Sstevel@tonic-gate 			return_val = TD_DBERR;
22017c478bd9Sstevel@tonic-gate 		else {
22027c478bd9Sstevel@tonic-gate 			maxkey = tsdm.tsdm_nused;
22037c478bd9Sstevel@tonic-gate 			nkey = addr == NULL ? TSD_NFAST : stsd.tsd_nalloc;
22047c478bd9Sstevel@tonic-gate 
22057c478bd9Sstevel@tonic-gate 			if (key < TSD_NFAST) {
22067c478bd9Sstevel@tonic-gate 				tsd_paddr = (psaddr_t)&ulwp->ul_ftsd[0];
22077c478bd9Sstevel@tonic-gate 			} else {
22087c478bd9Sstevel@tonic-gate 				tsd_paddr = addr;
22097c478bd9Sstevel@tonic-gate 			}
22107c478bd9Sstevel@tonic-gate 		}
22117c478bd9Sstevel@tonic-gate #else
22127c478bd9Sstevel@tonic-gate 		return_val = TD_ERR;
22137c478bd9Sstevel@tonic-gate #endif	/* _SYSCALL32 */
22147c478bd9Sstevel@tonic-gate 	}
22157c478bd9Sstevel@tonic-gate 
22167c478bd9Sstevel@tonic-gate 	if (return_val == TD_OK && (key < 1 || key >= maxkey))
22177c478bd9Sstevel@tonic-gate 		return_val = TD_NOTSD;
22187c478bd9Sstevel@tonic-gate 	if (return_val != TD_OK || key >= nkey) {
22197c478bd9Sstevel@tonic-gate 		/* NULL has already been stored in data_pp */
22207c478bd9Sstevel@tonic-gate 		(void) ps_pcontinue(ph_p);
22217c478bd9Sstevel@tonic-gate 		ph_unlock(ta_p);
22227c478bd9Sstevel@tonic-gate 		return (return_val);
22237c478bd9Sstevel@tonic-gate 	}
22247c478bd9Sstevel@tonic-gate 
22257c478bd9Sstevel@tonic-gate 	/*
22267c478bd9Sstevel@tonic-gate 	 * Read the value from the thread's tsd array.
22277c478bd9Sstevel@tonic-gate 	 */
22287c478bd9Sstevel@tonic-gate 	if (ta_p->model == PR_MODEL_NATIVE) {
22297c478bd9Sstevel@tonic-gate 		void *value;
22307c478bd9Sstevel@tonic-gate 
22317c478bd9Sstevel@tonic-gate 		if (ps_pdread(ph_p, tsd_paddr + key * sizeof (void *),
22327c478bd9Sstevel@tonic-gate 		    &value, sizeof (value)) != PS_OK)
22337c478bd9Sstevel@tonic-gate 			return_val = TD_DBERR;
22347c478bd9Sstevel@tonic-gate 		else
22357c478bd9Sstevel@tonic-gate 			*data_pp = value;
22367c478bd9Sstevel@tonic-gate #if defined(_LP64) && defined(_SYSCALL32)
22377c478bd9Sstevel@tonic-gate 	} else {
22387c478bd9Sstevel@tonic-gate 		caddr32_t value32;
22397c478bd9Sstevel@tonic-gate 
22407c478bd9Sstevel@tonic-gate 		if (ps_pdread(ph_p, tsd_paddr + key * sizeof (caddr32_t),
22417c478bd9Sstevel@tonic-gate 		    &value32, sizeof (value32)) != PS_OK)
22427c478bd9Sstevel@tonic-gate 			return_val = TD_DBERR;
22437c478bd9Sstevel@tonic-gate 		else
22447c478bd9Sstevel@tonic-gate 			*data_pp = (void *)(uintptr_t)value32;
22457c478bd9Sstevel@tonic-gate #endif	/* _SYSCALL32 */
22467c478bd9Sstevel@tonic-gate 	}
22477c478bd9Sstevel@tonic-gate 
22487c478bd9Sstevel@tonic-gate 	(void) ps_pcontinue(ph_p);
22497c478bd9Sstevel@tonic-gate 	ph_unlock(ta_p);
22507c478bd9Sstevel@tonic-gate 	return (return_val);
22517c478bd9Sstevel@tonic-gate }
22527c478bd9Sstevel@tonic-gate 
22537c478bd9Sstevel@tonic-gate /*
22547c478bd9Sstevel@tonic-gate  * Get the base address of a thread's thread local storage (TLS) block
22557c478bd9Sstevel@tonic-gate  * for the module (executable or shared object) identified by 'moduleid'.
22567c478bd9Sstevel@tonic-gate  */
22577c478bd9Sstevel@tonic-gate #pragma weak td_thr_tlsbase = __td_thr_tlsbase
22587c478bd9Sstevel@tonic-gate td_err_e
22597c478bd9Sstevel@tonic-gate __td_thr_tlsbase(td_thrhandle_t *th_p, ulong_t moduleid, psaddr_t *base)
22607c478bd9Sstevel@tonic-gate {
22617c478bd9Sstevel@tonic-gate 	struct ps_prochandle *ph_p;
22627c478bd9Sstevel@tonic-gate 	td_thragent_t	*ta_p;
22637c478bd9Sstevel@tonic-gate 	td_err_e	return_val;
22647c478bd9Sstevel@tonic-gate 
22657c478bd9Sstevel@tonic-gate 	if (base == NULL)
22667c478bd9Sstevel@tonic-gate 		return (TD_ERR);
22677c478bd9Sstevel@tonic-gate 	*base = NULL;
22687c478bd9Sstevel@tonic-gate 	if ((ph_p = ph_lock_th(th_p, &return_val)) == NULL)
22697c478bd9Sstevel@tonic-gate 		return (return_val);
22707c478bd9Sstevel@tonic-gate 	ta_p = th_p->th_ta_p;
22717c478bd9Sstevel@tonic-gate 	if (ps_pstop(ph_p) != PS_OK) {
22727c478bd9Sstevel@tonic-gate 		ph_unlock(ta_p);
22737c478bd9Sstevel@tonic-gate 		return (TD_DBERR);
22747c478bd9Sstevel@tonic-gate 	}
22757c478bd9Sstevel@tonic-gate 
22767c478bd9Sstevel@tonic-gate 	if (ta_p->model == PR_MODEL_NATIVE) {
22777c478bd9Sstevel@tonic-gate 		ulwp_t *ulwp = (ulwp_t *)th_p->th_unique;
22787c478bd9Sstevel@tonic-gate 		tls_metadata_t tls_metadata;
22797c478bd9Sstevel@tonic-gate 		TLS_modinfo tlsmod;
22807c478bd9Sstevel@tonic-gate 		tls_t tls;
22817c478bd9Sstevel@tonic-gate 
22827c478bd9Sstevel@tonic-gate 		if (ps_pdread(ph_p,
22837c478bd9Sstevel@tonic-gate 		    ta_p->uberdata_addr + offsetof(uberdata_t, tls_metadata),
22847c478bd9Sstevel@tonic-gate 		    &tls_metadata, sizeof (tls_metadata)) != PS_OK)
22857c478bd9Sstevel@tonic-gate 			return_val = TD_DBERR;
22867c478bd9Sstevel@tonic-gate 		else if (moduleid >= tls_metadata.tls_modinfo.tls_size)
22877c478bd9Sstevel@tonic-gate 			return_val = TD_NOTLS;
22887c478bd9Sstevel@tonic-gate 		else if (ps_pdread(ph_p,
22897c478bd9Sstevel@tonic-gate 		    (psaddr_t)((TLS_modinfo *)
22907c478bd9Sstevel@tonic-gate 		    tls_metadata.tls_modinfo.tls_data + moduleid),
22917c478bd9Sstevel@tonic-gate 		    &tlsmod, sizeof (tlsmod)) != PS_OK)
22927c478bd9Sstevel@tonic-gate 			return_val = TD_DBERR;
22937c478bd9Sstevel@tonic-gate 		else if (tlsmod.tm_memsz == 0)
22947c478bd9Sstevel@tonic-gate 			return_val = TD_NOTLS;
22957c478bd9Sstevel@tonic-gate 		else if (tlsmod.tm_flags & TM_FLG_STATICTLS)
22967c478bd9Sstevel@tonic-gate 			*base = (psaddr_t)ulwp - tlsmod.tm_stattlsoffset;
22977c478bd9Sstevel@tonic-gate 		else if (ps_pdread(ph_p, (psaddr_t)&ulwp->ul_tls,
22987c478bd9Sstevel@tonic-gate 		    &tls, sizeof (tls)) != PS_OK)
22997c478bd9Sstevel@tonic-gate 			return_val = TD_DBERR;
23007c478bd9Sstevel@tonic-gate 		else if (moduleid >= tls.tls_size)
23017c478bd9Sstevel@tonic-gate 			return_val = TD_TLSDEFER;
23027c478bd9Sstevel@tonic-gate 		else if (ps_pdread(ph_p,
23037c478bd9Sstevel@tonic-gate 		    (psaddr_t)((tls_t *)tls.tls_data + moduleid),
23047c478bd9Sstevel@tonic-gate 		    &tls, sizeof (tls)) != PS_OK)
23057c478bd9Sstevel@tonic-gate 			return_val = TD_DBERR;
23067c478bd9Sstevel@tonic-gate 		else if (tls.tls_size == 0)
23077c478bd9Sstevel@tonic-gate 			return_val = TD_TLSDEFER;
23087c478bd9Sstevel@tonic-gate 		else
23097c478bd9Sstevel@tonic-gate 			*base = (psaddr_t)tls.tls_data;
23107c478bd9Sstevel@tonic-gate 	} else {
23117c478bd9Sstevel@tonic-gate #if defined(_LP64) && defined(_SYSCALL32)
23127c478bd9Sstevel@tonic-gate 		ulwp32_t *ulwp = (ulwp32_t *)th_p->th_unique;
23137c478bd9Sstevel@tonic-gate 		tls_metadata32_t tls_metadata;
23147c478bd9Sstevel@tonic-gate 		TLS_modinfo32 tlsmod;
23157c478bd9Sstevel@tonic-gate 		tls32_t tls;
23167c478bd9Sstevel@tonic-gate 
23177c478bd9Sstevel@tonic-gate 		if (ps_pdread(ph_p,
23187c478bd9Sstevel@tonic-gate 		    ta_p->uberdata_addr + offsetof(uberdata32_t, tls_metadata),
23197c478bd9Sstevel@tonic-gate 		    &tls_metadata, sizeof (tls_metadata)) != PS_OK)
23207c478bd9Sstevel@tonic-gate 			return_val = TD_DBERR;
23217c478bd9Sstevel@tonic-gate 		else if (moduleid >= tls_metadata.tls_modinfo.tls_size)
23227c478bd9Sstevel@tonic-gate 			return_val = TD_NOTLS;
23237c478bd9Sstevel@tonic-gate 		else if (ps_pdread(ph_p,
23247c478bd9Sstevel@tonic-gate 		    (psaddr_t)((TLS_modinfo32 *)
23257c478bd9Sstevel@tonic-gate 		    (uintptr_t)tls_metadata.tls_modinfo.tls_data + moduleid),
23267c478bd9Sstevel@tonic-gate 		    &tlsmod, sizeof (tlsmod)) != PS_OK)
23277c478bd9Sstevel@tonic-gate 			return_val = TD_DBERR;
23287c478bd9Sstevel@tonic-gate 		else if (tlsmod.tm_memsz == 0)
23297c478bd9Sstevel@tonic-gate 			return_val = TD_NOTLS;
23307c478bd9Sstevel@tonic-gate 		else if (tlsmod.tm_flags & TM_FLG_STATICTLS)
23317c478bd9Sstevel@tonic-gate 			*base = (psaddr_t)ulwp - tlsmod.tm_stattlsoffset;
23327c478bd9Sstevel@tonic-gate 		else if (ps_pdread(ph_p, (psaddr_t)&ulwp->ul_tls,
23337c478bd9Sstevel@tonic-gate 		    &tls, sizeof (tls)) != PS_OK)
23347c478bd9Sstevel@tonic-gate 			return_val = TD_DBERR;
23357c478bd9Sstevel@tonic-gate 		else if (moduleid >= tls.tls_size)
23367c478bd9Sstevel@tonic-gate 			return_val = TD_TLSDEFER;
23377c478bd9Sstevel@tonic-gate 		else if (ps_pdread(ph_p,
23387c478bd9Sstevel@tonic-gate 		    (psaddr_t)((tls32_t *)(uintptr_t)tls.tls_data + moduleid),
23397c478bd9Sstevel@tonic-gate 		    &tls, sizeof (tls)) != PS_OK)
23407c478bd9Sstevel@tonic-gate 			return_val = TD_DBERR;
23417c478bd9Sstevel@tonic-gate 		else if (tls.tls_size == 0)
23427c478bd9Sstevel@tonic-gate 			return_val = TD_TLSDEFER;
23437c478bd9Sstevel@tonic-gate 		else
23447c478bd9Sstevel@tonic-gate 			*base = (psaddr_t)tls.tls_data;
23457c478bd9Sstevel@tonic-gate #else
23467c478bd9Sstevel@tonic-gate 		return_val = TD_ERR;
23477c478bd9Sstevel@tonic-gate #endif	/* _SYSCALL32 */
23487c478bd9Sstevel@tonic-gate 	}
23497c478bd9Sstevel@tonic-gate 
23507c478bd9Sstevel@tonic-gate 	(void) ps_pcontinue(ph_p);
23517c478bd9Sstevel@tonic-gate 	ph_unlock(ta_p);
23527c478bd9Sstevel@tonic-gate 	return (return_val);
23537c478bd9Sstevel@tonic-gate }
23547c478bd9Sstevel@tonic-gate 
23557c478bd9Sstevel@tonic-gate /*
23567c478bd9Sstevel@tonic-gate  * Change a thread's priority to the value specified by ti_pri.
23577c478bd9Sstevel@tonic-gate  * Currently unused by dbx.
23587c478bd9Sstevel@tonic-gate  */
23597c478bd9Sstevel@tonic-gate #pragma weak td_thr_setprio = __td_thr_setprio
2360d4204c85Sraf /* ARGSUSED */
23617c478bd9Sstevel@tonic-gate td_err_e
23627c478bd9Sstevel@tonic-gate __td_thr_setprio(td_thrhandle_t *th_p, int ti_pri)
23637c478bd9Sstevel@tonic-gate {
2364d4204c85Sraf 	return (TD_NOCAPAB);
23657c478bd9Sstevel@tonic-gate }
23667c478bd9Sstevel@tonic-gate 
23677c478bd9Sstevel@tonic-gate /*
23687c478bd9Sstevel@tonic-gate  * This structure links td_thr_lockowner and the lowner_cb callback function.
23697c478bd9Sstevel@tonic-gate  */
23707c478bd9Sstevel@tonic-gate typedef struct {
23717c478bd9Sstevel@tonic-gate 	td_sync_iter_f	*owner_cb;
23727c478bd9Sstevel@tonic-gate 	void		*owner_cb_arg;
23737c478bd9Sstevel@tonic-gate 	td_thrhandle_t	*th_p;
23747c478bd9Sstevel@tonic-gate } lowner_cb_ctl_t;
23757c478bd9Sstevel@tonic-gate 
23767c478bd9Sstevel@tonic-gate static int
23777c478bd9Sstevel@tonic-gate lowner_cb(const td_synchandle_t *sh_p, void *arg)
23787c478bd9Sstevel@tonic-gate {
23797c478bd9Sstevel@tonic-gate 	lowner_cb_ctl_t *ocb = arg;
23807c478bd9Sstevel@tonic-gate 	int trunc = 0;
23817c478bd9Sstevel@tonic-gate 	union {
23827c478bd9Sstevel@tonic-gate 		rwlock_t rwl;
23837c478bd9Sstevel@tonic-gate 		mutex_t mx;
23847c478bd9Sstevel@tonic-gate 	} rw_m;
23857c478bd9Sstevel@tonic-gate 
23867c478bd9Sstevel@tonic-gate 	if (ps_pdread(sh_p->sh_ta_p->ph_p, sh_p->sh_unique,
23877c478bd9Sstevel@tonic-gate 	    &rw_m, sizeof (rw_m)) != PS_OK) {
23887c478bd9Sstevel@tonic-gate 		trunc = 1;
23897c478bd9Sstevel@tonic-gate 		if (ps_pdread(sh_p->sh_ta_p->ph_p, sh_p->sh_unique,
23907c478bd9Sstevel@tonic-gate 		    &rw_m.mx, sizeof (rw_m.mx)) != PS_OK)
23917c478bd9Sstevel@tonic-gate 			return (0);
23927c478bd9Sstevel@tonic-gate 	}
23937c478bd9Sstevel@tonic-gate 	if (rw_m.mx.mutex_magic == MUTEX_MAGIC &&
23947c478bd9Sstevel@tonic-gate 	    rw_m.mx.mutex_owner == ocb->th_p->th_unique)
23957c478bd9Sstevel@tonic-gate 		return ((ocb->owner_cb)(sh_p, ocb->owner_cb_arg));
23967c478bd9Sstevel@tonic-gate 	if (!trunc && rw_m.rwl.magic == RWL_MAGIC) {
23977c478bd9Sstevel@tonic-gate 		mutex_t *rwlock = &rw_m.rwl.mutex;
23987c478bd9Sstevel@tonic-gate 		if (rwlock->mutex_owner == ocb->th_p->th_unique)
23997c478bd9Sstevel@tonic-gate 			return ((ocb->owner_cb)(sh_p, ocb->owner_cb_arg));
24007c478bd9Sstevel@tonic-gate 	}
24017c478bd9Sstevel@tonic-gate 	return (0);
24027c478bd9Sstevel@tonic-gate }
24037c478bd9Sstevel@tonic-gate 
24047c478bd9Sstevel@tonic-gate /*
24057c478bd9Sstevel@tonic-gate  * Iterate over the set of locks owned by a specified thread.
24067c478bd9Sstevel@tonic-gate  * If cb returns a non-zero value, terminate iterations.
24077c478bd9Sstevel@tonic-gate  */
24087c478bd9Sstevel@tonic-gate #pragma weak td_thr_lockowner = __td_thr_lockowner
24097c478bd9Sstevel@tonic-gate td_err_e
24107c478bd9Sstevel@tonic-gate __td_thr_lockowner(const td_thrhandle_t *th_p, td_sync_iter_f *cb,
24117c478bd9Sstevel@tonic-gate 	void *cb_data)
24127c478bd9Sstevel@tonic-gate {
24137c478bd9Sstevel@tonic-gate 	td_thragent_t	*ta_p;
24147c478bd9Sstevel@tonic-gate 	td_err_e	return_val;
24157c478bd9Sstevel@tonic-gate 	lowner_cb_ctl_t	lcb;
24167c478bd9Sstevel@tonic-gate 
24177c478bd9Sstevel@tonic-gate 	/*
24187c478bd9Sstevel@tonic-gate 	 * Just sanity checks.
24197c478bd9Sstevel@tonic-gate 	 */
24207c478bd9Sstevel@tonic-gate 	if (ph_lock_th((td_thrhandle_t *)th_p, &return_val) == NULL)
24217c478bd9Sstevel@tonic-gate 		return (return_val);
24227c478bd9Sstevel@tonic-gate 	ta_p = th_p->th_ta_p;
24237c478bd9Sstevel@tonic-gate 	ph_unlock(ta_p);
24247c478bd9Sstevel@tonic-gate 
24257c478bd9Sstevel@tonic-gate 	lcb.owner_cb = cb;
24267c478bd9Sstevel@tonic-gate 	lcb.owner_cb_arg = cb_data;
24277c478bd9Sstevel@tonic-gate 	lcb.th_p = (td_thrhandle_t *)th_p;
24287c478bd9Sstevel@tonic-gate 	return (__td_ta_sync_iter(ta_p, lowner_cb, &lcb));
24297c478bd9Sstevel@tonic-gate }
24307c478bd9Sstevel@tonic-gate 
24317c478bd9Sstevel@tonic-gate /*
24327c478bd9Sstevel@tonic-gate  * If a thread is asleep on a synchronization variable,
24337c478bd9Sstevel@tonic-gate  * then get the synchronization handle.
24347c478bd9Sstevel@tonic-gate  */
24357c478bd9Sstevel@tonic-gate #pragma weak td_thr_sleepinfo = __td_thr_sleepinfo
24367c478bd9Sstevel@tonic-gate td_err_e
24377c478bd9Sstevel@tonic-gate __td_thr_sleepinfo(const td_thrhandle_t *th_p, td_synchandle_t *sh_p)
24387c478bd9Sstevel@tonic-gate {
24397c478bd9Sstevel@tonic-gate 	struct ps_prochandle *ph_p;
24407c478bd9Sstevel@tonic-gate 	td_err_e	return_val = TD_OK;
24417c478bd9Sstevel@tonic-gate 	uintptr_t	wchan;
24427c478bd9Sstevel@tonic-gate 
24437c478bd9Sstevel@tonic-gate 	if (sh_p == NULL)
24447c478bd9Sstevel@tonic-gate 		return (TD_ERR);
24457c478bd9Sstevel@tonic-gate 	if ((ph_p = ph_lock_th((td_thrhandle_t *)th_p, &return_val)) == NULL)
24467c478bd9Sstevel@tonic-gate 		return (return_val);
24477c478bd9Sstevel@tonic-gate 
24487c478bd9Sstevel@tonic-gate 	/*
24497c478bd9Sstevel@tonic-gate 	 * No need to stop the process for a simple read.
24507c478bd9Sstevel@tonic-gate 	 */
24517c478bd9Sstevel@tonic-gate 	if (th_p->th_ta_p->model == PR_MODEL_NATIVE) {
24527c478bd9Sstevel@tonic-gate 		ulwp_t *ulwp = (ulwp_t *)th_p->th_unique;
24537c478bd9Sstevel@tonic-gate 
24547c478bd9Sstevel@tonic-gate 		if (ps_pdread(ph_p, (psaddr_t)&ulwp->ul_wchan,
24557c478bd9Sstevel@tonic-gate 		    &wchan, sizeof (wchan)) != PS_OK)
24567c478bd9Sstevel@tonic-gate 			return_val = TD_DBERR;
24577c478bd9Sstevel@tonic-gate 	} else {
24587c478bd9Sstevel@tonic-gate #if defined(_LP64) && defined(_SYSCALL32)
24597c478bd9Sstevel@tonic-gate 		ulwp32_t *ulwp = (ulwp32_t *)th_p->th_unique;
24607c478bd9Sstevel@tonic-gate 		caddr32_t wchan32;
24617c478bd9Sstevel@tonic-gate 
24627c478bd9Sstevel@tonic-gate 		if (ps_pdread(ph_p, (psaddr_t)&ulwp->ul_wchan,
24637c478bd9Sstevel@tonic-gate 		    &wchan32, sizeof (wchan32)) != PS_OK)
24647c478bd9Sstevel@tonic-gate 			return_val = TD_DBERR;
24657c478bd9Sstevel@tonic-gate 		wchan = wchan32;
24667c478bd9Sstevel@tonic-gate #else
24677c478bd9Sstevel@tonic-gate 		return_val = TD_ERR;
24687c478bd9Sstevel@tonic-gate #endif	/* _SYSCALL32 */
24697c478bd9Sstevel@tonic-gate 	}
24707c478bd9Sstevel@tonic-gate 
24717c478bd9Sstevel@tonic-gate 	if (return_val != TD_OK || wchan == NULL) {
24727c478bd9Sstevel@tonic-gate 		sh_p->sh_ta_p = NULL;
24737c478bd9Sstevel@tonic-gate 		sh_p->sh_unique = NULL;
24747c478bd9Sstevel@tonic-gate 		if (return_val == TD_OK)
24757c478bd9Sstevel@tonic-gate 			return_val = TD_ERR;
24767c478bd9Sstevel@tonic-gate 	} else {
24777c478bd9Sstevel@tonic-gate 		sh_p->sh_ta_p = th_p->th_ta_p;
24787c478bd9Sstevel@tonic-gate 		sh_p->sh_unique = (psaddr_t)wchan;
24797c478bd9Sstevel@tonic-gate 	}
24807c478bd9Sstevel@tonic-gate 
24817c478bd9Sstevel@tonic-gate 	ph_unlock(th_p->th_ta_p);
24827c478bd9Sstevel@tonic-gate 	return (return_val);
24837c478bd9Sstevel@tonic-gate }
24847c478bd9Sstevel@tonic-gate 
24857c478bd9Sstevel@tonic-gate /*
24867c478bd9Sstevel@tonic-gate  * Which thread is running on an lwp?
24877c478bd9Sstevel@tonic-gate  */
24887c478bd9Sstevel@tonic-gate #pragma weak td_ta_map_lwp2thr = __td_ta_map_lwp2thr
24897c478bd9Sstevel@tonic-gate td_err_e
24907c478bd9Sstevel@tonic-gate __td_ta_map_lwp2thr(td_thragent_t *ta_p, lwpid_t lwpid,
24917c478bd9Sstevel@tonic-gate 	td_thrhandle_t *th_p)
24927c478bd9Sstevel@tonic-gate {
24937c478bd9Sstevel@tonic-gate 	return (__td_ta_map_id2thr(ta_p, lwpid, th_p));
24947c478bd9Sstevel@tonic-gate }
24957c478bd9Sstevel@tonic-gate 
24967c478bd9Sstevel@tonic-gate /*
24977c478bd9Sstevel@tonic-gate  * Common code for td_sync_get_info() and td_sync_get_stats()
24987c478bd9Sstevel@tonic-gate  */
24997c478bd9Sstevel@tonic-gate static td_err_e
25007c478bd9Sstevel@tonic-gate sync_get_info_common(const td_synchandle_t *sh_p, struct ps_prochandle *ph_p,
25017c478bd9Sstevel@tonic-gate 	td_syncinfo_t *si_p)
25027c478bd9Sstevel@tonic-gate {
25037c478bd9Sstevel@tonic-gate 	int trunc = 0;
25047c478bd9Sstevel@tonic-gate 	td_so_un_t generic_so;
25057c478bd9Sstevel@tonic-gate 
25067c478bd9Sstevel@tonic-gate 	/*
25077c478bd9Sstevel@tonic-gate 	 * Determine the sync. object type; a little type fudgery here.
25087c478bd9Sstevel@tonic-gate 	 * First attempt to read the whole union.  If that fails, attempt
25097c478bd9Sstevel@tonic-gate 	 * to read just the condvar.  A condvar is the smallest sync. object.
25107c478bd9Sstevel@tonic-gate 	 */
25117c478bd9Sstevel@tonic-gate 	if (ps_pdread(ph_p, sh_p->sh_unique,
25127c478bd9Sstevel@tonic-gate 	    &generic_so, sizeof (generic_so)) != PS_OK) {
25137c478bd9Sstevel@tonic-gate 		trunc = 1;
25147c478bd9Sstevel@tonic-gate 		if (ps_pdread(ph_p, sh_p->sh_unique, &generic_so.condition,
25157c478bd9Sstevel@tonic-gate 		    sizeof (generic_so.condition)) != PS_OK)
25167c478bd9Sstevel@tonic-gate 			return (TD_DBERR);
25177c478bd9Sstevel@tonic-gate 	}
25187c478bd9Sstevel@tonic-gate 
25197c478bd9Sstevel@tonic-gate 	switch (generic_so.condition.cond_magic) {
25207c478bd9Sstevel@tonic-gate 	case MUTEX_MAGIC:
25217c478bd9Sstevel@tonic-gate 		if (trunc && ps_pdread(ph_p, sh_p->sh_unique,
25227c478bd9Sstevel@tonic-gate 		    &generic_so.lock, sizeof (generic_so.lock)) != PS_OK)
25237c478bd9Sstevel@tonic-gate 			return (TD_DBERR);
25247c478bd9Sstevel@tonic-gate 		si_p->si_type = TD_SYNC_MUTEX;
2525883492d5Sraf 		si_p->si_shared_type =
2526883492d5Sraf 		    (generic_so.lock.mutex_type & USYNC_PROCESS);
25277c478bd9Sstevel@tonic-gate 		(void) memcpy(si_p->si_flags, &generic_so.lock.mutex_flag,
25287c478bd9Sstevel@tonic-gate 		    sizeof (generic_so.lock.mutex_flag));
25297c478bd9Sstevel@tonic-gate 		si_p->si_state.mutex_locked =
25307c478bd9Sstevel@tonic-gate 		    (generic_so.lock.mutex_lockw != 0);
25317c478bd9Sstevel@tonic-gate 		si_p->si_size = sizeof (generic_so.lock);
25327c478bd9Sstevel@tonic-gate 		si_p->si_has_waiters = generic_so.lock.mutex_waiters;
25337c478bd9Sstevel@tonic-gate 		si_p->si_rcount = generic_so.lock.mutex_rcount;
25347c478bd9Sstevel@tonic-gate 		si_p->si_prioceiling = generic_so.lock.mutex_ceiling;
25357c478bd9Sstevel@tonic-gate 		if (si_p->si_state.mutex_locked) {
2536883492d5Sraf 			if (si_p->si_shared_type & USYNC_PROCESS)
25377c478bd9Sstevel@tonic-gate 				si_p->si_ownerpid =
25387c478bd9Sstevel@tonic-gate 				    generic_so.lock.mutex_ownerpid;
25397c478bd9Sstevel@tonic-gate 			si_p->si_owner.th_ta_p = sh_p->sh_ta_p;
25407c478bd9Sstevel@tonic-gate 			si_p->si_owner.th_unique = generic_so.lock.mutex_owner;
25417c478bd9Sstevel@tonic-gate 		}
25427c478bd9Sstevel@tonic-gate 		break;
25437c478bd9Sstevel@tonic-gate 	case COND_MAGIC:
25447c478bd9Sstevel@tonic-gate 		si_p->si_type = TD_SYNC_COND;
2545883492d5Sraf 		si_p->si_shared_type =
2546883492d5Sraf 		    (generic_so.condition.cond_type & USYNC_PROCESS);
25477c478bd9Sstevel@tonic-gate 		(void) memcpy(si_p->si_flags, generic_so.condition.flags.flag,
25487c478bd9Sstevel@tonic-gate 		    sizeof (generic_so.condition.flags.flag));
25497c478bd9Sstevel@tonic-gate 		si_p->si_size = sizeof (generic_so.condition);
25507c478bd9Sstevel@tonic-gate 		si_p->si_has_waiters =
25517c478bd9Sstevel@tonic-gate 		    (generic_so.condition.cond_waiters_user |
25527c478bd9Sstevel@tonic-gate 		    generic_so.condition.cond_waiters_kernel)? 1 : 0;
25537c478bd9Sstevel@tonic-gate 		break;
25547c478bd9Sstevel@tonic-gate 	case SEMA_MAGIC:
25557c478bd9Sstevel@tonic-gate 		if (trunc && ps_pdread(ph_p, sh_p->sh_unique,
25567c478bd9Sstevel@tonic-gate 		    &generic_so.semaphore, sizeof (generic_so.semaphore))
25577c478bd9Sstevel@tonic-gate 		    != PS_OK)
25587c478bd9Sstevel@tonic-gate 			return (TD_DBERR);
25597c478bd9Sstevel@tonic-gate 		si_p->si_type = TD_SYNC_SEMA;
2560883492d5Sraf 		si_p->si_shared_type =
2561883492d5Sraf 		    (generic_so.semaphore.type & USYNC_PROCESS);
25627c478bd9Sstevel@tonic-gate 		si_p->si_state.sem_count = generic_so.semaphore.count;
25637c478bd9Sstevel@tonic-gate 		si_p->si_size = sizeof (generic_so.semaphore);
25647c478bd9Sstevel@tonic-gate 		si_p->si_has_waiters =
25657c478bd9Sstevel@tonic-gate 		    ((lwp_sema_t *)&generic_so.semaphore)->flags[7];
25667c478bd9Sstevel@tonic-gate 		/* this is useless but the old interface provided it */
25677c478bd9Sstevel@tonic-gate 		si_p->si_data = (psaddr_t)generic_so.semaphore.count;
25687c478bd9Sstevel@tonic-gate 		break;
25697c478bd9Sstevel@tonic-gate 	case RWL_MAGIC:
257041efec22Sraf 	{
257141efec22Sraf 		uint32_t rwstate;
257241efec22Sraf 
25737c478bd9Sstevel@tonic-gate 		if (trunc && ps_pdread(ph_p, sh_p->sh_unique,
25747c478bd9Sstevel@tonic-gate 		    &generic_so.rwlock, sizeof (generic_so.rwlock)) != PS_OK)
25757c478bd9Sstevel@tonic-gate 			return (TD_DBERR);
25767c478bd9Sstevel@tonic-gate 		si_p->si_type = TD_SYNC_RWLOCK;
2577883492d5Sraf 		si_p->si_shared_type =
2578883492d5Sraf 		    (generic_so.rwlock.rwlock_type & USYNC_PROCESS);
25797c478bd9Sstevel@tonic-gate 		si_p->si_size = sizeof (generic_so.rwlock);
25807c478bd9Sstevel@tonic-gate 
258141efec22Sraf 		rwstate = (uint32_t)generic_so.rwlock.rwlock_readers;
258241efec22Sraf 		if (rwstate & URW_WRITE_LOCKED) {
25837c478bd9Sstevel@tonic-gate 			si_p->si_state.nreaders = -1;
25847c478bd9Sstevel@tonic-gate 			si_p->si_is_wlock = 1;
25857c478bd9Sstevel@tonic-gate 			si_p->si_owner.th_ta_p = sh_p->sh_ta_p;
25867c478bd9Sstevel@tonic-gate 			si_p->si_owner.th_unique =
25877c478bd9Sstevel@tonic-gate 			    generic_so.rwlock.rwlock_owner;
258841efec22Sraf 			if (si_p->si_shared_type & USYNC_PROCESS)
258941efec22Sraf 				si_p->si_ownerpid =
259041efec22Sraf 				    generic_so.rwlock.rwlock_ownerpid;
25917c478bd9Sstevel@tonic-gate 		} else {
259241efec22Sraf 			si_p->si_state.nreaders = (rwstate & URW_READERS_MASK);
25937c478bd9Sstevel@tonic-gate 		}
259441efec22Sraf 		si_p->si_has_waiters = ((rwstate & URW_HAS_WAITERS) != 0);
259541efec22Sraf 
25967c478bd9Sstevel@tonic-gate 		/* this is useless but the old interface provided it */
25977c478bd9Sstevel@tonic-gate 		si_p->si_data = (psaddr_t)generic_so.rwlock.readers;
25987c478bd9Sstevel@tonic-gate 		break;
259941efec22Sraf 	}
26007c478bd9Sstevel@tonic-gate 	default:
26017c478bd9Sstevel@tonic-gate 		return (TD_BADSH);
26027c478bd9Sstevel@tonic-gate 	}
26037c478bd9Sstevel@tonic-gate 
26047c478bd9Sstevel@tonic-gate 	si_p->si_ta_p = sh_p->sh_ta_p;
26057c478bd9Sstevel@tonic-gate 	si_p->si_sv_addr = sh_p->sh_unique;
26067c478bd9Sstevel@tonic-gate 	return (TD_OK);
26077c478bd9Sstevel@tonic-gate }
26087c478bd9Sstevel@tonic-gate 
26097c478bd9Sstevel@tonic-gate /*
26107c478bd9Sstevel@tonic-gate  * Given a synchronization handle, fill in the
26117c478bd9Sstevel@tonic-gate  * information for the synchronization variable into *si_p.
26127c478bd9Sstevel@tonic-gate  */
26137c478bd9Sstevel@tonic-gate #pragma weak td_sync_get_info = __td_sync_get_info
26147c478bd9Sstevel@tonic-gate td_err_e
26157c478bd9Sstevel@tonic-gate __td_sync_get_info(const td_synchandle_t *sh_p, td_syncinfo_t *si_p)
26167c478bd9Sstevel@tonic-gate {
26177c478bd9Sstevel@tonic-gate 	struct ps_prochandle *ph_p;
26187c478bd9Sstevel@tonic-gate 	td_err_e return_val;
26197c478bd9Sstevel@tonic-gate 
26207c478bd9Sstevel@tonic-gate 	if (si_p == NULL)
26217c478bd9Sstevel@tonic-gate 		return (TD_ERR);
26227c478bd9Sstevel@tonic-gate 	(void) memset(si_p, 0, sizeof (*si_p));
26237c478bd9Sstevel@tonic-gate 	if ((ph_p = ph_lock_sh(sh_p, &return_val)) == NULL)
26247c478bd9Sstevel@tonic-gate 		return (return_val);
26257c478bd9Sstevel@tonic-gate 	if (ps_pstop(ph_p) != PS_OK) {
26267c478bd9Sstevel@tonic-gate 		ph_unlock(sh_p->sh_ta_p);
26277c478bd9Sstevel@tonic-gate 		return (TD_DBERR);
26287c478bd9Sstevel@tonic-gate 	}
26297c478bd9Sstevel@tonic-gate 
26307c478bd9Sstevel@tonic-gate 	return_val = sync_get_info_common(sh_p, ph_p, si_p);
26317c478bd9Sstevel@tonic-gate 
26327c478bd9Sstevel@tonic-gate 	(void) ps_pcontinue(ph_p);
26337c478bd9Sstevel@tonic-gate 	ph_unlock(sh_p->sh_ta_p);
26347c478bd9Sstevel@tonic-gate 	return (return_val);
26357c478bd9Sstevel@tonic-gate }
26367c478bd9Sstevel@tonic-gate 
26377c478bd9Sstevel@tonic-gate static uint_t
26387c478bd9Sstevel@tonic-gate tdb_addr_hash64(uint64_t addr)
26397c478bd9Sstevel@tonic-gate {
26407c478bd9Sstevel@tonic-gate 	uint64_t value60 = (addr >> 4);
26417c478bd9Sstevel@tonic-gate 	uint32_t value30 = (value60 >> 30) ^ (value60 & 0x3fffffff);
26427c478bd9Sstevel@tonic-gate 	return ((value30 >> 15) ^ (value30 & 0x7fff));
26437c478bd9Sstevel@tonic-gate }
26447c478bd9Sstevel@tonic-gate 
26457c478bd9Sstevel@tonic-gate static uint_t
26467c478bd9Sstevel@tonic-gate tdb_addr_hash32(uint64_t addr)
26477c478bd9Sstevel@tonic-gate {
26487c478bd9Sstevel@tonic-gate 	uint32_t value30 = (addr >> 2);		/* 30 bits */
26497c478bd9Sstevel@tonic-gate 	return ((value30 >> 15) ^ (value30 & 0x7fff));
26507c478bd9Sstevel@tonic-gate }
26517c478bd9Sstevel@tonic-gate 
26527c478bd9Sstevel@tonic-gate static td_err_e
26537c478bd9Sstevel@tonic-gate read_sync_stats(td_thragent_t *ta_p, psaddr_t hash_table,
26547c478bd9Sstevel@tonic-gate 	psaddr_t sync_obj_addr, tdb_sync_stats_t *sync_stats)
26557c478bd9Sstevel@tonic-gate {
26567c478bd9Sstevel@tonic-gate 	psaddr_t next_desc;
26577c478bd9Sstevel@tonic-gate 	uint64_t first;
26587c478bd9Sstevel@tonic-gate 	uint_t ix;
26597c478bd9Sstevel@tonic-gate 
26607c478bd9Sstevel@tonic-gate 	/*
26617c478bd9Sstevel@tonic-gate 	 * Compute the hash table index from the synch object's address.
26627c478bd9Sstevel@tonic-gate 	 */
26637c478bd9Sstevel@tonic-gate 	if (ta_p->model == PR_MODEL_LP64)
26647c478bd9Sstevel@tonic-gate 		ix = tdb_addr_hash64(sync_obj_addr);
26657c478bd9Sstevel@tonic-gate 	else
26667c478bd9Sstevel@tonic-gate 		ix = tdb_addr_hash32(sync_obj_addr);
26677c478bd9Sstevel@tonic-gate 
26687c478bd9Sstevel@tonic-gate 	/*
26697c478bd9Sstevel@tonic-gate 	 * Get the address of the first element in the linked list.
26707c478bd9Sstevel@tonic-gate 	 */
26717c478bd9Sstevel@tonic-gate 	if (ps_pdread(ta_p->ph_p, hash_table + ix * sizeof (uint64_t),
26727c478bd9Sstevel@tonic-gate 	    &first, sizeof (first)) != PS_OK)
26737c478bd9Sstevel@tonic-gate 		return (TD_DBERR);
26747c478bd9Sstevel@tonic-gate 
26757c478bd9Sstevel@tonic-gate 	/*
26767c478bd9Sstevel@tonic-gate 	 * Search the linked list for an entry for the synch object..
26777c478bd9Sstevel@tonic-gate 	 */
26787c478bd9Sstevel@tonic-gate 	for (next_desc = (psaddr_t)first; next_desc != NULL;
26797c478bd9Sstevel@tonic-gate 	    next_desc = (psaddr_t)sync_stats->next) {
26807c478bd9Sstevel@tonic-gate 		if (ps_pdread(ta_p->ph_p, next_desc,
26817c478bd9Sstevel@tonic-gate 		    sync_stats, sizeof (*sync_stats)) != PS_OK)
26827c478bd9Sstevel@tonic-gate 			return (TD_DBERR);
26837c478bd9Sstevel@tonic-gate 		if (sync_stats->sync_addr == sync_obj_addr)
26847c478bd9Sstevel@tonic-gate 			return (TD_OK);
26857c478bd9Sstevel@tonic-gate 	}
26867c478bd9Sstevel@tonic-gate 
26877c478bd9Sstevel@tonic-gate 	(void) memset(sync_stats, 0, sizeof (*sync_stats));
26887c478bd9Sstevel@tonic-gate 	return (TD_OK);
26897c478bd9Sstevel@tonic-gate }
26907c478bd9Sstevel@tonic-gate 
26917c478bd9Sstevel@tonic-gate /*
26927c478bd9Sstevel@tonic-gate  * Given a synchronization handle, fill in the
26937c478bd9Sstevel@tonic-gate  * statistics for the synchronization variable into *ss_p.
26947c478bd9Sstevel@tonic-gate  */
26957c478bd9Sstevel@tonic-gate #pragma weak td_sync_get_stats = __td_sync_get_stats
26967c478bd9Sstevel@tonic-gate td_err_e
26977c478bd9Sstevel@tonic-gate __td_sync_get_stats(const td_synchandle_t *sh_p, td_syncstats_t *ss_p)
26987c478bd9Sstevel@tonic-gate {
26997c478bd9Sstevel@tonic-gate 	struct ps_prochandle *ph_p;
27007c478bd9Sstevel@tonic-gate 	td_thragent_t *ta_p;
27017c478bd9Sstevel@tonic-gate 	td_err_e return_val;
27027c478bd9Sstevel@tonic-gate 	register_sync_t enable;
27037c478bd9Sstevel@tonic-gate 	psaddr_t hashaddr;
27047c478bd9Sstevel@tonic-gate 	tdb_sync_stats_t sync_stats;
27057c478bd9Sstevel@tonic-gate 	size_t ix;
27067c478bd9Sstevel@tonic-gate 
27077c478bd9Sstevel@tonic-gate 	if (ss_p == NULL)
27087c478bd9Sstevel@tonic-gate 		return (TD_ERR);
27097c478bd9Sstevel@tonic-gate 	(void) memset(ss_p, 0, sizeof (*ss_p));
27107c478bd9Sstevel@tonic-gate 	if ((ph_p = ph_lock_sh(sh_p, &return_val)) == NULL)
27117c478bd9Sstevel@tonic-gate 		return (return_val);
27127c478bd9Sstevel@tonic-gate 	ta_p = sh_p->sh_ta_p;
27137c478bd9Sstevel@tonic-gate 	if (ps_pstop(ph_p) != PS_OK) {
27147c478bd9Sstevel@tonic-gate 		ph_unlock(ta_p);
27157c478bd9Sstevel@tonic-gate 		return (TD_DBERR);
27167c478bd9Sstevel@tonic-gate 	}
27177c478bd9Sstevel@tonic-gate 
27187c478bd9Sstevel@tonic-gate 	if ((return_val = sync_get_info_common(sh_p, ph_p, &ss_p->ss_info))
27197c478bd9Sstevel@tonic-gate 	    != TD_OK) {
27207c478bd9Sstevel@tonic-gate 		if (return_val != TD_BADSH)
27217c478bd9Sstevel@tonic-gate 			goto out;
27227c478bd9Sstevel@tonic-gate 		/* we can correct TD_BADSH */
27237c478bd9Sstevel@tonic-gate 		(void) memset(&ss_p->ss_info, 0, sizeof (ss_p->ss_info));
27247c478bd9Sstevel@tonic-gate 		ss_p->ss_info.si_ta_p = sh_p->sh_ta_p;
27257c478bd9Sstevel@tonic-gate 		ss_p->ss_info.si_sv_addr = sh_p->sh_unique;
27267c478bd9Sstevel@tonic-gate 		/* we correct si_type and si_size below */
27277c478bd9Sstevel@tonic-gate 		return_val = TD_OK;
27287c478bd9Sstevel@tonic-gate 	}
27297c478bd9Sstevel@tonic-gate 	if (ps_pdread(ph_p, ta_p->tdb_register_sync_addr,
27307c478bd9Sstevel@tonic-gate 	    &enable, sizeof (enable)) != PS_OK) {
27317c478bd9Sstevel@tonic-gate 		return_val = TD_DBERR;
27327c478bd9Sstevel@tonic-gate 		goto out;
27337c478bd9Sstevel@tonic-gate 	}
27347c478bd9Sstevel@tonic-gate 	if (enable != REGISTER_SYNC_ON)
27357c478bd9Sstevel@tonic-gate 		goto out;
27367c478bd9Sstevel@tonic-gate 
27377c478bd9Sstevel@tonic-gate 	/*
27387c478bd9Sstevel@tonic-gate 	 * Get the address of the hash table in the target process.
27397c478bd9Sstevel@tonic-gate 	 */
27407c478bd9Sstevel@tonic-gate 	if (ta_p->model == PR_MODEL_NATIVE) {
27417c478bd9Sstevel@tonic-gate 		if (ps_pdread(ph_p, ta_p->uberdata_addr +
27427c478bd9Sstevel@tonic-gate 		    offsetof(uberdata_t, tdb.tdb_sync_addr_hash),
27437c478bd9Sstevel@tonic-gate 		    &hashaddr, sizeof (&hashaddr)) != PS_OK) {
27447c478bd9Sstevel@tonic-gate 			return_val = TD_DBERR;
27457c478bd9Sstevel@tonic-gate 			goto out;
27467c478bd9Sstevel@tonic-gate 		}
27477c478bd9Sstevel@tonic-gate 	} else {
27487c478bd9Sstevel@tonic-gate #if defined(_LP64) && defined(_SYSCALL32)
27497c478bd9Sstevel@tonic-gate 		caddr32_t addr;
27507c478bd9Sstevel@tonic-gate 
27517c478bd9Sstevel@tonic-gate 		if (ps_pdread(ph_p, ta_p->uberdata_addr +
27527c478bd9Sstevel@tonic-gate 		    offsetof(uberdata32_t, tdb.tdb_sync_addr_hash),
27537c478bd9Sstevel@tonic-gate 		    &addr, sizeof (addr)) != PS_OK) {
27547c478bd9Sstevel@tonic-gate 			return_val = TD_DBERR;
27557c478bd9Sstevel@tonic-gate 			goto out;
27567c478bd9Sstevel@tonic-gate 		}
27577c478bd9Sstevel@tonic-gate 		hashaddr = addr;
27587c478bd9Sstevel@tonic-gate #else
27597c478bd9Sstevel@tonic-gate 		return_val = TD_ERR;
27607c478bd9Sstevel@tonic-gate 		goto out;
27617c478bd9Sstevel@tonic-gate #endif	/* _SYSCALL32 */
27627c478bd9Sstevel@tonic-gate 	}
27637c478bd9Sstevel@tonic-gate 
27647c478bd9Sstevel@tonic-gate 	if (hashaddr == 0)
27657c478bd9Sstevel@tonic-gate 		return_val = TD_BADSH;
27667c478bd9Sstevel@tonic-gate 	else
27677c478bd9Sstevel@tonic-gate 		return_val = read_sync_stats(ta_p, hashaddr,
27687c478bd9Sstevel@tonic-gate 		    sh_p->sh_unique, &sync_stats);
27697c478bd9Sstevel@tonic-gate 	if (return_val != TD_OK)
27707c478bd9Sstevel@tonic-gate 		goto out;
27717c478bd9Sstevel@tonic-gate 
27727c478bd9Sstevel@tonic-gate 	/*
27737c478bd9Sstevel@tonic-gate 	 * We have the hash table entry.  Transfer the data to
27747c478bd9Sstevel@tonic-gate 	 * the td_syncstats_t structure provided by the caller.
27757c478bd9Sstevel@tonic-gate 	 */
27767c478bd9Sstevel@tonic-gate 	switch (sync_stats.un.type) {
27777c478bd9Sstevel@tonic-gate 	case TDB_MUTEX:
27787c478bd9Sstevel@tonic-gate 	{
27797c478bd9Sstevel@tonic-gate 		td_mutex_stats_t *msp = &ss_p->ss_un.mutex;
27807c478bd9Sstevel@tonic-gate 
27817c478bd9Sstevel@tonic-gate 		ss_p->ss_info.si_type = TD_SYNC_MUTEX;
27827c478bd9Sstevel@tonic-gate 		ss_p->ss_info.si_size = sizeof (mutex_t);
27837c478bd9Sstevel@tonic-gate 		msp->mutex_lock =
27847c478bd9Sstevel@tonic-gate 		    sync_stats.un.mutex.mutex_lock;
27857c478bd9Sstevel@tonic-gate 		msp->mutex_sleep =
27867c478bd9Sstevel@tonic-gate 		    sync_stats.un.mutex.mutex_sleep;
27877c478bd9Sstevel@tonic-gate 		msp->mutex_sleep_time =
27887c478bd9Sstevel@tonic-gate 		    sync_stats.un.mutex.mutex_sleep_time;
27897c478bd9Sstevel@tonic-gate 		msp->mutex_hold_time =
27907c478bd9Sstevel@tonic-gate 		    sync_stats.un.mutex.mutex_hold_time;
27917c478bd9Sstevel@tonic-gate 		msp->mutex_try =
27927c478bd9Sstevel@tonic-gate 		    sync_stats.un.mutex.mutex_try;
27937c478bd9Sstevel@tonic-gate 		msp->mutex_try_fail =
27947c478bd9Sstevel@tonic-gate 		    sync_stats.un.mutex.mutex_try_fail;
27957c478bd9Sstevel@tonic-gate 		if (sync_stats.sync_addr >= ta_p->hash_table_addr &&
27967c478bd9Sstevel@tonic-gate 		    (ix = sync_stats.sync_addr - ta_p->hash_table_addr)
27977c478bd9Sstevel@tonic-gate 		    < ta_p->hash_size * sizeof (thr_hash_table_t))
27987c478bd9Sstevel@tonic-gate 			msp->mutex_internal =
27997c478bd9Sstevel@tonic-gate 			    ix / sizeof (thr_hash_table_t) + 1;
28007c478bd9Sstevel@tonic-gate 		break;
28017c478bd9Sstevel@tonic-gate 	}
28027c478bd9Sstevel@tonic-gate 	case TDB_COND:
28037c478bd9Sstevel@tonic-gate 	{
28047c478bd9Sstevel@tonic-gate 		td_cond_stats_t *csp = &ss_p->ss_un.cond;
28057c478bd9Sstevel@tonic-gate 
28067c478bd9Sstevel@tonic-gate 		ss_p->ss_info.si_type = TD_SYNC_COND;
28077c478bd9Sstevel@tonic-gate 		ss_p->ss_info.si_size = sizeof (cond_t);
28087c478bd9Sstevel@tonic-gate 		csp->cond_wait =
28097c478bd9Sstevel@tonic-gate 		    sync_stats.un.cond.cond_wait;
28107c478bd9Sstevel@tonic-gate 		csp->cond_timedwait =
28117c478bd9Sstevel@tonic-gate 		    sync_stats.un.cond.cond_timedwait;
28127c478bd9Sstevel@tonic-gate 		csp->cond_wait_sleep_time =
28137c478bd9Sstevel@tonic-gate 		    sync_stats.un.cond.cond_wait_sleep_time;
28147c478bd9Sstevel@tonic-gate 		csp->cond_timedwait_sleep_time =
28157c478bd9Sstevel@tonic-gate 		    sync_stats.un.cond.cond_timedwait_sleep_time;
28167c478bd9Sstevel@tonic-gate 		csp->cond_timedwait_timeout =
28177c478bd9Sstevel@tonic-gate 		    sync_stats.un.cond.cond_timedwait_timeout;
28187c478bd9Sstevel@tonic-gate 		csp->cond_signal =
28197c478bd9Sstevel@tonic-gate 		    sync_stats.un.cond.cond_signal;
28207c478bd9Sstevel@tonic-gate 		csp->cond_broadcast =
28217c478bd9Sstevel@tonic-gate 		    sync_stats.un.cond.cond_broadcast;
28227c478bd9Sstevel@tonic-gate 		if (sync_stats.sync_addr >= ta_p->hash_table_addr &&
28237c478bd9Sstevel@tonic-gate 		    (ix = sync_stats.sync_addr - ta_p->hash_table_addr)
28247c478bd9Sstevel@tonic-gate 		    < ta_p->hash_size * sizeof (thr_hash_table_t))
28257c478bd9Sstevel@tonic-gate 			csp->cond_internal =
28267c478bd9Sstevel@tonic-gate 			    ix / sizeof (thr_hash_table_t) + 1;
28277c478bd9Sstevel@tonic-gate 		break;
28287c478bd9Sstevel@tonic-gate 	}
28297c478bd9Sstevel@tonic-gate 	case TDB_RWLOCK:
28307c478bd9Sstevel@tonic-gate 	{
28317c478bd9Sstevel@tonic-gate 		td_rwlock_stats_t *rwsp = &ss_p->ss_un.rwlock;
28327c478bd9Sstevel@tonic-gate 
28337c478bd9Sstevel@tonic-gate 		ss_p->ss_info.si_type = TD_SYNC_RWLOCK;
28347c478bd9Sstevel@tonic-gate 		ss_p->ss_info.si_size = sizeof (rwlock_t);
28357c478bd9Sstevel@tonic-gate 		rwsp->rw_rdlock =
28367c478bd9Sstevel@tonic-gate 		    sync_stats.un.rwlock.rw_rdlock;
28377c478bd9Sstevel@tonic-gate 		rwsp->rw_rdlock_try =
28387c478bd9Sstevel@tonic-gate 		    sync_stats.un.rwlock.rw_rdlock_try;
28397c478bd9Sstevel@tonic-gate 		rwsp->rw_rdlock_try_fail =
28407c478bd9Sstevel@tonic-gate 		    sync_stats.un.rwlock.rw_rdlock_try_fail;
28417c478bd9Sstevel@tonic-gate 		rwsp->rw_wrlock =
28427c478bd9Sstevel@tonic-gate 		    sync_stats.un.rwlock.rw_wrlock;
28437c478bd9Sstevel@tonic-gate 		rwsp->rw_wrlock_hold_time =
28447c478bd9Sstevel@tonic-gate 		    sync_stats.un.rwlock.rw_wrlock_hold_time;
28457c478bd9Sstevel@tonic-gate 		rwsp->rw_wrlock_try =
28467c478bd9Sstevel@tonic-gate 		    sync_stats.un.rwlock.rw_wrlock_try;
28477c478bd9Sstevel@tonic-gate 		rwsp->rw_wrlock_try_fail =
28487c478bd9Sstevel@tonic-gate 		    sync_stats.un.rwlock.rw_wrlock_try_fail;
28497c478bd9Sstevel@tonic-gate 		break;
28507c478bd9Sstevel@tonic-gate 	}
28517c478bd9Sstevel@tonic-gate 	case TDB_SEMA:
28527c478bd9Sstevel@tonic-gate 	{
28537c478bd9Sstevel@tonic-gate 		td_sema_stats_t *ssp = &ss_p->ss_un.sema;
28547c478bd9Sstevel@tonic-gate 
28557c478bd9Sstevel@tonic-gate 		ss_p->ss_info.si_type = TD_SYNC_SEMA;
28567c478bd9Sstevel@tonic-gate 		ss_p->ss_info.si_size = sizeof (sema_t);
28577c478bd9Sstevel@tonic-gate 		ssp->sema_wait =
28587c478bd9Sstevel@tonic-gate 		    sync_stats.un.sema.sema_wait;
28597c478bd9Sstevel@tonic-gate 		ssp->sema_wait_sleep =
28607c478bd9Sstevel@tonic-gate 		    sync_stats.un.sema.sema_wait_sleep;
28617c478bd9Sstevel@tonic-gate 		ssp->sema_wait_sleep_time =
28627c478bd9Sstevel@tonic-gate 		    sync_stats.un.sema.sema_wait_sleep_time;
28637c478bd9Sstevel@tonic-gate 		ssp->sema_trywait =
28647c478bd9Sstevel@tonic-gate 		    sync_stats.un.sema.sema_trywait;
28657c478bd9Sstevel@tonic-gate 		ssp->sema_trywait_fail =
28667c478bd9Sstevel@tonic-gate 		    sync_stats.un.sema.sema_trywait_fail;
28677c478bd9Sstevel@tonic-gate 		ssp->sema_post =
28687c478bd9Sstevel@tonic-gate 		    sync_stats.un.sema.sema_post;
28697c478bd9Sstevel@tonic-gate 		ssp->sema_max_count =
28707c478bd9Sstevel@tonic-gate 		    sync_stats.un.sema.sema_max_count;
28717c478bd9Sstevel@tonic-gate 		ssp->sema_min_count =
28727c478bd9Sstevel@tonic-gate 		    sync_stats.un.sema.sema_min_count;
28737c478bd9Sstevel@tonic-gate 		break;
28747c478bd9Sstevel@tonic-gate 	}
28757c478bd9Sstevel@tonic-gate 	default:
28767c478bd9Sstevel@tonic-gate 		return_val = TD_BADSH;
28777c478bd9Sstevel@tonic-gate 		break;
28787c478bd9Sstevel@tonic-gate 	}
28797c478bd9Sstevel@tonic-gate 
28807c478bd9Sstevel@tonic-gate out:
28817c478bd9Sstevel@tonic-gate 	(void) ps_pcontinue(ph_p);
28827c478bd9Sstevel@tonic-gate 	ph_unlock(ta_p);
28837c478bd9Sstevel@tonic-gate 	return (return_val);
28847c478bd9Sstevel@tonic-gate }
28857c478bd9Sstevel@tonic-gate 
28867c478bd9Sstevel@tonic-gate /*
28877c478bd9Sstevel@tonic-gate  * Change the state of a synchronization variable.
28887c478bd9Sstevel@tonic-gate  *	1) mutex lock state set to value
28897c478bd9Sstevel@tonic-gate  *	2) semaphore's count set to value
289041efec22Sraf  *	3) writer's lock set by value < 0
289141efec22Sraf  *	4) reader's lock number of readers set to value >= 0
28927c478bd9Sstevel@tonic-gate  * Currently unused by dbx.
28937c478bd9Sstevel@tonic-gate  */
28947c478bd9Sstevel@tonic-gate #pragma weak td_sync_setstate = __td_sync_setstate
28957c478bd9Sstevel@tonic-gate td_err_e
28967c478bd9Sstevel@tonic-gate __td_sync_setstate(const td_synchandle_t *sh_p, long lvalue)
28977c478bd9Sstevel@tonic-gate {
28987c478bd9Sstevel@tonic-gate 	struct ps_prochandle *ph_p;
28997c478bd9Sstevel@tonic-gate 	int		trunc = 0;
29007c478bd9Sstevel@tonic-gate 	td_err_e	return_val;
29017c478bd9Sstevel@tonic-gate 	td_so_un_t	generic_so;
290241efec22Sraf 	uint32_t	*rwstate;
29037c478bd9Sstevel@tonic-gate 	int		value = (int)lvalue;
29047c478bd9Sstevel@tonic-gate 
29057c478bd9Sstevel@tonic-gate 	if ((ph_p = ph_lock_sh(sh_p, &return_val)) == NULL)
29067c478bd9Sstevel@tonic-gate 		return (return_val);
29077c478bd9Sstevel@tonic-gate 	if (ps_pstop(ph_p) != PS_OK) {
29087c478bd9Sstevel@tonic-gate 		ph_unlock(sh_p->sh_ta_p);
29097c478bd9Sstevel@tonic-gate 		return (TD_DBERR);
29107c478bd9Sstevel@tonic-gate 	}
29117c478bd9Sstevel@tonic-gate 
29127c478bd9Sstevel@tonic-gate 	/*
29137c478bd9Sstevel@tonic-gate 	 * Read the synch. variable information.
29147c478bd9Sstevel@tonic-gate 	 * First attempt to read the whole union and if that fails
29157c478bd9Sstevel@tonic-gate 	 * fall back to reading only the smallest member, the condvar.
29167c478bd9Sstevel@tonic-gate 	 */
29177c478bd9Sstevel@tonic-gate 	if (ps_pdread(ph_p, sh_p->sh_unique, &generic_so,
29187c478bd9Sstevel@tonic-gate 	    sizeof (generic_so)) != PS_OK) {
29197c478bd9Sstevel@tonic-gate 		trunc = 1;
29207c478bd9Sstevel@tonic-gate 		if (ps_pdread(ph_p, sh_p->sh_unique, &generic_so.condition,
29217c478bd9Sstevel@tonic-gate 		    sizeof (generic_so.condition)) != PS_OK) {
29227c478bd9Sstevel@tonic-gate 			(void) ps_pcontinue(ph_p);
29237c478bd9Sstevel@tonic-gate 			ph_unlock(sh_p->sh_ta_p);
29247c478bd9Sstevel@tonic-gate 			return (TD_DBERR);
29257c478bd9Sstevel@tonic-gate 		}
29267c478bd9Sstevel@tonic-gate 	}
29277c478bd9Sstevel@tonic-gate 
29287c478bd9Sstevel@tonic-gate 	/*
29297c478bd9Sstevel@tonic-gate 	 * Set the new value in the sync. variable, read the synch. variable
29307c478bd9Sstevel@tonic-gate 	 * information. from the process, reset its value and write it back.
29317c478bd9Sstevel@tonic-gate 	 */
29327c478bd9Sstevel@tonic-gate 	switch (generic_so.condition.mutex_magic) {
29337c478bd9Sstevel@tonic-gate 	case MUTEX_MAGIC:
29347c478bd9Sstevel@tonic-gate 		if (trunc && ps_pdread(ph_p, sh_p->sh_unique,
29357c478bd9Sstevel@tonic-gate 		    &generic_so.lock, sizeof (generic_so.lock)) != PS_OK) {
29367c478bd9Sstevel@tonic-gate 			return_val = TD_DBERR;
29377c478bd9Sstevel@tonic-gate 			break;
29387c478bd9Sstevel@tonic-gate 		}
29397c478bd9Sstevel@tonic-gate 		generic_so.lock.mutex_lockw = (uint8_t)value;
29407c478bd9Sstevel@tonic-gate 		if (ps_pdwrite(ph_p, sh_p->sh_unique, &generic_so.lock,
29417c478bd9Sstevel@tonic-gate 		    sizeof (generic_so.lock)) != PS_OK)
29427c478bd9Sstevel@tonic-gate 			return_val = TD_DBERR;
29437c478bd9Sstevel@tonic-gate 		break;
29447c478bd9Sstevel@tonic-gate 	case SEMA_MAGIC:
29457c478bd9Sstevel@tonic-gate 		if (trunc && ps_pdread(ph_p, sh_p->sh_unique,
29467c478bd9Sstevel@tonic-gate 		    &generic_so.semaphore, sizeof (generic_so.semaphore))
29477c478bd9Sstevel@tonic-gate 		    != PS_OK) {
29487c478bd9Sstevel@tonic-gate 			return_val = TD_DBERR;
29497c478bd9Sstevel@tonic-gate 			break;
29507c478bd9Sstevel@tonic-gate 		}
29517c478bd9Sstevel@tonic-gate 		generic_so.semaphore.count = value;
29527c478bd9Sstevel@tonic-gate 		if (ps_pdwrite(ph_p, sh_p->sh_unique, &generic_so.semaphore,
29537c478bd9Sstevel@tonic-gate 		    sizeof (generic_so.semaphore)) != PS_OK)
29547c478bd9Sstevel@tonic-gate 			return_val = TD_DBERR;
29557c478bd9Sstevel@tonic-gate 		break;
29567c478bd9Sstevel@tonic-gate 	case COND_MAGIC:
29577c478bd9Sstevel@tonic-gate 		/* Operation not supported on a condition variable */
29587c478bd9Sstevel@tonic-gate 		return_val = TD_ERR;
29597c478bd9Sstevel@tonic-gate 		break;
29607c478bd9Sstevel@tonic-gate 	case RWL_MAGIC:
29617c478bd9Sstevel@tonic-gate 		if (trunc && ps_pdread(ph_p, sh_p->sh_unique,
29627c478bd9Sstevel@tonic-gate 		    &generic_so.rwlock, sizeof (generic_so.rwlock)) != PS_OK) {
29637c478bd9Sstevel@tonic-gate 			return_val = TD_DBERR;
29647c478bd9Sstevel@tonic-gate 			break;
29657c478bd9Sstevel@tonic-gate 		}
296641efec22Sraf 		rwstate = (uint32_t *)&generic_so.rwlock.readers;
296741efec22Sraf 		*rwstate &= URW_HAS_WAITERS;
29687c478bd9Sstevel@tonic-gate 		if (value < 0)
296941efec22Sraf 			*rwstate |= URW_WRITE_LOCKED;
29707c478bd9Sstevel@tonic-gate 		else
297141efec22Sraf 			*rwstate |= (value & URW_READERS_MASK);
29727c478bd9Sstevel@tonic-gate 		if (ps_pdwrite(ph_p, sh_p->sh_unique, &generic_so.rwlock,
29737c478bd9Sstevel@tonic-gate 		    sizeof (generic_so.rwlock)) != PS_OK)
29747c478bd9Sstevel@tonic-gate 			return_val = TD_DBERR;
29757c478bd9Sstevel@tonic-gate 		break;
29767c478bd9Sstevel@tonic-gate 	default:
29777c478bd9Sstevel@tonic-gate 		/* Bad sync. object type */
29787c478bd9Sstevel@tonic-gate 		return_val = TD_BADSH;
29797c478bd9Sstevel@tonic-gate 		break;
29807c478bd9Sstevel@tonic-gate 	}
29817c478bd9Sstevel@tonic-gate 
29827c478bd9Sstevel@tonic-gate 	(void) ps_pcontinue(ph_p);
29837c478bd9Sstevel@tonic-gate 	ph_unlock(sh_p->sh_ta_p);
29847c478bd9Sstevel@tonic-gate 	return (return_val);
29857c478bd9Sstevel@tonic-gate }
29867c478bd9Sstevel@tonic-gate 
29877c478bd9Sstevel@tonic-gate typedef struct {
29887c478bd9Sstevel@tonic-gate 	td_thr_iter_f	*waiter_cb;
29897c478bd9Sstevel@tonic-gate 	psaddr_t	sync_obj_addr;
29907c478bd9Sstevel@tonic-gate 	uint16_t	sync_magic;
29917c478bd9Sstevel@tonic-gate 	void		*waiter_cb_arg;
29927c478bd9Sstevel@tonic-gate 	td_err_e	errcode;
29937c478bd9Sstevel@tonic-gate } waiter_cb_ctl_t;
29947c478bd9Sstevel@tonic-gate 
29957c478bd9Sstevel@tonic-gate static int
29967c478bd9Sstevel@tonic-gate waiters_cb(const td_thrhandle_t *th_p, void *arg)
29977c478bd9Sstevel@tonic-gate {
29987c478bd9Sstevel@tonic-gate 	td_thragent_t	*ta_p = th_p->th_ta_p;
29997c478bd9Sstevel@tonic-gate 	struct ps_prochandle *ph_p = ta_p->ph_p;
30007c478bd9Sstevel@tonic-gate 	waiter_cb_ctl_t	*wcb = arg;
30017c478bd9Sstevel@tonic-gate 	caddr_t		wchan;
30027c478bd9Sstevel@tonic-gate 
30037c478bd9Sstevel@tonic-gate 	if (ta_p->model == PR_MODEL_NATIVE) {
30047c478bd9Sstevel@tonic-gate 		ulwp_t *ulwp = (ulwp_t *)th_p->th_unique;
30057c478bd9Sstevel@tonic-gate 
30067c478bd9Sstevel@tonic-gate 		if (ps_pdread(ph_p, (psaddr_t)&ulwp->ul_wchan,
30077c478bd9Sstevel@tonic-gate 		    &wchan, sizeof (wchan)) != PS_OK) {
30087c478bd9Sstevel@tonic-gate 			wcb->errcode = TD_DBERR;
30097c478bd9Sstevel@tonic-gate 			return (1);
30107c478bd9Sstevel@tonic-gate 		}
30117c478bd9Sstevel@tonic-gate 	} else {
30127c478bd9Sstevel@tonic-gate #if defined(_LP64) && defined(_SYSCALL32)
30137c478bd9Sstevel@tonic-gate 		ulwp32_t *ulwp = (ulwp32_t *)th_p->th_unique;
30147c478bd9Sstevel@tonic-gate 		caddr32_t wchan32;
30157c478bd9Sstevel@tonic-gate 
30167c478bd9Sstevel@tonic-gate 		if (ps_pdread(ph_p, (psaddr_t)&ulwp->ul_wchan,
30177c478bd9Sstevel@tonic-gate 		    &wchan32, sizeof (wchan32)) != PS_OK) {
30187c478bd9Sstevel@tonic-gate 			wcb->errcode = TD_DBERR;
30197c478bd9Sstevel@tonic-gate 			return (1);
30207c478bd9Sstevel@tonic-gate 		}
30217c478bd9Sstevel@tonic-gate 		wchan = (caddr_t)(uintptr_t)wchan32;
30227c478bd9Sstevel@tonic-gate #else
30237c478bd9Sstevel@tonic-gate 		wcb->errcode = TD_ERR;
30247c478bd9Sstevel@tonic-gate 		return (1);
30257c478bd9Sstevel@tonic-gate #endif	/* _SYSCALL32 */
30267c478bd9Sstevel@tonic-gate 	}
30277c478bd9Sstevel@tonic-gate 
30287c478bd9Sstevel@tonic-gate 	if (wchan == NULL)
30297c478bd9Sstevel@tonic-gate 		return (0);
30307c478bd9Sstevel@tonic-gate 
30317c478bd9Sstevel@tonic-gate 	if (wchan == (caddr_t)wcb->sync_obj_addr)
30327c478bd9Sstevel@tonic-gate 		return ((*wcb->waiter_cb)(th_p, wcb->waiter_cb_arg));
30337c478bd9Sstevel@tonic-gate 
30347c478bd9Sstevel@tonic-gate 	return (0);
30357c478bd9Sstevel@tonic-gate }
30367c478bd9Sstevel@tonic-gate 
30377c478bd9Sstevel@tonic-gate /*
30387c478bd9Sstevel@tonic-gate  * For a given synchronization variable, iterate over the
30397c478bd9Sstevel@tonic-gate  * set of waiting threads.  The call back function is passed
30407c478bd9Sstevel@tonic-gate  * two parameters, a pointer to a thread handle and a pointer
30417c478bd9Sstevel@tonic-gate  * to extra call back data.
30427c478bd9Sstevel@tonic-gate  */
30437c478bd9Sstevel@tonic-gate #pragma weak td_sync_waiters = __td_sync_waiters
30447c478bd9Sstevel@tonic-gate td_err_e
30457c478bd9Sstevel@tonic-gate __td_sync_waiters(const td_synchandle_t *sh_p, td_thr_iter_f *cb, void *cb_data)
30467c478bd9Sstevel@tonic-gate {
30477c478bd9Sstevel@tonic-gate 	struct ps_prochandle *ph_p;
30487c478bd9Sstevel@tonic-gate 	waiter_cb_ctl_t	wcb;
30497c478bd9Sstevel@tonic-gate 	td_err_e	return_val;
30507c478bd9Sstevel@tonic-gate 
30517c478bd9Sstevel@tonic-gate 	if ((ph_p = ph_lock_sh(sh_p, &return_val)) == NULL)
30527c478bd9Sstevel@tonic-gate 		return (return_val);
30537c478bd9Sstevel@tonic-gate 	if (ps_pdread(ph_p,
30547c478bd9Sstevel@tonic-gate 	    (psaddr_t)&((mutex_t *)sh_p->sh_unique)->mutex_magic,
30557c478bd9Sstevel@tonic-gate 	    (caddr_t)&wcb.sync_magic, sizeof (wcb.sync_magic)) != PS_OK) {
30567c478bd9Sstevel@tonic-gate 		ph_unlock(sh_p->sh_ta_p);
30577c478bd9Sstevel@tonic-gate 		return (TD_DBERR);
30587c478bd9Sstevel@tonic-gate 	}
30597c478bd9Sstevel@tonic-gate 	ph_unlock(sh_p->sh_ta_p);
30607c478bd9Sstevel@tonic-gate 
30617c478bd9Sstevel@tonic-gate 	switch (wcb.sync_magic) {
30627c478bd9Sstevel@tonic-gate 	case MUTEX_MAGIC:
30637c478bd9Sstevel@tonic-gate 	case COND_MAGIC:
30647c478bd9Sstevel@tonic-gate 	case SEMA_MAGIC:
30657c478bd9Sstevel@tonic-gate 	case RWL_MAGIC:
30667c478bd9Sstevel@tonic-gate 		break;
30677c478bd9Sstevel@tonic-gate 	default:
30687c478bd9Sstevel@tonic-gate 		return (TD_BADSH);
30697c478bd9Sstevel@tonic-gate 	}
30707c478bd9Sstevel@tonic-gate 
30717c478bd9Sstevel@tonic-gate 	wcb.waiter_cb = cb;
30727c478bd9Sstevel@tonic-gate 	wcb.sync_obj_addr = sh_p->sh_unique;
30737c478bd9Sstevel@tonic-gate 	wcb.waiter_cb_arg = cb_data;
30747c478bd9Sstevel@tonic-gate 	wcb.errcode = TD_OK;
30757c478bd9Sstevel@tonic-gate 	return_val = __td_ta_thr_iter(sh_p->sh_ta_p, waiters_cb, &wcb,
30767c478bd9Sstevel@tonic-gate 	    TD_THR_SLEEP, TD_THR_LOWEST_PRIORITY,
30777c478bd9Sstevel@tonic-gate 	    TD_SIGNO_MASK, TD_THR_ANY_USER_FLAGS);
30787c478bd9Sstevel@tonic-gate 
30797c478bd9Sstevel@tonic-gate 	if (return_val != TD_OK)
30807c478bd9Sstevel@tonic-gate 		return (return_val);
30817c478bd9Sstevel@tonic-gate 
30827c478bd9Sstevel@tonic-gate 	return (wcb.errcode);
30837c478bd9Sstevel@tonic-gate }
3084