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