thread_db.c revision 641:057d58d31499
1/*
2 * CDDL HEADER START
3 *
4 * The contents of this file are subject to the terms of the
5 * Common Development and Distribution License, Version 1.0 only
6 * (the "License").  You may not use this file except in compliance
7 * with the License.
8 *
9 * You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
10 * or http://www.opensolaris.org/os/licensing.
11 * See the License for the specific language governing permissions
12 * and limitations under the License.
13 *
14 * When distributing Covered Code, include this CDDL HEADER in each
15 * file and include the License file at usr/src/OPENSOLARIS.LICENSE.
16 * If applicable, add the following below this CDDL HEADER, with the
17 * fields enclosed by brackets "[]" replaced with your own identifying
18 * information: Portions Copyright [yyyy] [name of copyright owner]
19 *
20 * CDDL HEADER END
21 */
22/*
23 * Copyright 2005 Sun Microsystems, Inc.  All rights reserved.
24 * Use is subject to license terms.
25 */
26
27#pragma ident	"%Z%%M%	%I%	%E% SMI"
28
29#include <stdio.h>
30#include <stdlib.h>
31#include <stddef.h>
32#include <unistd.h>
33#include <thr_uberdata.h>
34#include <thread_db.h>
35#include <libc_int.h>
36
37/*
38 * Private structures.
39 */
40
41typedef union {
42	mutex_t		lock;
43	rwlock_t	rwlock;
44	sema_t		semaphore;
45	cond_t		condition;
46} td_so_un_t;
47
48struct td_thragent {
49	rwlock_t	rwlock;
50	struct ps_prochandle *ph_p;
51	int		initialized;
52	int		sync_tracking;
53	int		model;
54	int		primary_map;
55	psaddr_t	bootstrap_addr;
56	psaddr_t	uberdata_addr;
57	psaddr_t	tdb_eventmask_addr;
58	psaddr_t	tdb_register_sync_addr;
59	psaddr_t	tdb_events[TD_MAX_EVENT_NUM - TD_MIN_EVENT_NUM + 1];
60	psaddr_t	hash_table_addr;
61	int		hash_size;
62	lwpid_t		single_lwpid;
63	psaddr_t	single_ulwp_addr;
64};
65
66/*
67 * This is the name of the variable in libc that contains
68 * the uberdata address that we will need.
69 */
70#define	TD_BOOTSTRAP_NAME	"_tdb_bootstrap"
71/*
72 * This is the actual name of uberdata, used in the event
73 * that tdb_bootstrap has not yet been initialized.
74 */
75#define	TD_UBERDATA_NAME	"_uberdata"
76/*
77 * The library name should end with ".so.1", but older versions of
78 * dbx expect the unadorned name and malfunction if ".1" is specified.
79 * Unfortunately, if ".1" is not specified, mdb malfunctions when it
80 * is applied to another instance of itself (due to the presence of
81 * /usr/lib/mdb/proc/libc.so).  So we try it both ways.
82 */
83#define	TD_LIBRARY_NAME		"libc.so"
84#define	TD_LIBRARY_NAME_1	"libc.so.1"
85
86td_err_e __td_thr_get_info(td_thrhandle_t *th_p, td_thrinfo_t *ti_p);
87
88td_err_e __td_ta_thr_iter(td_thragent_t *ta_p, td_thr_iter_f *cb,
89	void *cbdata_p, td_thr_state_e state, int ti_pri,
90	sigset_t *ti_sigmask_p, unsigned ti_user_flags);
91
92/*
93 * Initialize threads debugging interface.
94 */
95#pragma weak td_init = __td_init
96td_err_e
97__td_init()
98{
99	return (TD_OK);
100}
101
102/*
103 * This function does nothing, and never did.
104 * But the symbol is in the ABI, so we can't delete it.
105 */
106#pragma weak td_log = __td_log
107void
108__td_log()
109{
110}
111
112/*
113 * Short-cut to read just the hash table size from the process,
114 * to avoid repeatedly reading the full uberdata structure when
115 * dealing with a single-threaded process.
116 */
117static uint_t
118td_read_hash_size(td_thragent_t *ta_p)
119{
120	psaddr_t addr;
121	uint_t hash_size;
122
123	switch (ta_p->initialized) {
124	default:	/* uninitialized */
125		return (0);
126	case 1:		/* partially initialized */
127		break;
128	case 2:		/* fully initialized */
129		return (ta_p->hash_size);
130	}
131
132	if (ta_p->model == PR_MODEL_NATIVE) {
133		addr = ta_p->uberdata_addr + offsetof(uberdata_t, hash_size);
134	} else {
135#if defined(_LP64) && defined(_SYSCALL32)
136		addr = ta_p->uberdata_addr + offsetof(uberdata32_t, hash_size);
137#else
138		addr = 0;
139#endif
140	}
141	if (ps_pdread(ta_p->ph_p, addr, &hash_size, sizeof (hash_size))
142	    != PS_OK)
143		return (0);
144	return (hash_size);
145}
146
147static td_err_e
148td_read_uberdata(td_thragent_t *ta_p)
149{
150	struct ps_prochandle *ph_p = ta_p->ph_p;
151
152	if (ta_p->model == PR_MODEL_NATIVE) {
153		uberdata_t uberdata;
154
155		if (ps_pdread(ph_p, ta_p->uberdata_addr,
156		    &uberdata, sizeof (uberdata)) != PS_OK)
157			return (TD_DBERR);
158		ta_p->primary_map = uberdata.primary_map;
159		ta_p->tdb_eventmask_addr = ta_p->uberdata_addr +
160			offsetof(uberdata_t, tdb.tdb_ev_global_mask);
161		ta_p->tdb_register_sync_addr = ta_p->uberdata_addr +
162			offsetof(uberdata_t, uberflags.uf_tdb_register_sync);
163		ta_p->hash_table_addr = (psaddr_t)uberdata.thr_hash_table;
164		ta_p->hash_size = uberdata.hash_size;
165		if (ps_pdread(ph_p, (psaddr_t)uberdata.tdb.tdb_events,
166		    ta_p->tdb_events, sizeof (ta_p->tdb_events)) != PS_OK)
167			return (TD_DBERR);
168
169	} else {
170#if defined(_LP64) && defined(_SYSCALL32)
171		uberdata32_t uberdata;
172		caddr32_t tdb_events[TD_MAX_EVENT_NUM - TD_MIN_EVENT_NUM + 1];
173		int i;
174
175		if (ps_pdread(ph_p, ta_p->uberdata_addr,
176		    &uberdata, sizeof (uberdata)) != PS_OK)
177			return (TD_DBERR);
178		ta_p->primary_map = uberdata.primary_map;
179		ta_p->tdb_eventmask_addr = ta_p->uberdata_addr +
180			offsetof(uberdata32_t, tdb.tdb_ev_global_mask);
181		ta_p->tdb_register_sync_addr = ta_p->uberdata_addr +
182			offsetof(uberdata32_t, uberflags.uf_tdb_register_sync);
183		ta_p->hash_table_addr = (psaddr_t)uberdata.thr_hash_table;
184		ta_p->hash_size = uberdata.hash_size;
185		if (ps_pdread(ph_p, (psaddr_t)uberdata.tdb.tdb_events,
186		    tdb_events, sizeof (tdb_events)) != PS_OK)
187			return (TD_DBERR);
188		for (i = 0; i < TD_MAX_EVENT_NUM - TD_MIN_EVENT_NUM + 1; i++)
189			ta_p->tdb_events[i] = tdb_events[i];
190#else
191		return (TD_DBERR);
192#endif
193	}
194	if (ta_p->hash_size != 1) {	/* multi-threaded */
195		ta_p->initialized = 2;
196		ta_p->single_lwpid = 0;
197		ta_p->single_ulwp_addr = NULL;
198	} else {			/* single-threaded */
199		ta_p->initialized = 1;
200		/*
201		 * Get the address and lwpid of the single thread/LWP.
202		 * It may not be ulwp_one if this is a child of fork1().
203		 */
204		if (ta_p->model == PR_MODEL_NATIVE) {
205			thr_hash_table_t head;
206			lwpid_t lwpid = 0;
207
208			if (ps_pdread(ph_p, ta_p->hash_table_addr,
209			    &head, sizeof (head)) != PS_OK)
210				return (TD_DBERR);
211			if ((psaddr_t)head.hash_bucket == NULL)
212				ta_p->initialized = 0;
213			else if (ps_pdread(ph_p, (psaddr_t)head.hash_bucket +
214			    offsetof(ulwp_t, ul_lwpid),
215			    &lwpid, sizeof (lwpid)) != PS_OK)
216				return (TD_DBERR);
217			ta_p->single_lwpid = lwpid;
218			ta_p->single_ulwp_addr = (psaddr_t)head.hash_bucket;
219		} else {
220#if defined(_LP64) && defined(_SYSCALL32)
221			thr_hash_table32_t head;
222			lwpid_t lwpid = 0;
223
224			if (ps_pdread(ph_p, ta_p->hash_table_addr,
225			    &head, sizeof (head)) != PS_OK)
226				return (TD_DBERR);
227			if ((psaddr_t)head.hash_bucket == NULL)
228				ta_p->initialized = 0;
229			else if (ps_pdread(ph_p, (psaddr_t)head.hash_bucket +
230			    offsetof(ulwp32_t, ul_lwpid),
231			    &lwpid, sizeof (lwpid)) != PS_OK)
232				return (TD_DBERR);
233			ta_p->single_lwpid = lwpid;
234			ta_p->single_ulwp_addr = (psaddr_t)head.hash_bucket;
235#else
236			return (TD_DBERR);
237#endif
238		}
239	}
240	if (!ta_p->primary_map)
241		ta_p->initialized = 0;
242	return (TD_OK);
243}
244
245static td_err_e
246td_read_bootstrap_data(td_thragent_t *ta_p)
247{
248	struct ps_prochandle *ph_p = ta_p->ph_p;
249	psaddr_t bootstrap_addr;
250	psaddr_t uberdata_addr;
251	ps_err_e db_return;
252	td_err_e return_val;
253	int do_1;
254
255	switch (ta_p->initialized) {
256	case 2:			/* fully initialized */
257		return (TD_OK);
258	case 1:			/* partially initialized */
259		if (td_read_hash_size(ta_p) == 1)
260			return (TD_OK);
261		return (td_read_uberdata(ta_p));
262	}
263
264	/*
265	 * Uninitialized -- do the startup work.
266	 * We set ta_p->initialized to -1 to cut off recursive calls
267	 * into libc_db by code in the provider of ps_pglobal_lookup().
268	 */
269	do_1 = 0;
270	ta_p->initialized = -1;
271	db_return = ps_pglobal_lookup(ph_p, TD_LIBRARY_NAME,
272	    TD_BOOTSTRAP_NAME, &bootstrap_addr);
273	if (db_return == PS_NOSYM) {
274		do_1 = 1;
275		db_return = ps_pglobal_lookup(ph_p, TD_LIBRARY_NAME_1,
276		    TD_BOOTSTRAP_NAME, &bootstrap_addr);
277	}
278	if (db_return == PS_NOSYM)	/* libc is not linked yet */
279		return (TD_NOLIBTHREAD);
280	if (db_return != PS_OK)
281		return (TD_ERR);
282	db_return = ps_pglobal_lookup(ph_p,
283	    do_1? TD_LIBRARY_NAME_1 : TD_LIBRARY_NAME,
284	    TD_UBERDATA_NAME, &uberdata_addr);
285	if (db_return == PS_NOSYM)	/* libc is not linked yet */
286		return (TD_NOLIBTHREAD);
287	if (db_return != PS_OK)
288		return (TD_ERR);
289
290	/*
291	 * Read the uberdata address into the thread agent structure.
292	 */
293	if (ta_p->model == PR_MODEL_NATIVE) {
294		psaddr_t psaddr;
295		if (ps_pdread(ph_p, bootstrap_addr,
296		    &psaddr, sizeof (psaddr)) != PS_OK)
297			return (TD_DBERR);
298		if ((ta_p->bootstrap_addr = psaddr) == NULL)
299			psaddr = uberdata_addr;
300		else if (ps_pdread(ph_p, psaddr,
301		    &psaddr, sizeof (psaddr)) != PS_OK)
302			return (TD_DBERR);
303		ta_p->uberdata_addr = psaddr;
304	} else {
305#if defined(_LP64) && defined(_SYSCALL32)
306		caddr32_t psaddr;
307		if (ps_pdread(ph_p, bootstrap_addr,
308		    &psaddr, sizeof (psaddr)) != PS_OK)
309			return (TD_DBERR);
310		if ((ta_p->bootstrap_addr = (psaddr_t)psaddr) == NULL)
311			psaddr = (caddr32_t)uberdata_addr;
312		else if (ps_pdread(ph_p, (psaddr_t)psaddr,
313		    &psaddr, sizeof (psaddr)) != PS_OK)
314			return (TD_DBERR);
315		ta_p->uberdata_addr = (psaddr_t)psaddr;
316#else
317		return (TD_DBERR);
318#endif	/* _SYSCALL32 */
319	}
320
321	if ((return_val = td_read_uberdata(ta_p)) != TD_OK)
322		return (return_val);
323	if (ta_p->bootstrap_addr == NULL)
324		ta_p->initialized = 0;
325	return (TD_OK);
326}
327
328#pragma weak ps_kill
329#pragma weak ps_lrolltoaddr
330
331/*
332 * Allocate a new agent process handle ("thread agent").
333 */
334#pragma weak td_ta_new = __td_ta_new
335td_err_e
336__td_ta_new(struct ps_prochandle *ph_p, td_thragent_t **ta_pp)
337{
338	td_thragent_t *ta_p;
339	int model;
340	td_err_e return_val = TD_OK;
341
342	if (ph_p == NULL)
343		return (TD_BADPH);
344	if (ta_pp == NULL)
345		return (TD_ERR);
346	*ta_pp = NULL;
347	if (ps_pstop(ph_p) != PS_OK)
348		return (TD_DBERR);
349	/*
350	 * ps_pdmodel might not be defined if this is an older client.
351	 * Make it a weak symbol and test if it exists before calling.
352	 */
353#pragma weak ps_pdmodel
354	if (ps_pdmodel == NULL) {
355		model = PR_MODEL_NATIVE;
356	} else if (ps_pdmodel(ph_p, &model) != PS_OK) {
357		(void) ps_pcontinue(ph_p);
358		return (TD_ERR);
359	}
360	if ((ta_p = malloc(sizeof (*ta_p))) == NULL) {
361		(void) ps_pcontinue(ph_p);
362		return (TD_MALLOC);
363	}
364
365	/*
366	 * Initialize the agent process handle.
367	 * Pick up the symbol value we need from the target process.
368	 */
369	(void) memset(ta_p, 0, sizeof (*ta_p));
370	ta_p->ph_p = ph_p;
371	(void) rwlock_init(&ta_p->rwlock, USYNC_THREAD, NULL);
372	ta_p->model = model;
373	return_val = td_read_bootstrap_data(ta_p);
374
375	/*
376	 * Because the old libthread_db enabled lock tracking by default,
377	 * we must also do it.  However, we do it only if the application
378	 * provides the ps_kill() and ps_lrolltoaddr() interfaces.
379	 * (dbx provides the ps_kill() and ps_lrolltoaddr() interfaces.)
380	 */
381	if (return_val == TD_OK && ps_kill != NULL && ps_lrolltoaddr != NULL) {
382		register_sync_t oldenable;
383		register_sync_t enable = REGISTER_SYNC_ENABLE;
384		psaddr_t psaddr = ta_p->tdb_register_sync_addr;
385
386		if (ps_pdread(ph_p, psaddr,
387		    &oldenable, sizeof (oldenable)) != PS_OK)
388			return_val = TD_DBERR;
389		else if (oldenable != REGISTER_SYNC_OFF ||
390		    ps_pdwrite(ph_p, psaddr,
391		    &enable, sizeof (enable)) != PS_OK) {
392			/*
393			 * Lock tracking was already enabled or we
394			 * failed to enable it, probably because we
395			 * are examining a core file.  In either case
396			 * set the sync_tracking flag non-zero to
397			 * indicate that we should not attempt to
398			 * disable lock tracking when we delete the
399			 * agent process handle in td_ta_delete().
400			 */
401			ta_p->sync_tracking = 1;
402		}
403	}
404
405	if (return_val == TD_OK)
406		*ta_pp = ta_p;
407	else
408		free(ta_p);
409
410	(void) ps_pcontinue(ph_p);
411	return (return_val);
412}
413
414/*
415 * Utility function to grab the readers lock and return the prochandle,
416 * given an agent process handle.  Performs standard error checking.
417 * Returns non-NULL with the lock held, or NULL with the lock not held.
418 */
419static struct ps_prochandle *
420ph_lock_ta(td_thragent_t *ta_p, td_err_e *err)
421{
422	struct ps_prochandle *ph_p = NULL;
423	td_err_e error;
424
425	if (ta_p == NULL || ta_p->initialized == -1) {
426		*err = TD_BADTA;
427	} else if (rw_rdlock(&ta_p->rwlock) != 0) {	/* can't happen? */
428		*err = TD_BADTA;
429	} else if ((ph_p = ta_p->ph_p) == NULL) {
430		(void) rw_unlock(&ta_p->rwlock);
431		*err = TD_BADPH;
432	} else if (ta_p->initialized != 2 &&
433	    (error = td_read_bootstrap_data(ta_p)) != TD_OK) {
434		(void) rw_unlock(&ta_p->rwlock);
435		ph_p = NULL;
436		*err = error;
437	} else {
438		*err = TD_OK;
439	}
440
441	return (ph_p);
442}
443
444/*
445 * Utility function to grab the readers lock and return the prochandle,
446 * given an agent thread handle.  Performs standard error checking.
447 * Returns non-NULL with the lock held, or NULL with the lock not held.
448 */
449static struct ps_prochandle *
450ph_lock_th(const td_thrhandle_t *th_p, td_err_e *err)
451{
452	if (th_p == NULL || th_p->th_unique == NULL) {
453		*err = TD_BADTH;
454		return (NULL);
455	}
456	return (ph_lock_ta(th_p->th_ta_p, err));
457}
458
459/*
460 * Utility function to grab the readers lock and return the prochandle,
461 * given a synchronization object handle.  Performs standard error checking.
462 * Returns non-NULL with the lock held, or NULL with the lock not held.
463 */
464static struct ps_prochandle *
465ph_lock_sh(const td_synchandle_t *sh_p, td_err_e *err)
466{
467	if (sh_p == NULL || sh_p->sh_unique == NULL) {
468		*err = TD_BADSH;
469		return (NULL);
470	}
471	return (ph_lock_ta(sh_p->sh_ta_p, err));
472}
473
474/*
475 * Unlock the agent process handle obtained from ph_lock_*().
476 */
477static void
478ph_unlock(td_thragent_t *ta_p)
479{
480	(void) rw_unlock(&ta_p->rwlock);
481}
482
483/*
484 * De-allocate an agent process handle,
485 * releasing all related resources.
486 *
487 * XXX -- This is hopelessly broken ---
488 * Storage for thread agent is not deallocated.  The prochandle
489 * in the thread agent is set to NULL so that future uses of
490 * the thread agent can be detected and an error value returned.
491 * All functions in the external user interface that make
492 * use of the thread agent are expected
493 * to check for a NULL prochandle in the thread agent.
494 * All such functions are also expected to obtain a
495 * reader lock on the thread agent while it is using it.
496 */
497#pragma weak td_ta_delete = __td_ta_delete
498td_err_e
499__td_ta_delete(td_thragent_t *ta_p)
500{
501	struct ps_prochandle *ph_p;
502
503	/*
504	 * This is the only place we grab the writer lock.
505	 * We are going to NULL out the prochandle.
506	 */
507	if (ta_p == NULL || rw_wrlock(&ta_p->rwlock) != 0)
508		return (TD_BADTA);
509	if ((ph_p = ta_p->ph_p) == NULL) {
510		(void) rw_unlock(&ta_p->rwlock);
511		return (TD_BADPH);
512	}
513	/*
514	 * If synch. tracking was disabled when td_ta_new() was called and
515	 * if td_ta_sync_tracking_enable() was never called, then disable
516	 * synch. tracking (it was enabled by default in td_ta_new()).
517	 */
518	if (ta_p->sync_tracking == 0 &&
519	    ps_kill != NULL && ps_lrolltoaddr != NULL) {
520		register_sync_t enable = REGISTER_SYNC_DISABLE;
521
522		(void) ps_pdwrite(ph_p, ta_p->tdb_register_sync_addr,
523		    &enable, sizeof (enable));
524	}
525	ta_p->ph_p = NULL;
526	(void) rw_unlock(&ta_p->rwlock);
527	return (TD_OK);
528}
529
530/*
531 * Map an agent process handle to a client prochandle.
532 * Currently unused by dbx.
533 */
534#pragma weak td_ta_get_ph = __td_ta_get_ph
535td_err_e
536__td_ta_get_ph(td_thragent_t *ta_p, struct ps_prochandle **ph_pp)
537{
538	td_err_e return_val;
539
540	if (ph_pp != NULL)	/* protect stupid callers */
541		*ph_pp = NULL;
542	if (ph_pp == NULL)
543		return (TD_ERR);
544	if ((*ph_pp = ph_lock_ta(ta_p, &return_val)) == NULL)
545		return (return_val);
546	ph_unlock(ta_p);
547	return (TD_OK);
548}
549
550/*
551 * Set the process's suggested concurrency level.
552 * This is a no-op in a one-level model.
553 * Currently unused by dbx.
554 */
555#pragma weak td_ta_setconcurrency = __td_ta_setconcurrency
556/* ARGSUSED1 */
557td_err_e
558__td_ta_setconcurrency(const td_thragent_t *ta_p, int level)
559{
560	if (ta_p == NULL)
561		return (TD_BADTA);
562	if (ta_p->ph_p == NULL)
563		return (TD_BADPH);
564	return (TD_OK);
565}
566
567/*
568 * Get the number of threads in the process.
569 */
570#pragma weak td_ta_get_nthreads = __td_ta_get_nthreads
571td_err_e
572__td_ta_get_nthreads(td_thragent_t *ta_p, int *nthread_p)
573{
574	struct ps_prochandle *ph_p;
575	td_err_e return_val;
576	int nthreads;
577	int nzombies;
578	psaddr_t nthreads_addr;
579	psaddr_t nzombies_addr;
580
581	if (ta_p->model == PR_MODEL_NATIVE) {
582		nthreads_addr = ta_p->uberdata_addr +
583			offsetof(uberdata_t, nthreads);
584		nzombies_addr = ta_p->uberdata_addr +
585			offsetof(uberdata_t, nzombies);
586	} else {
587#if defined(_LP64) && defined(_SYSCALL32)
588		nthreads_addr = ta_p->uberdata_addr +
589			offsetof(uberdata32_t, nthreads);
590		nzombies_addr = ta_p->uberdata_addr +
591			offsetof(uberdata32_t, nzombies);
592#else
593		nthreads_addr = 0;
594		nzombies_addr = 0;
595#endif	/* _SYSCALL32 */
596	}
597
598	if (nthread_p == NULL)
599		return (TD_ERR);
600	if ((ph_p = ph_lock_ta(ta_p, &return_val)) == NULL)
601		return (return_val);
602	if (ps_pdread(ph_p, nthreads_addr, &nthreads, sizeof (int)) != PS_OK)
603		return_val = TD_DBERR;
604	if (ps_pdread(ph_p, nzombies_addr, &nzombies, sizeof (int)) != PS_OK)
605		return_val = TD_DBERR;
606	ph_unlock(ta_p);
607	if (return_val == TD_OK)
608		*nthread_p = nthreads + nzombies;
609	return (return_val);
610}
611
612typedef struct {
613	thread_t	tid;
614	int		found;
615	td_thrhandle_t	th;
616} td_mapper_param_t;
617
618/*
619 * Check the value in data against the thread id.
620 * If it matches, return 1 to terminate iterations.
621 * This function is used by td_ta_map_id2thr() to map a tid to a thread handle.
622 */
623static int
624td_mapper_id2thr(td_thrhandle_t *th_p, td_mapper_param_t *data)
625{
626	td_thrinfo_t ti;
627
628	if (__td_thr_get_info(th_p, &ti) == TD_OK &&
629	    data->tid == ti.ti_tid) {
630		data->found = 1;
631		data->th = *th_p;
632		return (1);
633	}
634	return (0);
635}
636
637/*
638 * Given a thread identifier, return the corresponding thread handle.
639 */
640#pragma weak td_ta_map_id2thr = __td_ta_map_id2thr
641td_err_e
642__td_ta_map_id2thr(td_thragent_t *ta_p, thread_t tid,
643	td_thrhandle_t *th_p)
644{
645	td_err_e		return_val;
646	td_mapper_param_t	data;
647
648	if (th_p != NULL &&	/* optimize for a single thread */
649	    ta_p != NULL &&
650	    ta_p->initialized == 1 &&
651	    (td_read_hash_size(ta_p) == 1 ||
652	    td_read_uberdata(ta_p) == TD_OK) &&
653	    ta_p->initialized == 1 &&
654	    ta_p->single_lwpid == tid) {
655		th_p->th_ta_p = ta_p;
656		if ((th_p->th_unique = ta_p->single_ulwp_addr) == 0)
657			return (TD_NOTHR);
658		return (TD_OK);
659	}
660
661	/*
662	 * LOCKING EXCEPTION - Locking is not required here because
663	 * the locking and checking will be done in __td_ta_thr_iter.
664	 */
665
666	if (ta_p == NULL)
667		return (TD_BADTA);
668	if (th_p == NULL)
669		return (TD_BADTH);
670	if (tid == 0)
671		return (TD_NOTHR);
672
673	data.tid = tid;
674	data.found = 0;
675	return_val = __td_ta_thr_iter(ta_p,
676		(td_thr_iter_f *)td_mapper_id2thr, (void *)&data,
677		TD_THR_ANY_STATE, TD_THR_LOWEST_PRIORITY,
678		TD_SIGNO_MASK, TD_THR_ANY_USER_FLAGS);
679	if (return_val == TD_OK) {
680		if (data.found == 0)
681			return_val = TD_NOTHR;
682		else
683			*th_p = data.th;
684	}
685
686	return (return_val);
687}
688
689/*
690 * Map the address of a synchronization object to a sync. object handle.
691 */
692#pragma weak td_ta_map_addr2sync = __td_ta_map_addr2sync
693td_err_e
694__td_ta_map_addr2sync(td_thragent_t *ta_p, psaddr_t addr, td_synchandle_t *sh_p)
695{
696	struct ps_prochandle *ph_p;
697	td_err_e return_val;
698	uint16_t sync_magic;
699
700	if (sh_p == NULL)
701		return (TD_BADSH);
702	if (addr == NULL)
703		return (TD_ERR);
704	if ((ph_p = ph_lock_ta(ta_p, &return_val)) == NULL)
705		return (return_val);
706	/*
707	 * Check the magic number of the sync. object to make sure it's valid.
708	 * The magic number is at the same offset for all sync. objects.
709	 */
710	if (ps_pdread(ph_p, (psaddr_t)&((mutex_t *)addr)->mutex_magic,
711	    &sync_magic, sizeof (sync_magic)) != PS_OK) {
712		ph_unlock(ta_p);
713		return (TD_BADSH);
714	}
715	ph_unlock(ta_p);
716	if (sync_magic != MUTEX_MAGIC && sync_magic != COND_MAGIC &&
717	    sync_magic != SEMA_MAGIC && sync_magic != RWL_MAGIC)
718		return (TD_BADSH);
719	/*
720	 * Just fill in the appropriate fields of the sync. handle.
721	 */
722	sh_p->sh_ta_p = (td_thragent_t *)ta_p;
723	sh_p->sh_unique = addr;
724	return (TD_OK);
725}
726
727/*
728 * Iterate over the set of global TSD keys.
729 * The call back function is called with three arguments,
730 * a key, a pointer to the destructor function, and the cbdata pointer.
731 * Currently unused by dbx.
732 */
733#pragma weak td_ta_tsd_iter = __td_ta_tsd_iter
734td_err_e
735__td_ta_tsd_iter(td_thragent_t *ta_p, td_key_iter_f *cb, void *cbdata_p)
736{
737	struct ps_prochandle *ph_p;
738	td_err_e	return_val;
739	int		key;
740	int		numkeys;
741	psaddr_t	dest_addr;
742	psaddr_t	*destructors = NULL;
743	PFrV		destructor;
744
745	if (cb == NULL)
746		return (TD_ERR);
747	if ((ph_p = ph_lock_ta(ta_p, &return_val)) == NULL)
748		return (return_val);
749	if (ps_pstop(ph_p) != PS_OK) {
750		ph_unlock(ta_p);
751		return (TD_DBERR);
752	}
753
754	if (ta_p->model == PR_MODEL_NATIVE) {
755		tsd_metadata_t tsdm;
756
757		if (ps_pdread(ph_p,
758		    ta_p->uberdata_addr + offsetof(uberdata_t, tsd_metadata),
759		    &tsdm, sizeof (tsdm)) != PS_OK)
760			return_val = TD_DBERR;
761		else {
762			numkeys = tsdm.tsdm_nused;
763			dest_addr = (psaddr_t)tsdm.tsdm_destro;
764			if (numkeys > 0)
765				destructors =
766				    malloc(numkeys * sizeof (psaddr_t));
767		}
768	} else {
769#if defined(_LP64) && defined(_SYSCALL32)
770		tsd_metadata32_t tsdm;
771
772		if (ps_pdread(ph_p,
773		    ta_p->uberdata_addr + offsetof(uberdata32_t, tsd_metadata),
774		    &tsdm, sizeof (tsdm)) != PS_OK)
775			return_val = TD_DBERR;
776		else {
777			numkeys = tsdm.tsdm_nused;
778			dest_addr = (psaddr_t)tsdm.tsdm_destro;
779			if (numkeys > 0)
780				destructors =
781				    malloc(numkeys * sizeof (caddr32_t));
782		}
783#else
784		return_val = TD_DBERR;
785#endif	/* _SYSCALL32 */
786	}
787
788	if (return_val != TD_OK || numkeys <= 0) {
789		(void) ps_pcontinue(ph_p);
790		ph_unlock(ta_p);
791		return (return_val);
792	}
793
794	if (destructors == NULL)
795		return_val = TD_MALLOC;
796	else if (ta_p->model == PR_MODEL_NATIVE) {
797		if (ps_pdread(ph_p, dest_addr,
798		    destructors, numkeys * sizeof (psaddr_t)) != PS_OK)
799			return_val = TD_DBERR;
800		else {
801			for (key = 1; key < numkeys; key++) {
802				destructor = (PFrV)destructors[key];
803				if (destructor != TSD_UNALLOCATED &&
804				    (*cb)(key, destructor, cbdata_p))
805					break;
806			}
807		}
808#if defined(_LP64) && defined(_SYSCALL32)
809	} else {
810		caddr32_t *destructors32 = (caddr32_t *)destructors;
811		caddr32_t destruct32;
812
813		if (ps_pdread(ph_p, dest_addr,
814		    destructors32, numkeys * sizeof (caddr32_t)) != PS_OK)
815			return_val = TD_DBERR;
816		else {
817			for (key = 1; key < numkeys; key++) {
818				destruct32 = destructors32[key];
819				if (destruct32 != (caddr32_t)TSD_UNALLOCATED &&
820				    (*cb)(key, (PFrV)(uintptr_t)destruct32,
821				    cbdata_p))
822					break;
823			}
824		}
825#endif	/* _SYSCALL32 */
826	}
827
828	if (destructors)
829		free(destructors);
830	(void) ps_pcontinue(ph_p);
831	ph_unlock(ta_p);
832	return (return_val);
833}
834
835int
836sigequalset(const sigset_t *s1, const sigset_t *s2)
837{
838	return (s1->__sigbits[0] == s2->__sigbits[0] &&
839		s1->__sigbits[1] == s2->__sigbits[1] &&
840		s1->__sigbits[2] == s2->__sigbits[2] &&
841		s1->__sigbits[3] == s2->__sigbits[3]);
842}
843
844/*
845 * Description:
846 *   Iterate over all threads. For each thread call
847 * the function pointed to by "cb" with a pointer
848 * to a thread handle, and a pointer to data which
849 * can be NULL. Only call td_thr_iter_f() on threads
850 * which match the properties of state, ti_pri,
851 * ti_sigmask_p, and ti_user_flags.  If cb returns
852 * a non-zero value, terminate iterations.
853 *
854 * Input:
855 *   *ta_p - thread agent
856 *   *cb - call back function defined by user.
857 * td_thr_iter_f() takes a thread handle and
858 * cbdata_p as a parameter.
859 *   cbdata_p - parameter for td_thr_iter_f().
860 *
861 *   state - state of threads of interest.  A value of
862 * TD_THR_ANY_STATE from enum td_thr_state_e
863 * does not restrict iterations by state.
864 *   ti_pri - lower bound of priorities of threads of
865 * interest.  A value of TD_THR_LOWEST_PRIORITY
866 * defined in thread_db.h does not restrict
867 * iterations by priority.  A thread with priority
868 * less than ti_pri will NOT be passed to the callback
869 * function.
870 *   ti_sigmask_p - signal mask of threads of interest.
871 * A value of TD_SIGNO_MASK defined in thread_db.h
872 * does not restrict iterations by signal mask.
873 *   ti_user_flags - user flags of threads of interest.  A
874 * value of TD_THR_ANY_USER_FLAGS defined in thread_db.h
875 * does not restrict iterations by user flags.
876 */
877#pragma weak td_ta_thr_iter = __td_ta_thr_iter
878td_err_e
879__td_ta_thr_iter(td_thragent_t *ta_p, td_thr_iter_f *cb,
880	void *cbdata_p, td_thr_state_e state, int ti_pri,
881	sigset_t *ti_sigmask_p, unsigned ti_user_flags)
882{
883	struct ps_prochandle *ph_p;
884	psaddr_t	first_lwp_addr;
885	psaddr_t	first_zombie_addr;
886	psaddr_t	curr_lwp_addr;
887	psaddr_t	next_lwp_addr;
888	td_thrhandle_t	th;
889	ps_err_e	db_return;
890	ps_err_e	db_return2;
891	td_err_e	return_val;
892
893	if (cb == NULL)
894		return (TD_ERR);
895	/*
896	 * If state is not within bound, short circuit.
897	 */
898	if (state < TD_THR_ANY_STATE || state > TD_THR_STOPPED_ASLEEP)
899		return (TD_OK);
900
901	if ((ph_p = ph_lock_ta(ta_p, &return_val)) == NULL)
902		return (return_val);
903	if (ps_pstop(ph_p) != PS_OK) {
904		ph_unlock(ta_p);
905		return (TD_DBERR);
906	}
907
908	/*
909	 * For each ulwp_t in the circular linked lists pointed
910	 * to by "all_lwps" and "all_zombies":
911	 * (1) Filter each thread.
912	 * (2) Create the thread_object for each thread that passes.
913	 * (3) Call the call back function on each thread.
914	 */
915
916	if (ta_p->model == PR_MODEL_NATIVE) {
917		db_return = ps_pdread(ph_p,
918		    ta_p->uberdata_addr + offsetof(uberdata_t, all_lwps),
919		    &first_lwp_addr, sizeof (first_lwp_addr));
920		db_return2 = ps_pdread(ph_p,
921		    ta_p->uberdata_addr + offsetof(uberdata_t, all_zombies),
922		    &first_zombie_addr, sizeof (first_zombie_addr));
923	} else {
924#if defined(_LP64) && defined(_SYSCALL32)
925		caddr32_t addr32;
926
927		db_return = ps_pdread(ph_p,
928		    ta_p->uberdata_addr + offsetof(uberdata32_t, all_lwps),
929		    &addr32, sizeof (addr32));
930		first_lwp_addr = addr32;
931		db_return2 = ps_pdread(ph_p,
932		    ta_p->uberdata_addr + offsetof(uberdata32_t, all_zombies),
933		    &addr32, sizeof (addr32));
934		first_zombie_addr = addr32;
935#else	/* _SYSCALL32 */
936		db_return = PS_ERR;
937		db_return2 = PS_ERR;
938#endif	/* _SYSCALL32 */
939	}
940	if (db_return == PS_OK)
941		db_return = db_return2;
942
943	/*
944	 * If first_lwp_addr and first_zombie_addr are both NULL,
945	 * libc must not yet be initialized or all threads have
946	 * exited.  Return TD_NOTHR and all will be well.
947	 */
948	if (db_return == PS_OK &&
949	    first_lwp_addr == NULL && first_zombie_addr == NULL) {
950		(void) ps_pcontinue(ph_p);
951		ph_unlock(ta_p);
952		return (TD_NOTHR);
953	}
954	if (db_return != PS_OK) {
955		(void) ps_pcontinue(ph_p);
956		ph_unlock(ta_p);
957		return (TD_DBERR);
958	}
959
960	/*
961	 * Run down the lists of all living and dead lwps.
962	 */
963	if (first_lwp_addr == NULL)
964		first_lwp_addr = first_zombie_addr;
965	curr_lwp_addr = first_lwp_addr;
966	for (;;) {
967		td_thr_state_e ts_state;
968		int userpri;
969		unsigned userflags;
970		sigset_t mask;
971
972		/*
973		 * Read the ulwp struct.
974		 */
975		if (ta_p->model == PR_MODEL_NATIVE) {
976			ulwp_t ulwp;
977
978			if (ps_pdread(ph_p, curr_lwp_addr,
979			    &ulwp, sizeof (ulwp)) != PS_OK &&
980			    ((void) memset(&ulwp, 0, sizeof (ulwp)),
981			    ps_pdread(ph_p, curr_lwp_addr,
982			    &ulwp, REPLACEMENT_SIZE)) != PS_OK) {
983				return_val = TD_DBERR;
984				break;
985			}
986			next_lwp_addr = (psaddr_t)ulwp.ul_forw;
987
988			ts_state = ulwp.ul_dead? TD_THR_ZOMBIE :
989				ulwp.ul_stop? TD_THR_STOPPED :
990				ulwp.ul_wchan? TD_THR_SLEEP :
991				TD_THR_ACTIVE;
992			userpri = ulwp.ul_pri;
993			userflags = ulwp.ul_usropts;
994			if (ulwp.ul_dead)
995				(void) sigemptyset(&mask);
996			else
997				mask = *(sigset_t *)&ulwp.ul_sigmask;
998		} else {
999#if defined(_LP64) && defined(_SYSCALL32)
1000			ulwp32_t ulwp;
1001
1002			if (ps_pdread(ph_p, curr_lwp_addr,
1003			    &ulwp, sizeof (ulwp)) != PS_OK &&
1004			    ((void) memset(&ulwp, 0, sizeof (ulwp)),
1005			    ps_pdread(ph_p, curr_lwp_addr,
1006			    &ulwp, REPLACEMENT_SIZE32)) != PS_OK) {
1007				return_val = TD_DBERR;
1008				break;
1009			}
1010			next_lwp_addr = (psaddr_t)ulwp.ul_forw;
1011
1012			ts_state = ulwp.ul_dead? TD_THR_ZOMBIE :
1013				ulwp.ul_stop? TD_THR_STOPPED :
1014				ulwp.ul_wchan? TD_THR_SLEEP :
1015				TD_THR_ACTIVE;
1016			userpri = ulwp.ul_pri;
1017			userflags = ulwp.ul_usropts;
1018			if (ulwp.ul_dead)
1019				(void) sigemptyset(&mask);
1020			else
1021				mask = *(sigset_t *)&ulwp.ul_sigmask;
1022#else	/* _SYSCALL32 */
1023			return_val = TD_ERR;
1024			break;
1025#endif	/* _SYSCALL32 */
1026		}
1027
1028		/*
1029		 * Filter on state, priority, sigmask, and user flags.
1030		 */
1031
1032		if ((state != ts_state) &&
1033		    (state != TD_THR_ANY_STATE))
1034			goto advance;
1035
1036		if (ti_pri > userpri)
1037			goto advance;
1038
1039		if (ti_sigmask_p != TD_SIGNO_MASK &&
1040		    !sigequalset(ti_sigmask_p, &mask))
1041			goto advance;
1042
1043		if (ti_user_flags != userflags &&
1044		    ti_user_flags != (unsigned)TD_THR_ANY_USER_FLAGS)
1045			goto advance;
1046
1047		/*
1048		 * Call back - break if the return
1049		 * from the call back is non-zero.
1050		 */
1051		th.th_ta_p = (td_thragent_t *)ta_p;
1052		th.th_unique = curr_lwp_addr;
1053		if ((*cb)(&th, cbdata_p))
1054			break;
1055
1056advance:
1057		if ((curr_lwp_addr = next_lwp_addr) == first_lwp_addr) {
1058			/*
1059			 * Switch to the zombie list, unless it is NULL
1060			 * or we have already been doing the zombie list,
1061			 * in which case terminate the loop.
1062			 */
1063			if (first_zombie_addr == NULL ||
1064			    first_lwp_addr == first_zombie_addr)
1065				break;
1066			curr_lwp_addr = first_lwp_addr = first_zombie_addr;
1067		}
1068	}
1069
1070	(void) ps_pcontinue(ph_p);
1071	ph_unlock(ta_p);
1072	return (return_val);
1073}
1074
1075/*
1076 * Enable or disable process synchronization object tracking.
1077 * Currently unused by dbx.
1078 */
1079#pragma weak td_ta_sync_tracking_enable = __td_ta_sync_tracking_enable
1080td_err_e
1081__td_ta_sync_tracking_enable(td_thragent_t *ta_p, int onoff)
1082{
1083	struct ps_prochandle *ph_p;
1084	td_err_e return_val;
1085	register_sync_t enable;
1086
1087	if ((ph_p = ph_lock_ta(ta_p, &return_val)) == NULL)
1088		return (return_val);
1089	/*
1090	 * Values of tdb_register_sync in the victim process:
1091	 *	REGISTER_SYNC_ENABLE	enables registration of synch objects
1092	 *	REGISTER_SYNC_DISABLE	disables registration of synch objects
1093	 * These cause the table to be cleared and tdb_register_sync set to:
1094	 *	REGISTER_SYNC_ON	registration in effect
1095	 *	REGISTER_SYNC_OFF	registration not in effect
1096	 */
1097	enable = onoff? REGISTER_SYNC_ENABLE : REGISTER_SYNC_DISABLE;
1098	if (ps_pdwrite(ph_p, ta_p->tdb_register_sync_addr,
1099	    &enable, sizeof (enable)) != PS_OK)
1100		return_val = TD_DBERR;
1101	/*
1102	 * Remember that this interface was called (see td_ta_delete()).
1103	 */
1104	ta_p->sync_tracking = 1;
1105	ph_unlock(ta_p);
1106	return (return_val);
1107}
1108
1109/*
1110 * Iterate over all known synchronization variables.
1111 * It is very possible that the list generated is incomplete,
1112 * because the iterator can only find synchronization variables
1113 * that have been registered by the process since synchronization
1114 * object registration was enabled.
1115 * The call back function cb is called for each synchronization
1116 * variable with two arguments: a pointer to the synchronization
1117 * handle and the passed-in argument cbdata.
1118 * If cb returns a non-zero value, iterations are terminated.
1119 */
1120#pragma weak td_ta_sync_iter = __td_ta_sync_iter
1121td_err_e
1122__td_ta_sync_iter(td_thragent_t *ta_p, td_sync_iter_f *cb, void *cbdata)
1123{
1124	struct ps_prochandle *ph_p;
1125	td_err_e	return_val;
1126	int		i;
1127	register_sync_t	enable;
1128	psaddr_t	next_desc;
1129	tdb_sync_stats_t sync_stats;
1130	td_synchandle_t	synchandle;
1131	psaddr_t	psaddr;
1132	void		*vaddr;
1133	uint64_t	*sync_addr_hash = NULL;
1134
1135	if (cb == NULL)
1136		return (TD_ERR);
1137	if ((ph_p = ph_lock_ta(ta_p, &return_val)) == NULL)
1138		return (return_val);
1139	if (ps_pstop(ph_p) != PS_OK) {
1140		ph_unlock(ta_p);
1141		return (TD_DBERR);
1142	}
1143	if (ps_pdread(ph_p, ta_p->tdb_register_sync_addr,
1144	    &enable, sizeof (enable)) != PS_OK) {
1145		return_val = TD_DBERR;
1146		goto out;
1147	}
1148	if (enable != REGISTER_SYNC_ON)
1149		goto out;
1150
1151	/*
1152	 * First read the hash table.
1153	 * The hash table is large; allocate with mmap().
1154	 */
1155	if ((vaddr = mmap(NULL, TDB_HASH_SIZE * sizeof (uint64_t),
1156	    PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANON, -1, (off_t)0))
1157	    == MAP_FAILED) {
1158		return_val = TD_MALLOC;
1159		goto out;
1160	}
1161	sync_addr_hash = vaddr;
1162
1163	if (ta_p->model == PR_MODEL_NATIVE) {
1164		if (ps_pdread(ph_p, ta_p->uberdata_addr +
1165		    offsetof(uberdata_t, tdb.tdb_sync_addr_hash),
1166		    &psaddr, sizeof (&psaddr)) != PS_OK) {
1167			return_val = TD_DBERR;
1168			goto out;
1169		}
1170	} else {
1171#ifdef  _SYSCALL32
1172		caddr32_t addr;
1173
1174		if (ps_pdread(ph_p, ta_p->uberdata_addr +
1175		    offsetof(uberdata32_t, tdb.tdb_sync_addr_hash),
1176		    &addr, sizeof (addr)) != PS_OK) {
1177			return_val = TD_DBERR;
1178			goto out;
1179		}
1180		psaddr = addr;
1181#else
1182		return_val = TD_ERR;
1183		goto out;
1184#endif /* _SYSCALL32 */
1185	}
1186
1187	if (psaddr == NULL)
1188		goto out;
1189	if (ps_pdread(ph_p, psaddr, sync_addr_hash,
1190	    TDB_HASH_SIZE * sizeof (uint64_t)) != PS_OK) {
1191		return_val = TD_DBERR;
1192		goto out;
1193	}
1194
1195	/*
1196	 * Now scan the hash table.
1197	 */
1198	for (i = 0; i < TDB_HASH_SIZE; i++) {
1199		for (next_desc = (psaddr_t)sync_addr_hash[i];
1200		    next_desc != NULL;
1201		    next_desc = (psaddr_t)sync_stats.next) {
1202			if (ps_pdread(ph_p, next_desc,
1203			    &sync_stats, sizeof (sync_stats)) != PS_OK) {
1204				return_val = TD_DBERR;
1205				goto out;
1206			}
1207			if (sync_stats.un.type == TDB_NONE) {
1208				/* not registered since registration enabled */
1209				continue;
1210			}
1211			synchandle.sh_ta_p = ta_p;
1212			synchandle.sh_unique = (psaddr_t)sync_stats.sync_addr;
1213			if ((*cb)(&synchandle, cbdata) != 0)
1214				goto out;
1215		}
1216	}
1217
1218out:
1219	if (sync_addr_hash != NULL)
1220		(void) munmap((void *)sync_addr_hash,
1221		    TDB_HASH_SIZE * sizeof (uint64_t));
1222	(void) ps_pcontinue(ph_p);
1223	ph_unlock(ta_p);
1224	return (return_val);
1225}
1226
1227/*
1228 * Enable process statistics collection.
1229 */
1230#pragma weak td_ta_enable_stats = __td_ta_enable_stats
1231/* ARGSUSED */
1232td_err_e
1233__td_ta_enable_stats(const td_thragent_t *ta_p, int onoff)
1234{
1235	return (TD_NOCAPAB);
1236}
1237
1238/*
1239 * Reset process statistics.
1240 */
1241#pragma weak td_ta_reset_stats = __td_ta_reset_stats
1242/* ARGSUSED */
1243td_err_e
1244__td_ta_reset_stats(const td_thragent_t *ta_p)
1245{
1246	return (TD_NOCAPAB);
1247}
1248
1249/*
1250 * Read process statistics.
1251 */
1252#pragma weak td_ta_get_stats = __td_ta_get_stats
1253/* ARGSUSED */
1254td_err_e
1255__td_ta_get_stats(const td_thragent_t *ta_p, td_ta_stats_t *tstats)
1256{
1257	return (TD_NOCAPAB);
1258}
1259
1260/*
1261 * Transfer information from lwp struct to thread information struct.
1262 * XXX -- lots of this needs cleaning up.
1263 */
1264static void
1265td_thr2to(td_thragent_t *ta_p, psaddr_t ts_addr,
1266	ulwp_t *ulwp, td_thrinfo_t *ti_p)
1267{
1268	lwpid_t lwpid;
1269
1270	if ((lwpid = ulwp->ul_lwpid) == 0)
1271		lwpid = 1;
1272	(void) memset(ti_p, 0, sizeof (*ti_p));
1273	ti_p->ti_ta_p = ta_p;
1274	ti_p->ti_user_flags = ulwp->ul_usropts;
1275	ti_p->ti_tid = lwpid;
1276	ti_p->ti_exitval = ulwp->ul_rval;
1277	ti_p->ti_startfunc = (psaddr_t)ulwp->ul_startpc;
1278	if (!ulwp->ul_dead) {
1279		/*
1280		 * The bloody fools got this backwards!
1281		 */
1282		ti_p->ti_stkbase = (psaddr_t)ulwp->ul_stktop;
1283		ti_p->ti_stksize = ulwp->ul_stksiz;
1284	}
1285	ti_p->ti_ro_area = ts_addr;
1286	ti_p->ti_ro_size = ulwp->ul_replace?
1287		REPLACEMENT_SIZE : sizeof (ulwp_t);
1288	ti_p->ti_state = ulwp->ul_dead? TD_THR_ZOMBIE :
1289		ulwp->ul_stop? TD_THR_STOPPED :
1290		ulwp->ul_wchan? TD_THR_SLEEP :
1291		TD_THR_ACTIVE;
1292	ti_p->ti_db_suspended = 0;
1293	ti_p->ti_type = TD_THR_USER;
1294	ti_p->ti_sp = ulwp->ul_sp;
1295	ti_p->ti_flags = 0;
1296	ti_p->ti_pri = ulwp->ul_pri;
1297	ti_p->ti_lid = lwpid;
1298	if (!ulwp->ul_dead)
1299		ti_p->ti_sigmask = ulwp->ul_sigmask;
1300	ti_p->ti_traceme = 0;
1301	ti_p->ti_preemptflag = 0;
1302	ti_p->ti_pirecflag = 0;
1303	(void) sigemptyset(&ti_p->ti_pending);
1304	ti_p->ti_events = ulwp->ul_td_evbuf.eventmask;
1305}
1306
1307#if defined(_LP64) && defined(_SYSCALL32)
1308static void
1309td_thr2to32(td_thragent_t *ta_p, psaddr_t ts_addr,
1310	ulwp32_t *ulwp, td_thrinfo_t *ti_p)
1311{
1312	lwpid_t lwpid;
1313
1314	if ((lwpid = ulwp->ul_lwpid) == 0)
1315		lwpid = 1;
1316	(void) memset(ti_p, 0, sizeof (*ti_p));
1317	ti_p->ti_ta_p = ta_p;
1318	ti_p->ti_user_flags = ulwp->ul_usropts;
1319	ti_p->ti_tid = lwpid;
1320	ti_p->ti_exitval = (void *)(uintptr_t)ulwp->ul_rval;
1321	ti_p->ti_startfunc = (psaddr_t)ulwp->ul_startpc;
1322	if (!ulwp->ul_dead) {
1323		/*
1324		 * The bloody fools got this backwards!
1325		 */
1326		ti_p->ti_stkbase = (psaddr_t)ulwp->ul_stktop;
1327		ti_p->ti_stksize = ulwp->ul_stksiz;
1328	}
1329	ti_p->ti_ro_area = ts_addr;
1330	ti_p->ti_ro_size = ulwp->ul_replace?
1331		REPLACEMENT_SIZE32 : sizeof (ulwp32_t);
1332	ti_p->ti_state = ulwp->ul_dead? TD_THR_ZOMBIE :
1333		ulwp->ul_stop? TD_THR_STOPPED :
1334		ulwp->ul_wchan? TD_THR_SLEEP :
1335		TD_THR_ACTIVE;
1336	ti_p->ti_db_suspended = 0;
1337	ti_p->ti_type = TD_THR_USER;
1338	ti_p->ti_sp = (uint32_t)ulwp->ul_sp;
1339	ti_p->ti_flags = 0;
1340	ti_p->ti_pri = ulwp->ul_pri;
1341	ti_p->ti_lid = lwpid;
1342	if (!ulwp->ul_dead)
1343		ti_p->ti_sigmask = *(sigset_t *)&ulwp->ul_sigmask;
1344	ti_p->ti_traceme = 0;
1345	ti_p->ti_preemptflag = 0;
1346	ti_p->ti_pirecflag = 0;
1347	(void) sigemptyset(&ti_p->ti_pending);
1348	ti_p->ti_events = ulwp->ul_td_evbuf.eventmask;
1349}
1350#endif	/* _SYSCALL32 */
1351
1352/*
1353 * Get thread information.
1354 */
1355#pragma weak td_thr_get_info = __td_thr_get_info
1356td_err_e
1357__td_thr_get_info(td_thrhandle_t *th_p, td_thrinfo_t *ti_p)
1358{
1359	struct ps_prochandle *ph_p;
1360	td_thragent_t	*ta_p;
1361	td_err_e	return_val;
1362	psaddr_t	psaddr;
1363
1364	if (ti_p == NULL)
1365		return (TD_ERR);
1366	(void) memset(ti_p, NULL, sizeof (*ti_p));
1367
1368	if ((ph_p = ph_lock_th(th_p, &return_val)) == NULL)
1369		return (return_val);
1370	ta_p = th_p->th_ta_p;
1371	if (ps_pstop(ph_p) != PS_OK) {
1372		ph_unlock(ta_p);
1373		return (TD_DBERR);
1374	}
1375
1376	/*
1377	 * Read the ulwp struct from the process.
1378	 * Transfer the ulwp struct to the thread information struct.
1379	 */
1380	psaddr = th_p->th_unique;
1381	if (ta_p->model == PR_MODEL_NATIVE) {
1382		ulwp_t ulwp;
1383
1384		if (ps_pdread(ph_p, psaddr, &ulwp, sizeof (ulwp)) != PS_OK &&
1385		    ((void) memset(&ulwp, 0, sizeof (ulwp)),
1386		    ps_pdread(ph_p, psaddr, &ulwp, REPLACEMENT_SIZE)) != PS_OK)
1387			return_val = TD_DBERR;
1388		else
1389			td_thr2to(ta_p, psaddr, &ulwp, ti_p);
1390	} else {
1391#if defined(_LP64) && defined(_SYSCALL32)
1392		ulwp32_t ulwp;
1393
1394		if (ps_pdread(ph_p, psaddr, &ulwp, sizeof (ulwp)) != PS_OK &&
1395		    ((void) memset(&ulwp, 0, sizeof (ulwp)),
1396		    ps_pdread(ph_p, psaddr, &ulwp, REPLACEMENT_SIZE32)) !=
1397				PS_OK)
1398			return_val = TD_DBERR;
1399		else
1400			td_thr2to32(ta_p, psaddr, &ulwp, ti_p);
1401#else
1402		return_val = TD_ERR;
1403#endif	/* _SYSCALL32 */
1404	}
1405
1406	(void) ps_pcontinue(ph_p);
1407	ph_unlock(ta_p);
1408	return (return_val);
1409}
1410
1411/*
1412 * Given a process and an event number, return information about
1413 * an address in the process or at which a breakpoint can be set
1414 * to monitor the event.
1415 */
1416#pragma weak td_ta_event_addr = __td_ta_event_addr
1417td_err_e
1418__td_ta_event_addr(td_thragent_t *ta_p, td_event_e event, td_notify_t *notify_p)
1419{
1420	if (ta_p == NULL)
1421		return (TD_BADTA);
1422	if (event < TD_MIN_EVENT_NUM || event > TD_MAX_EVENT_NUM)
1423		return (TD_NOEVENT);
1424	if (notify_p == NULL)
1425		return (TD_ERR);
1426
1427	notify_p->type = NOTIFY_BPT;
1428	notify_p->u.bptaddr = ta_p->tdb_events[event - TD_MIN_EVENT_NUM];
1429
1430	return (TD_OK);
1431}
1432
1433/*
1434 * Add the events in eventset 2 to eventset 1.
1435 */
1436static void
1437eventsetaddset(td_thr_events_t *event1_p, td_thr_events_t *event2_p)
1438{
1439	int	i;
1440
1441	for (i = 0; i < TD_EVENTSIZE; i++)
1442		event1_p->event_bits[i] |= event2_p->event_bits[i];
1443}
1444
1445/*
1446 * Delete the events in eventset 2 from eventset 1.
1447 */
1448static void
1449eventsetdelset(td_thr_events_t *event1_p, td_thr_events_t *event2_p)
1450{
1451	int	i;
1452
1453	for (i = 0; i < TD_EVENTSIZE; i++)
1454		event1_p->event_bits[i] &= ~event2_p->event_bits[i];
1455}
1456
1457/*
1458 * Either add or delete the given event set from a thread's event mask.
1459 */
1460static td_err_e
1461mod_eventset(td_thrhandle_t *th_p, td_thr_events_t *events, int onoff)
1462{
1463	struct ps_prochandle *ph_p;
1464	td_err_e	return_val = TD_OK;
1465	char		enable;
1466	td_thr_events_t	evset;
1467	psaddr_t	psaddr_evset;
1468	psaddr_t	psaddr_enab;
1469
1470	if ((ph_p = ph_lock_th(th_p, &return_val)) == NULL)
1471		return (return_val);
1472	if (th_p->th_ta_p->model == PR_MODEL_NATIVE) {
1473		ulwp_t *ulwp = (ulwp_t *)th_p->th_unique;
1474		psaddr_evset = (psaddr_t)&ulwp->ul_td_evbuf.eventmask;
1475		psaddr_enab = (psaddr_t)&ulwp->ul_td_events_enable;
1476	} else {
1477#if defined(_LP64) && defined(_SYSCALL32)
1478		ulwp32_t *ulwp = (ulwp32_t *)th_p->th_unique;
1479		psaddr_evset = (psaddr_t)&ulwp->ul_td_evbuf.eventmask;
1480		psaddr_enab = (psaddr_t)&ulwp->ul_td_events_enable;
1481#else
1482		ph_unlock(th_p->th_ta_p);
1483		return (TD_ERR);
1484#endif	/* _SYSCALL32 */
1485	}
1486	if (ps_pstop(ph_p) != PS_OK) {
1487		ph_unlock(th_p->th_ta_p);
1488		return (TD_DBERR);
1489	}
1490
1491	if (ps_pdread(ph_p, psaddr_evset, &evset, sizeof (evset)) != PS_OK)
1492		return_val = TD_DBERR;
1493	else {
1494		if (onoff)
1495			eventsetaddset(&evset, events);
1496		else
1497			eventsetdelset(&evset, events);
1498		if (ps_pdwrite(ph_p, psaddr_evset, &evset, sizeof (evset))
1499		    != PS_OK)
1500			return_val = TD_DBERR;
1501		else {
1502			enable = 0;
1503			if (td_eventismember(&evset, TD_EVENTS_ENABLE))
1504				enable = 1;
1505			if (ps_pdwrite(ph_p, psaddr_enab,
1506			    &enable, sizeof (enable)) != PS_OK)
1507				return_val = TD_DBERR;
1508		}
1509	}
1510
1511	(void) ps_pcontinue(ph_p);
1512	ph_unlock(th_p->th_ta_p);
1513	return (return_val);
1514}
1515
1516/*
1517 * Enable or disable tracing for a given thread.  Tracing
1518 * is filtered based on the event mask of each thread.  Tracing
1519 * can be turned on/off for the thread without changing thread
1520 * event mask.
1521 * Currently unused by dbx.
1522 */
1523#pragma weak td_thr_event_enable = __td_thr_event_enable
1524td_err_e
1525__td_thr_event_enable(td_thrhandle_t *th_p, int onoff)
1526{
1527	td_thr_events_t	evset;
1528
1529	td_event_emptyset(&evset);
1530	td_event_addset(&evset, TD_EVENTS_ENABLE);
1531	return (mod_eventset(th_p, &evset, onoff));
1532}
1533
1534/*
1535 * Set event mask to enable event. event is turned on in
1536 * event mask for thread.  If a thread encounters an event
1537 * for which its event mask is on, notification will be sent
1538 * to the debugger.
1539 * Addresses for each event are provided to the
1540 * debugger.  It is assumed that a breakpoint of some type will
1541 * be placed at that address.  If the event mask for the thread
1542 * is on, the instruction at the address will be executed.
1543 * Otherwise, the instruction will be skipped.
1544 */
1545#pragma weak td_thr_set_event = __td_thr_set_event
1546td_err_e
1547__td_thr_set_event(td_thrhandle_t *th_p, td_thr_events_t *events)
1548{
1549	return (mod_eventset(th_p, events, 1));
1550}
1551
1552/*
1553 * Enable or disable a set of events in the process-global event mask,
1554 * depending on the value of onoff.
1555 */
1556static td_err_e
1557td_ta_mod_event(td_thragent_t *ta_p, td_thr_events_t *events, int onoff)
1558{
1559	struct ps_prochandle *ph_p;
1560	td_thr_events_t targ_eventset;
1561	td_err_e	return_val;
1562
1563	if ((ph_p = ph_lock_ta(ta_p, &return_val)) == NULL)
1564		return (return_val);
1565	if (ps_pstop(ph_p) != PS_OK) {
1566		ph_unlock(ta_p);
1567		return (TD_DBERR);
1568	}
1569	if (ps_pdread(ph_p, ta_p->tdb_eventmask_addr,
1570	    &targ_eventset, sizeof (targ_eventset)) != PS_OK)
1571		return_val = TD_DBERR;
1572	else {
1573		if (onoff)
1574			eventsetaddset(&targ_eventset, events);
1575		else
1576			eventsetdelset(&targ_eventset, events);
1577		if (ps_pdwrite(ph_p, ta_p->tdb_eventmask_addr,
1578		    &targ_eventset, sizeof (targ_eventset)) != PS_OK)
1579			return_val = TD_DBERR;
1580	}
1581	(void) ps_pcontinue(ph_p);
1582	ph_unlock(ta_p);
1583	return (return_val);
1584}
1585
1586/*
1587 * Enable a set of events in the process-global event mask.
1588 */
1589#pragma weak td_ta_set_event = __td_ta_set_event
1590td_err_e
1591__td_ta_set_event(td_thragent_t *ta_p, td_thr_events_t *events)
1592{
1593	return (td_ta_mod_event(ta_p, events, 1));
1594}
1595
1596/*
1597 * Set event mask to disable the given event set; these events are cleared
1598 * from the event mask of the thread.  Events that occur for a thread
1599 * with the event masked off will not cause notification to be
1600 * sent to the debugger (see td_thr_set_event for fuller description).
1601 */
1602#pragma weak td_thr_clear_event = __td_thr_clear_event
1603td_err_e
1604__td_thr_clear_event(td_thrhandle_t *th_p, td_thr_events_t *events)
1605{
1606	return (mod_eventset(th_p, events, 0));
1607}
1608
1609/*
1610 * Disable a set of events in the process-global event mask.
1611 */
1612#pragma weak td_ta_clear_event = __td_ta_clear_event
1613td_err_e
1614__td_ta_clear_event(td_thragent_t *ta_p, td_thr_events_t *events)
1615{
1616	return (td_ta_mod_event(ta_p, events, 0));
1617}
1618
1619/*
1620 * This function returns the most recent event message, if any,
1621 * associated with a thread.  Given a thread handle, return the message
1622 * corresponding to the event encountered by the thread.  Only one
1623 * message per thread is saved.  Messages from earlier events are lost
1624 * when later events occur.
1625 */
1626#pragma weak td_thr_event_getmsg = __td_thr_event_getmsg
1627td_err_e
1628__td_thr_event_getmsg(td_thrhandle_t *th_p, td_event_msg_t *msg)
1629{
1630	struct ps_prochandle *ph_p;
1631	td_err_e	return_val = TD_OK;
1632	psaddr_t	psaddr;
1633
1634	if ((ph_p = ph_lock_th(th_p, &return_val)) == NULL)
1635		return (return_val);
1636	if (ps_pstop(ph_p) != PS_OK) {
1637		ph_unlock(th_p->th_ta_p);
1638		return (TD_BADTA);
1639	}
1640	if (th_p->th_ta_p->model == PR_MODEL_NATIVE) {
1641		ulwp_t *ulwp = (ulwp_t *)th_p->th_unique;
1642		td_evbuf_t evbuf;
1643
1644		psaddr = (psaddr_t)&ulwp->ul_td_evbuf;
1645		if (ps_pdread(ph_p, psaddr, &evbuf, sizeof (evbuf)) != PS_OK) {
1646			return_val = TD_DBERR;
1647		} else if (evbuf.eventnum == TD_EVENT_NONE) {
1648			return_val = TD_NOEVENT;
1649		} else {
1650			msg->event = evbuf.eventnum;
1651			msg->th_p = (td_thrhandle_t *)th_p;
1652			msg->msg.data = (uintptr_t)evbuf.eventdata;
1653			/* "Consume" the message */
1654			evbuf.eventnum = TD_EVENT_NONE;
1655			evbuf.eventdata = NULL;
1656			if (ps_pdwrite(ph_p, psaddr, &evbuf, sizeof (evbuf))
1657			    != PS_OK)
1658				return_val = TD_DBERR;
1659		}
1660	} else {
1661#if defined(_LP64) && defined(_SYSCALL32)
1662		ulwp32_t *ulwp = (ulwp32_t *)th_p->th_unique;
1663		td_evbuf32_t evbuf;
1664
1665		psaddr = (psaddr_t)&ulwp->ul_td_evbuf;
1666		if (ps_pdread(ph_p, psaddr, &evbuf, sizeof (evbuf)) != PS_OK) {
1667			return_val = TD_DBERR;
1668		} else if (evbuf.eventnum == TD_EVENT_NONE) {
1669			return_val = TD_NOEVENT;
1670		} else {
1671			msg->event = evbuf.eventnum;
1672			msg->th_p = (td_thrhandle_t *)th_p;
1673			msg->msg.data = (uintptr_t)evbuf.eventdata;
1674			/* "Consume" the message */
1675			evbuf.eventnum = TD_EVENT_NONE;
1676			evbuf.eventdata = NULL;
1677			if (ps_pdwrite(ph_p, psaddr, &evbuf, sizeof (evbuf))
1678			    != PS_OK)
1679				return_val = TD_DBERR;
1680		}
1681#else
1682		return_val = TD_ERR;
1683#endif	/* _SYSCALL32 */
1684	}
1685
1686	(void) ps_pcontinue(ph_p);
1687	ph_unlock(th_p->th_ta_p);
1688	return (return_val);
1689}
1690
1691/*
1692 * The callback function td_ta_event_getmsg uses when looking for
1693 * a thread with an event.  A thin wrapper around td_thr_event_getmsg.
1694 */
1695static int
1696event_msg_cb(const td_thrhandle_t *th_p, void *arg)
1697{
1698	static td_thrhandle_t th;
1699	td_event_msg_t *msg = arg;
1700
1701	if (__td_thr_event_getmsg((td_thrhandle_t *)th_p, msg) == TD_OK) {
1702		/*
1703		 * Got an event, stop iterating.
1704		 *
1705		 * Because of past mistakes in interface definition,
1706		 * we are forced to pass back a static local variable
1707		 * for the thread handle because th_p is a pointer
1708		 * to a local variable in __td_ta_thr_iter().
1709		 * Grr...
1710		 */
1711		th = *th_p;
1712		msg->th_p = &th;
1713		return (1);
1714	}
1715	return (0);
1716}
1717
1718/*
1719 * This function is just like td_thr_event_getmsg, except that it is
1720 * passed a process handle rather than a thread handle, and returns
1721 * an event message for some thread in the process that has an event
1722 * message pending.  If no thread has an event message pending, this
1723 * routine returns TD_NOEVENT.  Thus, all pending event messages may
1724 * be collected from a process by repeatedly calling this routine
1725 * until it returns TD_NOEVENT.
1726 */
1727#pragma weak td_ta_event_getmsg = __td_ta_event_getmsg
1728td_err_e
1729__td_ta_event_getmsg(td_thragent_t *ta_p, td_event_msg_t *msg)
1730{
1731	td_err_e return_val;
1732
1733	if (ta_p == NULL)
1734		return (TD_BADTA);
1735	if (ta_p->ph_p == NULL)
1736		return (TD_BADPH);
1737	if (msg == NULL)
1738		return (TD_ERR);
1739	msg->event = TD_EVENT_NONE;
1740	if ((return_val = __td_ta_thr_iter(ta_p, event_msg_cb, msg,
1741	    TD_THR_ANY_STATE, TD_THR_LOWEST_PRIORITY, TD_SIGNO_MASK,
1742	    TD_THR_ANY_USER_FLAGS)) != TD_OK)
1743		return (return_val);
1744	if (msg->event == TD_EVENT_NONE)
1745		return (TD_NOEVENT);
1746	return (TD_OK);
1747}
1748
1749static lwpid_t
1750thr_to_lwpid(const td_thrhandle_t *th_p)
1751{
1752	struct ps_prochandle *ph_p = th_p->th_ta_p->ph_p;
1753	lwpid_t lwpid;
1754
1755	/*
1756	 * The caller holds the prochandle lock
1757	 * and has already verfied everything.
1758	 */
1759	if (th_p->th_ta_p->model == PR_MODEL_NATIVE) {
1760		ulwp_t *ulwp = (ulwp_t *)th_p->th_unique;
1761
1762		if (ps_pdread(ph_p, (psaddr_t)&ulwp->ul_lwpid,
1763		    &lwpid, sizeof (lwpid)) != PS_OK)
1764			lwpid = 0;
1765		else if (lwpid == 0)
1766			lwpid = 1;
1767	} else {
1768#if defined(_LP64) && defined(_SYSCALL32)
1769		ulwp32_t *ulwp = (ulwp32_t *)th_p->th_unique;
1770
1771		if (ps_pdread(ph_p, (psaddr_t)&ulwp->ul_lwpid,
1772		    &lwpid, sizeof (lwpid)) != PS_OK)
1773			lwpid = 0;
1774		else if (lwpid == 0)
1775			lwpid = 1;
1776#else
1777		lwpid = 0;
1778#endif	/* _SYSCALL32 */
1779	}
1780
1781	return (lwpid);
1782}
1783
1784/*
1785 * Suspend a thread.
1786 * XXX: What does this mean in a one-level model?
1787 */
1788#pragma weak td_thr_dbsuspend = __td_thr_dbsuspend
1789td_err_e
1790__td_thr_dbsuspend(const td_thrhandle_t *th_p)
1791{
1792	struct ps_prochandle *ph_p;
1793	td_err_e return_val;
1794
1795	if ((ph_p = ph_lock_th(th_p, &return_val)) == NULL)
1796		return (return_val);
1797	if (ps_lstop(ph_p, thr_to_lwpid(th_p)) != PS_OK)
1798		return_val = TD_DBERR;
1799	ph_unlock(th_p->th_ta_p);
1800	return (return_val);
1801}
1802
1803/*
1804 * Resume a suspended thread.
1805 * XXX: What does this mean in a one-level model?
1806 */
1807#pragma weak td_thr_dbresume = __td_thr_dbresume
1808td_err_e
1809__td_thr_dbresume(const td_thrhandle_t *th_p)
1810{
1811	struct ps_prochandle *ph_p;
1812	td_err_e return_val;
1813
1814	if ((ph_p = ph_lock_th(th_p, &return_val)) == NULL)
1815		return (return_val);
1816	if (ps_lcontinue(ph_p, thr_to_lwpid(th_p)) != PS_OK)
1817		return_val = TD_DBERR;
1818	ph_unlock(th_p->th_ta_p);
1819	return (return_val);
1820}
1821
1822/*
1823 * Set a thread's signal mask.
1824 * Currently unused by dbx.
1825 */
1826#pragma weak td_thr_sigsetmask = __td_thr_sigsetmask
1827/* ARGSUSED */
1828td_err_e
1829__td_thr_sigsetmask(const td_thrhandle_t *th_p, const sigset_t ti_sigmask)
1830{
1831	return (TD_NOCAPAB);
1832}
1833
1834/*
1835 * Set a thread's "signals-pending" set.
1836 * Currently unused by dbx.
1837 */
1838#pragma weak td_thr_setsigpending = __td_thr_setsigpending
1839/* ARGSUSED */
1840td_err_e
1841__td_thr_setsigpending(const td_thrhandle_t *th_p,
1842	uchar_t ti_pending_flag, const sigset_t ti_pending)
1843{
1844	return (TD_NOCAPAB);
1845}
1846
1847/*
1848 * Get a thread's general register set.
1849 */
1850#pragma weak td_thr_getgregs = __td_thr_getgregs
1851td_err_e
1852__td_thr_getgregs(td_thrhandle_t *th_p, prgregset_t regset)
1853{
1854	struct ps_prochandle *ph_p;
1855	td_err_e return_val;
1856
1857	if ((ph_p = ph_lock_th(th_p, &return_val)) == NULL)
1858		return (return_val);
1859	if (ps_pstop(ph_p) != PS_OK) {
1860		ph_unlock(th_p->th_ta_p);
1861		return (TD_DBERR);
1862	}
1863
1864	if (ps_lgetregs(ph_p, thr_to_lwpid(th_p), regset) != PS_OK)
1865		return_val = TD_DBERR;
1866
1867	(void) ps_pcontinue(ph_p);
1868	ph_unlock(th_p->th_ta_p);
1869	return (return_val);
1870}
1871
1872/*
1873 * Set a thread's general register set.
1874 */
1875#pragma weak td_thr_setgregs = __td_thr_setgregs
1876td_err_e
1877__td_thr_setgregs(td_thrhandle_t *th_p, const prgregset_t regset)
1878{
1879	struct ps_prochandle *ph_p;
1880	td_err_e return_val;
1881
1882	if ((ph_p = ph_lock_th(th_p, &return_val)) == NULL)
1883		return (return_val);
1884	if (ps_pstop(ph_p) != PS_OK) {
1885		ph_unlock(th_p->th_ta_p);
1886		return (TD_DBERR);
1887	}
1888
1889	if (ps_lsetregs(ph_p, thr_to_lwpid(th_p), regset) != PS_OK)
1890		return_val = TD_DBERR;
1891
1892	(void) ps_pcontinue(ph_p);
1893	ph_unlock(th_p->th_ta_p);
1894	return (return_val);
1895}
1896
1897/*
1898 * Get a thread's floating-point register set.
1899 */
1900#pragma weak td_thr_getfpregs = __td_thr_getfpregs
1901td_err_e
1902__td_thr_getfpregs(td_thrhandle_t *th_p, prfpregset_t *fpregset)
1903{
1904	struct ps_prochandle *ph_p;
1905	td_err_e return_val;
1906
1907	if ((ph_p = ph_lock_th(th_p, &return_val)) == NULL)
1908		return (return_val);
1909	if (ps_pstop(ph_p) != PS_OK) {
1910		ph_unlock(th_p->th_ta_p);
1911		return (TD_DBERR);
1912	}
1913
1914	if (ps_lgetfpregs(ph_p, thr_to_lwpid(th_p), fpregset) != PS_OK)
1915		return_val = TD_DBERR;
1916
1917	(void) ps_pcontinue(ph_p);
1918	ph_unlock(th_p->th_ta_p);
1919	return (return_val);
1920}
1921
1922/*
1923 * Set a thread's floating-point register set.
1924 */
1925#pragma weak td_thr_setfpregs = __td_thr_setfpregs
1926td_err_e
1927__td_thr_setfpregs(td_thrhandle_t *th_p, const prfpregset_t *fpregset)
1928{
1929	struct ps_prochandle *ph_p;
1930	td_err_e return_val;
1931
1932	if ((ph_p = ph_lock_th(th_p, &return_val)) == NULL)
1933		return (return_val);
1934	if (ps_pstop(ph_p) != PS_OK) {
1935		ph_unlock(th_p->th_ta_p);
1936		return (TD_DBERR);
1937	}
1938
1939	if (ps_lsetfpregs(ph_p, thr_to_lwpid(th_p), fpregset) != PS_OK)
1940		return_val = TD_DBERR;
1941
1942	(void) ps_pcontinue(ph_p);
1943	ph_unlock(th_p->th_ta_p);
1944	return (return_val);
1945}
1946
1947/*
1948 * Get the size of the extra state register set for this architecture.
1949 * Currently unused by dbx.
1950 */
1951#pragma weak td_thr_getxregsize = __td_thr_getxregsize
1952/* ARGSUSED */
1953td_err_e
1954__td_thr_getxregsize(td_thrhandle_t *th_p, int *xregsize)
1955{
1956#if defined(__sparc)
1957	struct ps_prochandle *ph_p;
1958	td_err_e return_val;
1959
1960	if ((ph_p = ph_lock_th(th_p, &return_val)) == NULL)
1961		return (return_val);
1962	if (ps_pstop(ph_p) != PS_OK) {
1963		ph_unlock(th_p->th_ta_p);
1964		return (TD_DBERR);
1965	}
1966
1967	if (ps_lgetxregsize(ph_p, thr_to_lwpid(th_p), xregsize) != PS_OK)
1968		return_val = TD_DBERR;
1969
1970	(void) ps_pcontinue(ph_p);
1971	ph_unlock(th_p->th_ta_p);
1972	return (return_val);
1973#else	/* __sparc */
1974	return (TD_NOXREGS);
1975#endif	/* __sparc */
1976}
1977
1978/*
1979 * Get a thread's extra state register set.
1980 */
1981#pragma weak td_thr_getxregs = __td_thr_getxregs
1982/* ARGSUSED */
1983td_err_e
1984__td_thr_getxregs(td_thrhandle_t *th_p, void *xregset)
1985{
1986#if defined(__sparc)
1987	struct ps_prochandle *ph_p;
1988	td_err_e return_val;
1989
1990	if ((ph_p = ph_lock_th(th_p, &return_val)) == NULL)
1991		return (return_val);
1992	if (ps_pstop(ph_p) != PS_OK) {
1993		ph_unlock(th_p->th_ta_p);
1994		return (TD_DBERR);
1995	}
1996
1997	if (ps_lgetxregs(ph_p, thr_to_lwpid(th_p), (caddr_t)xregset) != PS_OK)
1998		return_val = TD_DBERR;
1999
2000	(void) ps_pcontinue(ph_p);
2001	ph_unlock(th_p->th_ta_p);
2002	return (return_val);
2003#else	/* __sparc */
2004	return (TD_NOXREGS);
2005#endif	/* __sparc */
2006}
2007
2008/*
2009 * Set a thread's extra state register set.
2010 */
2011#pragma weak td_thr_setxregs = __td_thr_setxregs
2012/* ARGSUSED */
2013td_err_e
2014__td_thr_setxregs(td_thrhandle_t *th_p, const void *xregset)
2015{
2016#if defined(__sparc)
2017	struct ps_prochandle *ph_p;
2018	td_err_e return_val;
2019
2020	if ((ph_p = ph_lock_th(th_p, &return_val)) == NULL)
2021		return (return_val);
2022	if (ps_pstop(ph_p) != PS_OK) {
2023		ph_unlock(th_p->th_ta_p);
2024		return (TD_DBERR);
2025	}
2026
2027	if (ps_lsetxregs(ph_p, thr_to_lwpid(th_p), (caddr_t)xregset) != PS_OK)
2028		return_val = TD_DBERR;
2029
2030	(void) ps_pcontinue(ph_p);
2031	ph_unlock(th_p->th_ta_p);
2032	return (return_val);
2033#else	/* __sparc */
2034	return (TD_NOXREGS);
2035#endif	/* __sparc */
2036}
2037
2038struct searcher {
2039	psaddr_t	addr;
2040	int		status;
2041};
2042
2043/*
2044 * Check the struct thread address in *th_p again first
2045 * value in "data".  If value in data is found, set second value
2046 * in "data" to 1 and return 1 to terminate iterations.
2047 * This function is used by td_thr_validate() to verify that
2048 * a thread handle is valid.
2049 */
2050static int
2051td_searcher(const td_thrhandle_t *th_p, void *data)
2052{
2053	struct searcher *searcher_data = (struct searcher *)data;
2054
2055	if (searcher_data->addr == th_p->th_unique) {
2056		searcher_data->status = 1;
2057		return (1);
2058	}
2059	return (0);
2060}
2061
2062/*
2063 * Validate the thread handle.  Check that
2064 * a thread exists in the thread agent/process that
2065 * corresponds to thread with handle *th_p.
2066 * Currently unused by dbx.
2067 */
2068#pragma weak td_thr_validate = __td_thr_validate
2069td_err_e
2070__td_thr_validate(const td_thrhandle_t *th_p)
2071{
2072	td_err_e return_val;
2073	struct searcher searcher_data = {0, 0};
2074
2075	if (th_p == NULL)
2076		return (TD_BADTH);
2077	if (th_p->th_unique == NULL || th_p->th_ta_p == NULL)
2078		return (TD_BADTH);
2079
2080	/*
2081	 * LOCKING EXCEPTION - Locking is not required
2082	 * here because no use of the thread agent is made (other
2083	 * than the sanity check) and checking of the thread
2084	 * agent will be done in __td_ta_thr_iter.
2085	 */
2086
2087	searcher_data.addr = th_p->th_unique;
2088	return_val = __td_ta_thr_iter(th_p->th_ta_p,
2089		td_searcher, &searcher_data,
2090		TD_THR_ANY_STATE, TD_THR_LOWEST_PRIORITY,
2091		TD_SIGNO_MASK, TD_THR_ANY_USER_FLAGS);
2092
2093	if (return_val == TD_OK && searcher_data.status == 0)
2094		return_val = TD_NOTHR;
2095
2096	return (return_val);
2097}
2098
2099/*
2100 * Get a thread's private binding to a given thread specific
2101 * data(TSD) key(see thr_getspecific(3T).  If the thread doesn't
2102 * have a binding for a particular key, then NULL is returned.
2103 */
2104#pragma weak td_thr_tsd = __td_thr_tsd
2105td_err_e
2106__td_thr_tsd(td_thrhandle_t *th_p, thread_key_t key, void **data_pp)
2107{
2108	struct ps_prochandle *ph_p;
2109	td_thragent_t	*ta_p;
2110	td_err_e	return_val;
2111	int		maxkey;
2112	int		nkey;
2113	psaddr_t	tsd_paddr;
2114
2115	if (data_pp == NULL)
2116		return (TD_ERR);
2117	*data_pp = NULL;
2118	if ((ph_p = ph_lock_th(th_p, &return_val)) == NULL)
2119		return (return_val);
2120	ta_p = th_p->th_ta_p;
2121	if (ps_pstop(ph_p) != PS_OK) {
2122		ph_unlock(ta_p);
2123		return (TD_DBERR);
2124	}
2125
2126	if (ta_p->model == PR_MODEL_NATIVE) {
2127		ulwp_t *ulwp = (ulwp_t *)th_p->th_unique;
2128		tsd_metadata_t tsdm;
2129		tsd_t stsd;
2130
2131		if (ps_pdread(ph_p,
2132		    ta_p->uberdata_addr + offsetof(uberdata_t, tsd_metadata),
2133		    &tsdm, sizeof (tsdm)) != PS_OK)
2134			return_val = TD_DBERR;
2135		else if (ps_pdread(ph_p, (psaddr_t)&ulwp->ul_stsd,
2136		    &tsd_paddr, sizeof (tsd_paddr)) != PS_OK)
2137			return_val = TD_DBERR;
2138		else if (tsd_paddr != NULL &&
2139		    ps_pdread(ph_p, tsd_paddr, &stsd, sizeof (stsd)) != PS_OK)
2140			return_val = TD_DBERR;
2141		else {
2142			maxkey = tsdm.tsdm_nused;
2143			nkey = tsd_paddr == NULL ? TSD_NFAST : stsd.tsd_nalloc;
2144
2145			if (key < TSD_NFAST)
2146				tsd_paddr = (psaddr_t)&ulwp->ul_ftsd[0];
2147		}
2148	} else {
2149#if defined(_LP64) && defined(_SYSCALL32)
2150		ulwp32_t *ulwp = (ulwp32_t *)th_p->th_unique;
2151		tsd_metadata32_t tsdm;
2152		tsd32_t stsd;
2153		caddr32_t addr;
2154
2155		if (ps_pdread(ph_p,
2156		    ta_p->uberdata_addr + offsetof(uberdata32_t, tsd_metadata),
2157		    &tsdm, sizeof (tsdm)) != PS_OK)
2158			return_val = TD_DBERR;
2159		else if (ps_pdread(ph_p, (psaddr_t)&ulwp->ul_stsd,
2160		    &addr, sizeof (addr)) != PS_OK)
2161			return_val = TD_DBERR;
2162		else if (addr != NULL &&
2163		    ps_pdread(ph_p, addr, &stsd, sizeof (stsd)) != PS_OK)
2164			return_val = TD_DBERR;
2165		else {
2166			maxkey = tsdm.tsdm_nused;
2167			nkey = addr == NULL ? TSD_NFAST : stsd.tsd_nalloc;
2168
2169			if (key < TSD_NFAST) {
2170				tsd_paddr = (psaddr_t)&ulwp->ul_ftsd[0];
2171			} else {
2172				tsd_paddr = addr;
2173			}
2174		}
2175#else
2176		return_val = TD_ERR;
2177#endif	/* _SYSCALL32 */
2178	}
2179
2180	if (return_val == TD_OK && (key < 1 || key >= maxkey))
2181		return_val = TD_NOTSD;
2182	if (return_val != TD_OK || key >= nkey) {
2183		/* NULL has already been stored in data_pp */
2184		(void) ps_pcontinue(ph_p);
2185		ph_unlock(ta_p);
2186		return (return_val);
2187	}
2188
2189	/*
2190	 * Read the value from the thread's tsd array.
2191	 */
2192	if (ta_p->model == PR_MODEL_NATIVE) {
2193		void *value;
2194
2195		if (ps_pdread(ph_p, tsd_paddr + key * sizeof (void *),
2196		    &value, sizeof (value)) != PS_OK)
2197			return_val = TD_DBERR;
2198		else
2199			*data_pp = value;
2200#if defined(_LP64) && defined(_SYSCALL32)
2201	} else {
2202		caddr32_t value32;
2203
2204		if (ps_pdread(ph_p, tsd_paddr + key * sizeof (caddr32_t),
2205		    &value32, sizeof (value32)) != PS_OK)
2206			return_val = TD_DBERR;
2207		else
2208			*data_pp = (void *)(uintptr_t)value32;
2209#endif	/* _SYSCALL32 */
2210	}
2211
2212	(void) ps_pcontinue(ph_p);
2213	ph_unlock(ta_p);
2214	return (return_val);
2215}
2216
2217/*
2218 * Get the base address of a thread's thread local storage (TLS) block
2219 * for the module (executable or shared object) identified by 'moduleid'.
2220 */
2221#pragma weak td_thr_tlsbase = __td_thr_tlsbase
2222td_err_e
2223__td_thr_tlsbase(td_thrhandle_t *th_p, ulong_t moduleid, psaddr_t *base)
2224{
2225	struct ps_prochandle *ph_p;
2226	td_thragent_t	*ta_p;
2227	td_err_e	return_val;
2228
2229	if (base == NULL)
2230		return (TD_ERR);
2231	*base = NULL;
2232	if ((ph_p = ph_lock_th(th_p, &return_val)) == NULL)
2233		return (return_val);
2234	ta_p = th_p->th_ta_p;
2235	if (ps_pstop(ph_p) != PS_OK) {
2236		ph_unlock(ta_p);
2237		return (TD_DBERR);
2238	}
2239
2240	if (ta_p->model == PR_MODEL_NATIVE) {
2241		ulwp_t *ulwp = (ulwp_t *)th_p->th_unique;
2242		tls_metadata_t tls_metadata;
2243		TLS_modinfo tlsmod;
2244		tls_t tls;
2245
2246		if (ps_pdread(ph_p,
2247		    ta_p->uberdata_addr + offsetof(uberdata_t, tls_metadata),
2248		    &tls_metadata, sizeof (tls_metadata)) != PS_OK)
2249			return_val = TD_DBERR;
2250		else if (moduleid >= tls_metadata.tls_modinfo.tls_size)
2251			return_val = TD_NOTLS;
2252		else if (ps_pdread(ph_p,
2253		    (psaddr_t)((TLS_modinfo *)
2254		    tls_metadata.tls_modinfo.tls_data + moduleid),
2255		    &tlsmod, sizeof (tlsmod)) != PS_OK)
2256			return_val = TD_DBERR;
2257		else if (tlsmod.tm_memsz == 0)
2258			return_val = TD_NOTLS;
2259		else if (tlsmod.tm_flags & TM_FLG_STATICTLS)
2260			*base = (psaddr_t)ulwp - tlsmod.tm_stattlsoffset;
2261		else if (ps_pdread(ph_p, (psaddr_t)&ulwp->ul_tls,
2262		    &tls, sizeof (tls)) != PS_OK)
2263			return_val = TD_DBERR;
2264		else if (moduleid >= tls.tls_size)
2265			return_val = TD_TLSDEFER;
2266		else if (ps_pdread(ph_p,
2267		    (psaddr_t)((tls_t *)tls.tls_data + moduleid),
2268		    &tls, sizeof (tls)) != PS_OK)
2269			return_val = TD_DBERR;
2270		else if (tls.tls_size == 0)
2271			return_val = TD_TLSDEFER;
2272		else
2273			*base = (psaddr_t)tls.tls_data;
2274	} else {
2275#if defined(_LP64) && defined(_SYSCALL32)
2276		ulwp32_t *ulwp = (ulwp32_t *)th_p->th_unique;
2277		tls_metadata32_t tls_metadata;
2278		TLS_modinfo32 tlsmod;
2279		tls32_t tls;
2280
2281		if (ps_pdread(ph_p,
2282		    ta_p->uberdata_addr + offsetof(uberdata32_t, tls_metadata),
2283		    &tls_metadata, sizeof (tls_metadata)) != PS_OK)
2284			return_val = TD_DBERR;
2285		else if (moduleid >= tls_metadata.tls_modinfo.tls_size)
2286			return_val = TD_NOTLS;
2287		else if (ps_pdread(ph_p,
2288		    (psaddr_t)((TLS_modinfo32 *)
2289		    (uintptr_t)tls_metadata.tls_modinfo.tls_data + moduleid),
2290		    &tlsmod, sizeof (tlsmod)) != PS_OK)
2291			return_val = TD_DBERR;
2292		else if (tlsmod.tm_memsz == 0)
2293			return_val = TD_NOTLS;
2294		else if (tlsmod.tm_flags & TM_FLG_STATICTLS)
2295			*base = (psaddr_t)ulwp - tlsmod.tm_stattlsoffset;
2296		else if (ps_pdread(ph_p, (psaddr_t)&ulwp->ul_tls,
2297		    &tls, sizeof (tls)) != PS_OK)
2298			return_val = TD_DBERR;
2299		else if (moduleid >= tls.tls_size)
2300			return_val = TD_TLSDEFER;
2301		else if (ps_pdread(ph_p,
2302		    (psaddr_t)((tls32_t *)(uintptr_t)tls.tls_data + moduleid),
2303		    &tls, sizeof (tls)) != PS_OK)
2304			return_val = TD_DBERR;
2305		else if (tls.tls_size == 0)
2306			return_val = TD_TLSDEFER;
2307		else
2308			*base = (psaddr_t)tls.tls_data;
2309#else
2310		return_val = TD_ERR;
2311#endif	/* _SYSCALL32 */
2312	}
2313
2314	(void) ps_pcontinue(ph_p);
2315	ph_unlock(ta_p);
2316	return (return_val);
2317}
2318
2319/*
2320 * Change a thread's priority to the value specified by ti_pri.
2321 * Currently unused by dbx.
2322 */
2323#pragma weak td_thr_setprio = __td_thr_setprio
2324td_err_e
2325__td_thr_setprio(td_thrhandle_t *th_p, int ti_pri)
2326{
2327	struct ps_prochandle *ph_p;
2328	pri_t		priority = ti_pri;
2329	td_err_e	return_val = TD_OK;
2330
2331	if (ti_pri < THREAD_MIN_PRIORITY || ti_pri > THREAD_MAX_PRIORITY)
2332		return (TD_ERR);
2333	if ((ph_p = ph_lock_th(th_p, &return_val)) == NULL)
2334		return (return_val);
2335
2336	if (th_p->th_ta_p->model == PR_MODEL_NATIVE) {
2337		ulwp_t *ulwp = (ulwp_t *)th_p->th_unique;
2338
2339		if (ps_pdwrite(ph_p, (psaddr_t)&ulwp->ul_pri,
2340		    &priority, sizeof (priority)) != PS_OK)
2341			return_val = TD_DBERR;
2342	} else {
2343#if defined(_LP64) && defined(_SYSCALL32)
2344		ulwp32_t *ulwp = (ulwp32_t *)th_p->th_unique;
2345
2346		if (ps_pdwrite(ph_p, (psaddr_t)&ulwp->ul_pri,
2347		    &priority, sizeof (priority)) != PS_OK)
2348			return_val = TD_DBERR;
2349#else
2350		return_val = TD_ERR;
2351#endif	/* _SYSCALL32 */
2352	}
2353
2354	ph_unlock(th_p->th_ta_p);
2355	return (return_val);
2356}
2357
2358/*
2359 * This structure links td_thr_lockowner and the lowner_cb callback function.
2360 */
2361typedef struct {
2362	td_sync_iter_f	*owner_cb;
2363	void		*owner_cb_arg;
2364	td_thrhandle_t	*th_p;
2365} lowner_cb_ctl_t;
2366
2367static int
2368lowner_cb(const td_synchandle_t *sh_p, void *arg)
2369{
2370	lowner_cb_ctl_t *ocb = arg;
2371	int trunc = 0;
2372	union {
2373		rwlock_t rwl;
2374		mutex_t mx;
2375	} rw_m;
2376
2377	if (ps_pdread(sh_p->sh_ta_p->ph_p, sh_p->sh_unique,
2378	    &rw_m, sizeof (rw_m)) != PS_OK) {
2379		trunc = 1;
2380		if (ps_pdread(sh_p->sh_ta_p->ph_p, sh_p->sh_unique,
2381		    &rw_m.mx, sizeof (rw_m.mx)) != PS_OK)
2382			return (0);
2383	}
2384	if (rw_m.mx.mutex_magic == MUTEX_MAGIC &&
2385	    rw_m.mx.mutex_owner == ocb->th_p->th_unique)
2386		return ((ocb->owner_cb)(sh_p, ocb->owner_cb_arg));
2387	if (!trunc && rw_m.rwl.magic == RWL_MAGIC) {
2388		mutex_t *rwlock = &rw_m.rwl.mutex;
2389		if (rwlock->mutex_owner == ocb->th_p->th_unique)
2390			return ((ocb->owner_cb)(sh_p, ocb->owner_cb_arg));
2391	}
2392	return (0);
2393}
2394
2395/*
2396 * Iterate over the set of locks owned by a specified thread.
2397 * If cb returns a non-zero value, terminate iterations.
2398 */
2399#pragma weak td_thr_lockowner = __td_thr_lockowner
2400td_err_e
2401__td_thr_lockowner(const td_thrhandle_t *th_p, td_sync_iter_f *cb,
2402	void *cb_data)
2403{
2404	td_thragent_t	*ta_p;
2405	td_err_e	return_val;
2406	lowner_cb_ctl_t	lcb;
2407
2408	/*
2409	 * Just sanity checks.
2410	 */
2411	if (ph_lock_th((td_thrhandle_t *)th_p, &return_val) == NULL)
2412		return (return_val);
2413	ta_p = th_p->th_ta_p;
2414	ph_unlock(ta_p);
2415
2416	lcb.owner_cb = cb;
2417	lcb.owner_cb_arg = cb_data;
2418	lcb.th_p = (td_thrhandle_t *)th_p;
2419	return (__td_ta_sync_iter(ta_p, lowner_cb, &lcb));
2420}
2421
2422/*
2423 * If a thread is asleep on a synchronization variable,
2424 * then get the synchronization handle.
2425 */
2426#pragma weak td_thr_sleepinfo = __td_thr_sleepinfo
2427td_err_e
2428__td_thr_sleepinfo(const td_thrhandle_t *th_p, td_synchandle_t *sh_p)
2429{
2430	struct ps_prochandle *ph_p;
2431	td_err_e	return_val = TD_OK;
2432	uintptr_t	wchan;
2433
2434	if (sh_p == NULL)
2435		return (TD_ERR);
2436	if ((ph_p = ph_lock_th((td_thrhandle_t *)th_p, &return_val)) == NULL)
2437		return (return_val);
2438
2439	/*
2440	 * No need to stop the process for a simple read.
2441	 */
2442	if (th_p->th_ta_p->model == PR_MODEL_NATIVE) {
2443		ulwp_t *ulwp = (ulwp_t *)th_p->th_unique;
2444
2445		if (ps_pdread(ph_p, (psaddr_t)&ulwp->ul_wchan,
2446		    &wchan, sizeof (wchan)) != PS_OK)
2447			return_val = TD_DBERR;
2448	} else {
2449#if defined(_LP64) && defined(_SYSCALL32)
2450		ulwp32_t *ulwp = (ulwp32_t *)th_p->th_unique;
2451		caddr32_t wchan32;
2452
2453		if (ps_pdread(ph_p, (psaddr_t)&ulwp->ul_wchan,
2454		    &wchan32, sizeof (wchan32)) != PS_OK)
2455			return_val = TD_DBERR;
2456		wchan = wchan32;
2457#else
2458		return_val = TD_ERR;
2459#endif	/* _SYSCALL32 */
2460	}
2461
2462	if (return_val != TD_OK || wchan == NULL) {
2463		sh_p->sh_ta_p = NULL;
2464		sh_p->sh_unique = NULL;
2465		if (return_val == TD_OK)
2466			return_val = TD_ERR;
2467	} else {
2468		sh_p->sh_ta_p = th_p->th_ta_p;
2469		sh_p->sh_unique = (psaddr_t)wchan;
2470	}
2471
2472	ph_unlock(th_p->th_ta_p);
2473	return (return_val);
2474}
2475
2476/*
2477 * Which thread is running on an lwp?
2478 */
2479#pragma weak td_ta_map_lwp2thr = __td_ta_map_lwp2thr
2480td_err_e
2481__td_ta_map_lwp2thr(td_thragent_t *ta_p, lwpid_t lwpid,
2482	td_thrhandle_t *th_p)
2483{
2484	return (__td_ta_map_id2thr(ta_p, lwpid, th_p));
2485}
2486
2487/*
2488 * Common code for td_sync_get_info() and td_sync_get_stats()
2489 */
2490static td_err_e
2491sync_get_info_common(const td_synchandle_t *sh_p, struct ps_prochandle *ph_p,
2492	td_syncinfo_t *si_p)
2493{
2494	int trunc = 0;
2495	td_so_un_t generic_so;
2496
2497	/*
2498	 * Determine the sync. object type; a little type fudgery here.
2499	 * First attempt to read the whole union.  If that fails, attempt
2500	 * to read just the condvar.  A condvar is the smallest sync. object.
2501	 */
2502	if (ps_pdread(ph_p, sh_p->sh_unique,
2503	    &generic_so, sizeof (generic_so)) != PS_OK) {
2504		trunc = 1;
2505		if (ps_pdread(ph_p, sh_p->sh_unique, &generic_so.condition,
2506		    sizeof (generic_so.condition)) != PS_OK)
2507			return (TD_DBERR);
2508	}
2509
2510	switch (generic_so.condition.cond_magic) {
2511	case MUTEX_MAGIC:
2512		if (trunc && ps_pdread(ph_p, sh_p->sh_unique,
2513		    &generic_so.lock, sizeof (generic_so.lock)) != PS_OK)
2514			return (TD_DBERR);
2515		si_p->si_type = TD_SYNC_MUTEX;
2516		si_p->si_shared_type = generic_so.lock.mutex_type;
2517		(void) memcpy(si_p->si_flags, &generic_so.lock.mutex_flag,
2518		    sizeof (generic_so.lock.mutex_flag));
2519		si_p->si_state.mutex_locked =
2520		    (generic_so.lock.mutex_lockw != 0);
2521		si_p->si_size = sizeof (generic_so.lock);
2522		si_p->si_has_waiters = generic_so.lock.mutex_waiters;
2523		si_p->si_rcount = generic_so.lock.mutex_rcount;
2524		si_p->si_prioceiling = generic_so.lock.mutex_ceiling;
2525		if (si_p->si_state.mutex_locked) {
2526			if (si_p->si_shared_type &
2527			    (USYNC_PROCESS | USYNC_PROCESS_ROBUST))
2528				si_p->si_ownerpid =
2529					generic_so.lock.mutex_ownerpid;
2530			si_p->si_owner.th_ta_p = sh_p->sh_ta_p;
2531			si_p->si_owner.th_unique = generic_so.lock.mutex_owner;
2532		}
2533		break;
2534	case COND_MAGIC:
2535		si_p->si_type = TD_SYNC_COND;
2536		si_p->si_shared_type = generic_so.condition.cond_type;
2537		(void) memcpy(si_p->si_flags, generic_so.condition.flags.flag,
2538		    sizeof (generic_so.condition.flags.flag));
2539		si_p->si_size = sizeof (generic_so.condition);
2540		si_p->si_has_waiters =
2541			(generic_so.condition.cond_waiters_user |
2542			generic_so.condition.cond_waiters_kernel)? 1 : 0;
2543		break;
2544	case SEMA_MAGIC:
2545		if (trunc && ps_pdread(ph_p, sh_p->sh_unique,
2546		    &generic_so.semaphore, sizeof (generic_so.semaphore))
2547		    != PS_OK)
2548			return (TD_DBERR);
2549		si_p->si_type = TD_SYNC_SEMA;
2550		si_p->si_shared_type = generic_so.semaphore.type;
2551		si_p->si_state.sem_count = generic_so.semaphore.count;
2552		si_p->si_size = sizeof (generic_so.semaphore);
2553		si_p->si_has_waiters =
2554		    ((lwp_sema_t *)&generic_so.semaphore)->flags[7];
2555		/* this is useless but the old interface provided it */
2556		si_p->si_data = (psaddr_t)generic_so.semaphore.count;
2557		break;
2558	case RWL_MAGIC:
2559		if (trunc && ps_pdread(ph_p, sh_p->sh_unique,
2560		    &generic_so.rwlock, sizeof (generic_so.rwlock)) != PS_OK)
2561			return (TD_DBERR);
2562		si_p->si_type = TD_SYNC_RWLOCK;
2563		si_p->si_shared_type = generic_so.rwlock.rwlock_type;
2564		si_p->si_size = sizeof (generic_so.rwlock);
2565		if (generic_so.rwlock.rwlock_type == USYNC_PROCESS) {
2566			uint32_t *rwstate =
2567			    (uint32_t *)&si_p->si_state.nreaders;
2568
2569			if (*rwstate & URW_WRITE_LOCKED) {
2570				si_p->si_state.nreaders = -1;
2571				si_p->si_is_wlock = 1;
2572				si_p->si_owner.th_ta_p = sh_p->sh_ta_p;
2573				si_p->si_owner.th_unique =
2574					generic_so.rwlock.rwlock_owner;
2575			} else if (*rwstate & URW_READERS_MASK)
2576				si_p->si_state.nreaders =
2577				    *rwstate & URW_READERS_MASK;
2578			else
2579				si_p->si_state.nreaders = 0;
2580			si_p->si_has_waiters = (*rwstate & URW_HAS_WAITERS);
2581		} else {
2582			si_p->si_state.nreaders = generic_so.rwlock.readers;
2583			si_p->si_has_waiters =
2584			    generic_so.rwlock.rwlock_mwaiters;
2585			if (si_p->si_state.nreaders == -1) {
2586				si_p->si_is_wlock = 1;
2587				si_p->si_owner.th_ta_p = sh_p->sh_ta_p;
2588				si_p->si_owner.th_unique =
2589					generic_so.rwlock.rwlock_mowner;
2590			}
2591		}
2592		/* this is useless but the old interface provided it */
2593		si_p->si_data = (psaddr_t)generic_so.rwlock.readers;
2594		break;
2595	default:
2596		return (TD_BADSH);
2597	}
2598
2599	si_p->si_ta_p = sh_p->sh_ta_p;
2600	si_p->si_sv_addr = sh_p->sh_unique;
2601	return (TD_OK);
2602}
2603
2604/*
2605 * Given a synchronization handle, fill in the
2606 * information for the synchronization variable into *si_p.
2607 */
2608#pragma weak td_sync_get_info = __td_sync_get_info
2609td_err_e
2610__td_sync_get_info(const td_synchandle_t *sh_p, td_syncinfo_t *si_p)
2611{
2612	struct ps_prochandle *ph_p;
2613	td_err_e return_val;
2614
2615	if (si_p == NULL)
2616		return (TD_ERR);
2617	(void) memset(si_p, 0, sizeof (*si_p));
2618	if ((ph_p = ph_lock_sh(sh_p, &return_val)) == NULL)
2619		return (return_val);
2620	if (ps_pstop(ph_p) != PS_OK) {
2621		ph_unlock(sh_p->sh_ta_p);
2622		return (TD_DBERR);
2623	}
2624
2625	return_val = sync_get_info_common(sh_p, ph_p, si_p);
2626
2627	(void) ps_pcontinue(ph_p);
2628	ph_unlock(sh_p->sh_ta_p);
2629	return (return_val);
2630}
2631
2632static uint_t
2633tdb_addr_hash64(uint64_t addr)
2634{
2635	uint64_t value60 = (addr >> 4);
2636	uint32_t value30 = (value60 >> 30) ^ (value60 & 0x3fffffff);
2637	return ((value30 >> 15) ^ (value30 & 0x7fff));
2638}
2639
2640static uint_t
2641tdb_addr_hash32(uint64_t addr)
2642{
2643	uint32_t value30 = (addr >> 2);		/* 30 bits */
2644	return ((value30 >> 15) ^ (value30 & 0x7fff));
2645}
2646
2647static td_err_e
2648read_sync_stats(td_thragent_t *ta_p, psaddr_t hash_table,
2649	psaddr_t sync_obj_addr, tdb_sync_stats_t *sync_stats)
2650{
2651	psaddr_t next_desc;
2652	uint64_t first;
2653	uint_t ix;
2654
2655	/*
2656	 * Compute the hash table index from the synch object's address.
2657	 */
2658	if (ta_p->model == PR_MODEL_LP64)
2659		ix = tdb_addr_hash64(sync_obj_addr);
2660	else
2661		ix = tdb_addr_hash32(sync_obj_addr);
2662
2663	/*
2664	 * Get the address of the first element in the linked list.
2665	 */
2666	if (ps_pdread(ta_p->ph_p, hash_table + ix * sizeof (uint64_t),
2667	    &first, sizeof (first)) != PS_OK)
2668		return (TD_DBERR);
2669
2670	/*
2671	 * Search the linked list for an entry for the synch object..
2672	 */
2673	for (next_desc = (psaddr_t)first; next_desc != NULL;
2674	    next_desc = (psaddr_t)sync_stats->next) {
2675		if (ps_pdread(ta_p->ph_p, next_desc,
2676		    sync_stats, sizeof (*sync_stats)) != PS_OK)
2677			return (TD_DBERR);
2678		if (sync_stats->sync_addr == sync_obj_addr)
2679			return (TD_OK);
2680	}
2681
2682	(void) memset(sync_stats, 0, sizeof (*sync_stats));
2683	return (TD_OK);
2684}
2685
2686/*
2687 * Given a synchronization handle, fill in the
2688 * statistics for the synchronization variable into *ss_p.
2689 */
2690#pragma weak td_sync_get_stats = __td_sync_get_stats
2691td_err_e
2692__td_sync_get_stats(const td_synchandle_t *sh_p, td_syncstats_t *ss_p)
2693{
2694	struct ps_prochandle *ph_p;
2695	td_thragent_t *ta_p;
2696	td_err_e return_val;
2697	register_sync_t enable;
2698	psaddr_t hashaddr;
2699	tdb_sync_stats_t sync_stats;
2700	size_t ix;
2701
2702	if (ss_p == NULL)
2703		return (TD_ERR);
2704	(void) memset(ss_p, 0, sizeof (*ss_p));
2705	if ((ph_p = ph_lock_sh(sh_p, &return_val)) == NULL)
2706		return (return_val);
2707	ta_p = sh_p->sh_ta_p;
2708	if (ps_pstop(ph_p) != PS_OK) {
2709		ph_unlock(ta_p);
2710		return (TD_DBERR);
2711	}
2712
2713	if ((return_val = sync_get_info_common(sh_p, ph_p, &ss_p->ss_info))
2714	    != TD_OK) {
2715		if (return_val != TD_BADSH)
2716			goto out;
2717		/* we can correct TD_BADSH */
2718		(void) memset(&ss_p->ss_info, 0, sizeof (ss_p->ss_info));
2719		ss_p->ss_info.si_ta_p = sh_p->sh_ta_p;
2720		ss_p->ss_info.si_sv_addr = sh_p->sh_unique;
2721		/* we correct si_type and si_size below */
2722		return_val = TD_OK;
2723	}
2724	if (ps_pdread(ph_p, ta_p->tdb_register_sync_addr,
2725	    &enable, sizeof (enable)) != PS_OK) {
2726		return_val = TD_DBERR;
2727		goto out;
2728	}
2729	if (enable != REGISTER_SYNC_ON)
2730		goto out;
2731
2732	/*
2733	 * Get the address of the hash table in the target process.
2734	 */
2735	if (ta_p->model == PR_MODEL_NATIVE) {
2736		if (ps_pdread(ph_p, ta_p->uberdata_addr +
2737		    offsetof(uberdata_t, tdb.tdb_sync_addr_hash),
2738		    &hashaddr, sizeof (&hashaddr)) != PS_OK) {
2739			return_val = TD_DBERR;
2740			goto out;
2741		}
2742	} else {
2743#if defined(_LP64) && defined(_SYSCALL32)
2744		caddr32_t addr;
2745
2746		if (ps_pdread(ph_p, ta_p->uberdata_addr +
2747		    offsetof(uberdata32_t, tdb.tdb_sync_addr_hash),
2748		    &addr, sizeof (addr)) != PS_OK) {
2749			return_val = TD_DBERR;
2750			goto out;
2751		}
2752		hashaddr = addr;
2753#else
2754		return_val = TD_ERR;
2755		goto out;
2756#endif	/* _SYSCALL32 */
2757	}
2758
2759	if (hashaddr == 0)
2760		return_val = TD_BADSH;
2761	else
2762		return_val = read_sync_stats(ta_p, hashaddr,
2763			sh_p->sh_unique, &sync_stats);
2764	if (return_val != TD_OK)
2765		goto out;
2766
2767	/*
2768	 * We have the hash table entry.  Transfer the data to
2769	 * the td_syncstats_t structure provided by the caller.
2770	 */
2771	switch (sync_stats.un.type) {
2772	case TDB_MUTEX:
2773	    {
2774		td_mutex_stats_t *msp = &ss_p->ss_un.mutex;
2775
2776		ss_p->ss_info.si_type = TD_SYNC_MUTEX;
2777		ss_p->ss_info.si_size = sizeof (mutex_t);
2778		msp->mutex_lock =
2779			sync_stats.un.mutex.mutex_lock;
2780		msp->mutex_sleep =
2781			sync_stats.un.mutex.mutex_sleep;
2782		msp->mutex_sleep_time =
2783			sync_stats.un.mutex.mutex_sleep_time;
2784		msp->mutex_hold_time =
2785			sync_stats.un.mutex.mutex_hold_time;
2786		msp->mutex_try =
2787			sync_stats.un.mutex.mutex_try;
2788		msp->mutex_try_fail =
2789			sync_stats.un.mutex.mutex_try_fail;
2790		if (sync_stats.sync_addr >= ta_p->hash_table_addr &&
2791		    (ix = sync_stats.sync_addr - ta_p->hash_table_addr)
2792		    < ta_p->hash_size * sizeof (thr_hash_table_t))
2793			msp->mutex_internal =
2794				ix / sizeof (thr_hash_table_t) + 1;
2795		break;
2796	    }
2797	case TDB_COND:
2798	    {
2799		td_cond_stats_t *csp = &ss_p->ss_un.cond;
2800
2801		ss_p->ss_info.si_type = TD_SYNC_COND;
2802		ss_p->ss_info.si_size = sizeof (cond_t);
2803		csp->cond_wait =
2804			sync_stats.un.cond.cond_wait;
2805		csp->cond_timedwait =
2806			sync_stats.un.cond.cond_timedwait;
2807		csp->cond_wait_sleep_time =
2808			sync_stats.un.cond.cond_wait_sleep_time;
2809		csp->cond_timedwait_sleep_time =
2810			sync_stats.un.cond.cond_timedwait_sleep_time;
2811		csp->cond_timedwait_timeout =
2812			sync_stats.un.cond.cond_timedwait_timeout;
2813		csp->cond_signal =
2814			sync_stats.un.cond.cond_signal;
2815		csp->cond_broadcast =
2816			sync_stats.un.cond.cond_broadcast;
2817		if (sync_stats.sync_addr >= ta_p->hash_table_addr &&
2818		    (ix = sync_stats.sync_addr - ta_p->hash_table_addr)
2819		    < ta_p->hash_size * sizeof (thr_hash_table_t))
2820			csp->cond_internal =
2821				ix / sizeof (thr_hash_table_t) + 1;
2822		break;
2823	    }
2824	case TDB_RWLOCK:
2825	    {
2826		psaddr_t cond_addr;
2827		tdb_sync_stats_t cond_stats;
2828		td_rwlock_stats_t *rwsp = &ss_p->ss_un.rwlock;
2829
2830		ss_p->ss_info.si_type = TD_SYNC_RWLOCK;
2831		ss_p->ss_info.si_size = sizeof (rwlock_t);
2832		rwsp->rw_rdlock =
2833			sync_stats.un.rwlock.rw_rdlock;
2834		cond_addr = (psaddr_t)&((rwlock_t *)sh_p->sh_unique)->readercv;
2835		if (read_sync_stats(ta_p, hashaddr, cond_addr, &cond_stats)
2836		    == TD_OK) {
2837			rwsp->rw_rdlock_sleep =
2838				cond_stats.un.cond.cond_wait;
2839			rwsp->rw_rdlock_sleep_time =
2840				cond_stats.un.cond.cond_wait_sleep_time;
2841		}
2842		rwsp->rw_rdlock_try =
2843			sync_stats.un.rwlock.rw_rdlock_try;
2844		rwsp->rw_rdlock_try_fail =
2845			sync_stats.un.rwlock.rw_rdlock_try_fail;
2846		rwsp->rw_wrlock =
2847			sync_stats.un.rwlock.rw_wrlock;
2848		cond_addr = (psaddr_t)&((rwlock_t *)sh_p->sh_unique)->writercv;
2849		if (read_sync_stats(ta_p, hashaddr, cond_addr, &cond_stats)
2850		    == TD_OK) {
2851			rwsp->rw_wrlock_sleep =
2852				cond_stats.un.cond.cond_wait;
2853			rwsp->rw_wrlock_sleep_time =
2854				cond_stats.un.cond.cond_wait_sleep_time;
2855		}
2856		rwsp->rw_wrlock_hold_time =
2857			sync_stats.un.rwlock.rw_wrlock_hold_time;
2858		rwsp->rw_wrlock_try =
2859			sync_stats.un.rwlock.rw_wrlock_try;
2860		rwsp->rw_wrlock_try_fail =
2861			sync_stats.un.rwlock.rw_wrlock_try_fail;
2862		break;
2863	    }
2864	case TDB_SEMA:
2865	    {
2866		td_sema_stats_t *ssp = &ss_p->ss_un.sema;
2867
2868		ss_p->ss_info.si_type = TD_SYNC_SEMA;
2869		ss_p->ss_info.si_size = sizeof (sema_t);
2870		ssp->sema_wait =
2871			sync_stats.un.sema.sema_wait;
2872		ssp->sema_wait_sleep =
2873			sync_stats.un.sema.sema_wait_sleep;
2874		ssp->sema_wait_sleep_time =
2875			sync_stats.un.sema.sema_wait_sleep_time;
2876		ssp->sema_trywait =
2877			sync_stats.un.sema.sema_trywait;
2878		ssp->sema_trywait_fail =
2879			sync_stats.un.sema.sema_trywait_fail;
2880		ssp->sema_post =
2881			sync_stats.un.sema.sema_post;
2882		ssp->sema_max_count =
2883			sync_stats.un.sema.sema_max_count;
2884		ssp->sema_min_count =
2885			sync_stats.un.sema.sema_min_count;
2886		break;
2887	    }
2888	default:
2889		return_val = TD_BADSH;
2890		break;
2891	}
2892
2893out:
2894	(void) ps_pcontinue(ph_p);
2895	ph_unlock(ta_p);
2896	return (return_val);
2897}
2898
2899/*
2900 * Change the state of a synchronization variable.
2901 *	1) mutex lock state set to value
2902 *	2) semaphore's count set to value
2903 *	3) writer's lock set to value
2904 *	4) reader's lock number of readers set to value
2905 * Currently unused by dbx.
2906 */
2907#pragma weak td_sync_setstate = __td_sync_setstate
2908td_err_e
2909__td_sync_setstate(const td_synchandle_t *sh_p, long lvalue)
2910{
2911	struct ps_prochandle *ph_p;
2912	int		trunc = 0;
2913	td_err_e	return_val;
2914	td_so_un_t	generic_so;
2915	int		value = (int)lvalue;
2916
2917	if ((ph_p = ph_lock_sh(sh_p, &return_val)) == NULL)
2918		return (return_val);
2919	if (ps_pstop(ph_p) != PS_OK) {
2920		ph_unlock(sh_p->sh_ta_p);
2921		return (TD_DBERR);
2922	}
2923
2924	/*
2925	 * Read the synch. variable information.
2926	 * First attempt to read the whole union and if that fails
2927	 * fall back to reading only the smallest member, the condvar.
2928	 */
2929	if (ps_pdread(ph_p, sh_p->sh_unique, &generic_so,
2930	    sizeof (generic_so)) != PS_OK) {
2931		trunc = 1;
2932		if (ps_pdread(ph_p, sh_p->sh_unique, &generic_so.condition,
2933		    sizeof (generic_so.condition)) != PS_OK) {
2934			(void) ps_pcontinue(ph_p);
2935			ph_unlock(sh_p->sh_ta_p);
2936			return (TD_DBERR);
2937		}
2938	}
2939
2940	/*
2941	 * Set the new value in the sync. variable, read the synch. variable
2942	 * information. from the process, reset its value and write it back.
2943	 */
2944	switch (generic_so.condition.mutex_magic) {
2945	case MUTEX_MAGIC:
2946		if (trunc && ps_pdread(ph_p, sh_p->sh_unique,
2947		    &generic_so.lock, sizeof (generic_so.lock)) != PS_OK) {
2948			return_val = TD_DBERR;
2949			break;
2950		}
2951		generic_so.lock.mutex_lockw = (uint8_t)value;
2952		if (ps_pdwrite(ph_p, sh_p->sh_unique, &generic_so.lock,
2953		    sizeof (generic_so.lock)) != PS_OK)
2954			return_val = TD_DBERR;
2955		break;
2956	case SEMA_MAGIC:
2957		if (trunc && ps_pdread(ph_p, sh_p->sh_unique,
2958		    &generic_so.semaphore, sizeof (generic_so.semaphore))
2959		    != PS_OK) {
2960			return_val = TD_DBERR;
2961			break;
2962		}
2963		generic_so.semaphore.count = value;
2964		if (ps_pdwrite(ph_p, sh_p->sh_unique, &generic_so.semaphore,
2965		    sizeof (generic_so.semaphore)) != PS_OK)
2966			return_val = TD_DBERR;
2967		break;
2968	case COND_MAGIC:
2969		/* Operation not supported on a condition variable */
2970		return_val = TD_ERR;
2971		break;
2972	case RWL_MAGIC:
2973		if (trunc && ps_pdread(ph_p, sh_p->sh_unique,
2974		    &generic_so.rwlock, sizeof (generic_so.rwlock)) != PS_OK) {
2975			return_val = TD_DBERR;
2976			break;
2977		}
2978		if (generic_so.rwlock.rwlock_type == USYNC_PROCESS) {
2979			uint32_t *rwstate =
2980			    (uint32_t *)&generic_so.rwlock.readers;
2981			if (value < 0)
2982				*rwstate = URW_WRITE_LOCKED;
2983			else if (value > 0)
2984				*rwstate = (value & URW_READERS_MASK);
2985			else
2986				*rwstate = 0;
2987		} else
2988			generic_so.rwlock.readers = value;
2989
2990		if (ps_pdwrite(ph_p, sh_p->sh_unique, &generic_so.rwlock,
2991		    sizeof (generic_so.rwlock)) != PS_OK)
2992			return_val = TD_DBERR;
2993		break;
2994	default:
2995		/* Bad sync. object type */
2996		return_val = TD_BADSH;
2997		break;
2998	}
2999
3000	(void) ps_pcontinue(ph_p);
3001	ph_unlock(sh_p->sh_ta_p);
3002	return (return_val);
3003}
3004
3005typedef struct {
3006	td_thr_iter_f	*waiter_cb;
3007	psaddr_t	sync_obj_addr;
3008	uint16_t	sync_magic;
3009	void		*waiter_cb_arg;
3010	td_err_e	errcode;
3011} waiter_cb_ctl_t;
3012
3013static int
3014waiters_cb(const td_thrhandle_t *th_p, void *arg)
3015{
3016	td_thragent_t	*ta_p = th_p->th_ta_p;
3017	struct ps_prochandle *ph_p = ta_p->ph_p;
3018	waiter_cb_ctl_t	*wcb = arg;
3019	caddr_t		wchan;
3020
3021	if (ta_p->model == PR_MODEL_NATIVE) {
3022		ulwp_t *ulwp = (ulwp_t *)th_p->th_unique;
3023
3024		if (ps_pdread(ph_p, (psaddr_t)&ulwp->ul_wchan,
3025		    &wchan, sizeof (wchan)) != PS_OK) {
3026			wcb->errcode = TD_DBERR;
3027			return (1);
3028		}
3029	} else {
3030#if defined(_LP64) && defined(_SYSCALL32)
3031		ulwp32_t *ulwp = (ulwp32_t *)th_p->th_unique;
3032		caddr32_t wchan32;
3033
3034		if (ps_pdread(ph_p, (psaddr_t)&ulwp->ul_wchan,
3035		    &wchan32, sizeof (wchan32)) != PS_OK) {
3036			wcb->errcode = TD_DBERR;
3037			return (1);
3038		}
3039		wchan = (caddr_t)(uintptr_t)wchan32;
3040#else
3041		wcb->errcode = TD_ERR;
3042		return (1);
3043#endif	/* _SYSCALL32 */
3044	}
3045
3046	if (wchan == NULL)
3047		return (0);
3048
3049	if (wchan == (caddr_t)wcb->sync_obj_addr)
3050		return ((*wcb->waiter_cb)(th_p, wcb->waiter_cb_arg));
3051
3052	return (0);
3053}
3054
3055/*
3056 * For a given synchronization variable, iterate over the
3057 * set of waiting threads.  The call back function is passed
3058 * two parameters, a pointer to a thread handle and a pointer
3059 * to extra call back data.
3060 */
3061#pragma weak td_sync_waiters = __td_sync_waiters
3062td_err_e
3063__td_sync_waiters(const td_synchandle_t *sh_p, td_thr_iter_f *cb, void *cb_data)
3064{
3065	struct ps_prochandle *ph_p;
3066	waiter_cb_ctl_t	wcb;
3067	td_err_e	return_val;
3068
3069	if ((ph_p = ph_lock_sh(sh_p, &return_val)) == NULL)
3070		return (return_val);
3071	if (ps_pdread(ph_p,
3072	    (psaddr_t)&((mutex_t *)sh_p->sh_unique)->mutex_magic,
3073	    (caddr_t)&wcb.sync_magic, sizeof (wcb.sync_magic)) != PS_OK) {
3074		ph_unlock(sh_p->sh_ta_p);
3075		return (TD_DBERR);
3076	}
3077	ph_unlock(sh_p->sh_ta_p);
3078
3079	switch (wcb.sync_magic) {
3080	case MUTEX_MAGIC:
3081	case COND_MAGIC:
3082	case SEMA_MAGIC:
3083	case RWL_MAGIC:
3084		break;
3085	default:
3086		return (TD_BADSH);
3087	}
3088
3089	wcb.waiter_cb = cb;
3090	wcb.sync_obj_addr = sh_p->sh_unique;
3091	wcb.waiter_cb_arg = cb_data;
3092	wcb.errcode = TD_OK;
3093	return_val = __td_ta_thr_iter(sh_p->sh_ta_p, waiters_cb, &wcb,
3094		TD_THR_SLEEP, TD_THR_LOWEST_PRIORITY,
3095		TD_SIGNO_MASK, TD_THR_ANY_USER_FLAGS);
3096
3097	if (return_val != TD_OK)
3098		return (return_val);
3099
3100	return (wcb.errcode);
3101}
3102