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 !=
 828                                     (caddr32_t)(uintptr_t)TSD_UNALLOCATED) &&
 829                                     (*cb)(key, (PFrV)(uintptr_t)destruct32,
 830                                     cbdata_p))
 831                                         break;
 832                         }
 833                 }
 834 #endif  /* _SYSCALL32 */
 835         }
 836 
 837         if (destructors)
 838                 free(destructors);
 839         (void) ps_pcontinue(ph_p);
 840         ph_unlock(ta_p);
 841         return (return_val);
 842 }
 843 
 844 int
 845 sigequalset(const sigset_t *s1, const sigset_t *s2)
 846 {
 847         return (
 848             s1->__sigbits[0] == s2->__sigbits[0] &&
 849             s1->__sigbits[1] == s2->__sigbits[1] &&
 850             s1->__sigbits[2] == s2->__sigbits[2] &&
 851             s1->__sigbits[3] == s2->__sigbits[3]);
 852 }
 853 
 854 /*
 855  * Description:
 856  *   Iterate over all threads. For each thread call
 857  * the function pointed to by "cb" with a pointer
 858  * to a thread handle, and a pointer to data which
 859  * can be NULL. Only call td_thr_iter_f() on threads
 860  * which match the properties of state, ti_pri,
 861  * ti_sigmask_p, and ti_user_flags.  If cb returns
 862  * a non-zero value, terminate iterations.
 863  *
 864  * Input:
 865  *   *ta_p - thread agent
 866  *   *cb - call back function defined by user.
 867  * td_thr_iter_f() takes a thread handle and
 868  * cbdata_p as a parameter.
 869  *   cbdata_p - parameter for td_thr_iter_f().
 870  *
 871  *   state - state of threads of interest.  A value of
 872  * TD_THR_ANY_STATE from enum td_thr_state_e
 873  * does not restrict iterations by state.
 874  *   ti_pri - lower bound of priorities of threads of
 875  * interest.  A value of TD_THR_LOWEST_PRIORITY
 876  * defined in thread_db.h does not restrict
 877  * iterations by priority.  A thread with priority
 878  * less than ti_pri will NOT be passed to the callback
 879  * function.
 880  *   ti_sigmask_p - signal mask of threads of interest.
 881  * A value of TD_SIGNO_MASK defined in thread_db.h
 882  * does not restrict iterations by signal mask.
 883  *   ti_user_flags - user flags of threads of interest.  A
 884  * value of TD_THR_ANY_USER_FLAGS defined in thread_db.h
 885  * does not restrict iterations by user flags.
 886  */
 887 #pragma weak td_ta_thr_iter = __td_ta_thr_iter
 888 td_err_e
 889 __td_ta_thr_iter(td_thragent_t *ta_p, td_thr_iter_f *cb,
 890         void *cbdata_p, td_thr_state_e state, int ti_pri,
 891         sigset_t *ti_sigmask_p, unsigned ti_user_flags)
 892 {
 893         struct ps_prochandle *ph_p;
 894         psaddr_t        first_lwp_addr;
 895         psaddr_t        first_zombie_addr;
 896         psaddr_t        curr_lwp_addr;
 897         psaddr_t        next_lwp_addr;
 898         td_thrhandle_t  th;
 899         ps_err_e        db_return;
 900         ps_err_e        db_return2;
 901         td_err_e        return_val;
 902 
 903         if (cb == NULL)
 904                 return (TD_ERR);
 905         /*
 906          * If state is not within bound, short circuit.
 907          */
 908         if (state < TD_THR_ANY_STATE || state > TD_THR_STOPPED_ASLEEP)
 909                 return (TD_OK);
 910 
 911         if ((ph_p = ph_lock_ta(ta_p, &return_val)) == NULL)
 912                 return (return_val);
 913         if (ps_pstop(ph_p) != PS_OK) {
 914                 ph_unlock(ta_p);
 915                 return (TD_DBERR);
 916         }
 917 
 918         /*
 919          * For each ulwp_t in the circular linked lists pointed
 920          * to by "all_lwps" and "all_zombies":
 921          * (1) Filter each thread.
 922          * (2) Create the thread_object for each thread that passes.
 923          * (3) Call the call back function on each thread.
 924          */
 925 
 926         if (ta_p->model == PR_MODEL_NATIVE) {
 927                 db_return = ps_pdread(ph_p,
 928                     ta_p->uberdata_addr + offsetof(uberdata_t, all_lwps),
 929                     &first_lwp_addr, sizeof (first_lwp_addr));
 930                 db_return2 = ps_pdread(ph_p,
 931                     ta_p->uberdata_addr + offsetof(uberdata_t, all_zombies),
 932                     &first_zombie_addr, sizeof (first_zombie_addr));
 933         } else {
 934 #if defined(_LP64) && defined(_SYSCALL32)
 935                 caddr32_t addr32;
 936 
 937                 db_return = ps_pdread(ph_p,
 938                     ta_p->uberdata_addr + offsetof(uberdata32_t, all_lwps),
 939                     &addr32, sizeof (addr32));
 940                 first_lwp_addr = addr32;
 941                 db_return2 = ps_pdread(ph_p,
 942                     ta_p->uberdata_addr + offsetof(uberdata32_t, all_zombies),
 943                     &addr32, sizeof (addr32));
 944                 first_zombie_addr = addr32;
 945 #else   /* _SYSCALL32 */
 946                 db_return = PS_ERR;
 947                 db_return2 = PS_ERR;
 948 #endif  /* _SYSCALL32 */
 949         }
 950         if (db_return == PS_OK)
 951                 db_return = db_return2;
 952 
 953         /*
 954          * If first_lwp_addr and first_zombie_addr are both NULL,
 955          * libc must not yet be initialized or all threads have
 956          * exited.  Return TD_NOTHR and all will be well.
 957          */
 958         if (db_return == PS_OK &&
 959             first_lwp_addr == NULL && first_zombie_addr == NULL) {
 960                 (void) ps_pcontinue(ph_p);
 961                 ph_unlock(ta_p);
 962                 return (TD_NOTHR);
 963         }
 964         if (db_return != PS_OK) {
 965                 (void) ps_pcontinue(ph_p);
 966                 ph_unlock(ta_p);
 967                 return (TD_DBERR);
 968         }
 969 
 970         /*
 971          * Run down the lists of all living and dead lwps.
 972          */
 973         if (first_lwp_addr == NULL)
 974                 first_lwp_addr = first_zombie_addr;
 975         curr_lwp_addr = first_lwp_addr;
 976         for (;;) {
 977                 td_thr_state_e ts_state;
 978                 int userpri;
 979                 unsigned userflags;
 980                 sigset_t mask;
 981 
 982                 /*
 983                  * Read the ulwp struct.
 984                  */
 985                 if (ta_p->model == PR_MODEL_NATIVE) {
 986                         ulwp_t ulwp;
 987 
 988                         if (ps_pdread(ph_p, curr_lwp_addr,
 989                             &ulwp, sizeof (ulwp)) != PS_OK &&
 990                             ((void) memset(&ulwp, 0, sizeof (ulwp)),
 991                             ps_pdread(ph_p, curr_lwp_addr,
 992                             &ulwp, REPLACEMENT_SIZE)) != PS_OK) {
 993                                 return_val = TD_DBERR;
 994                                 break;
 995                         }
 996                         next_lwp_addr = (psaddr_t)ulwp.ul_forw;
 997 
 998                         ts_state = ulwp.ul_dead? TD_THR_ZOMBIE :
 999                             ulwp.ul_stop? TD_THR_STOPPED :
1000                             ulwp.ul_wchan? TD_THR_SLEEP :
1001                             TD_THR_ACTIVE;
1002                         userpri = ulwp.ul_pri;
1003                         userflags = ulwp.ul_usropts;
1004                         if (ulwp.ul_dead)
1005                                 (void) sigemptyset(&mask);
1006                         else
1007                                 mask = *(sigset_t *)&ulwp.ul_sigmask;
1008                 } else {
1009 #if defined(_LP64) && defined(_SYSCALL32)
1010                         ulwp32_t ulwp;
1011 
1012                         if (ps_pdread(ph_p, curr_lwp_addr,
1013                             &ulwp, sizeof (ulwp)) != PS_OK &&
1014                             ((void) memset(&ulwp, 0, sizeof (ulwp)),
1015                             ps_pdread(ph_p, curr_lwp_addr,
1016                             &ulwp, REPLACEMENT_SIZE32)) != PS_OK) {
1017                                 return_val = TD_DBERR;
1018                                 break;
1019                         }
1020                         next_lwp_addr = (psaddr_t)ulwp.ul_forw;
1021 
1022                         ts_state = ulwp.ul_dead? TD_THR_ZOMBIE :
1023                             ulwp.ul_stop? TD_THR_STOPPED :
1024                             ulwp.ul_wchan? TD_THR_SLEEP :
1025                             TD_THR_ACTIVE;
1026                         userpri = ulwp.ul_pri;
1027                         userflags = ulwp.ul_usropts;
1028                         if (ulwp.ul_dead)
1029                                 (void) sigemptyset(&mask);
1030                         else
1031                                 mask = *(sigset_t *)&ulwp.ul_sigmask;
1032 #else   /* _SYSCALL32 */
1033                         return_val = TD_ERR;
1034                         break;
1035 #endif  /* _SYSCALL32 */
1036                 }
1037 
1038                 /*
1039                  * Filter on state, priority, sigmask, and user flags.
1040                  */
1041 
1042                 if ((state != ts_state) &&
1043                     (state != TD_THR_ANY_STATE))
1044                         goto advance;
1045 
1046                 if (ti_pri > userpri)
1047                         goto advance;
1048 
1049                 if (ti_sigmask_p != TD_SIGNO_MASK &&
1050                     !sigequalset(ti_sigmask_p, &mask))
1051                         goto advance;
1052 
1053                 if (ti_user_flags != userflags &&
1054                     ti_user_flags != (unsigned)TD_THR_ANY_USER_FLAGS)
1055                         goto advance;
1056 
1057                 /*
1058                  * Call back - break if the return
1059                  * from the call back is non-zero.
1060                  */
1061                 th.th_ta_p = (td_thragent_t *)ta_p;
1062                 th.th_unique = curr_lwp_addr;
1063                 if ((*cb)(&th, cbdata_p))
1064                         break;
1065 
1066 advance:
1067                 if ((curr_lwp_addr = next_lwp_addr) == first_lwp_addr) {
1068                         /*
1069                          * Switch to the zombie list, unless it is NULL
1070                          * or we have already been doing the zombie list,
1071                          * in which case terminate the loop.
1072                          */
1073                         if (first_zombie_addr == NULL ||
1074                             first_lwp_addr == first_zombie_addr)
1075                                 break;
1076                         curr_lwp_addr = first_lwp_addr = first_zombie_addr;
1077                 }
1078         }
1079 
1080         (void) ps_pcontinue(ph_p);
1081         ph_unlock(ta_p);
1082         return (return_val);
1083 }
1084 
1085 /*
1086  * Enable or disable process synchronization object tracking.
1087  * Currently unused by dbx.
1088  */
1089 #pragma weak td_ta_sync_tracking_enable = __td_ta_sync_tracking_enable
1090 td_err_e
1091 __td_ta_sync_tracking_enable(td_thragent_t *ta_p, int onoff)
1092 {
1093         struct ps_prochandle *ph_p;
1094         td_err_e return_val;
1095         register_sync_t enable;
1096 
1097         if ((ph_p = ph_lock_ta(ta_p, &return_val)) == NULL)
1098                 return (return_val);
1099         /*
1100          * Values of tdb_register_sync in the victim process:
1101          *      REGISTER_SYNC_ENABLE    enables registration of synch objects
1102          *      REGISTER_SYNC_DISABLE   disables registration of synch objects
1103          * These cause the table to be cleared and tdb_register_sync set to:
1104          *      REGISTER_SYNC_ON        registration in effect
1105          *      REGISTER_SYNC_OFF       registration not in effect
1106          */
1107         enable = onoff? REGISTER_SYNC_ENABLE : REGISTER_SYNC_DISABLE;
1108         if (ps_pdwrite(ph_p, ta_p->tdb_register_sync_addr,
1109             &enable, sizeof (enable)) != PS_OK)
1110                 return_val = TD_DBERR;
1111         /*
1112          * Remember that this interface was called (see td_ta_delete()).
1113          */
1114         ta_p->sync_tracking = 1;
1115         ph_unlock(ta_p);
1116         return (return_val);
1117 }
1118 
1119 /*
1120  * Iterate over all known synchronization variables.
1121  * It is very possible that the list generated is incomplete,
1122  * because the iterator can only find synchronization variables
1123  * that have been registered by the process since synchronization
1124  * object registration was enabled.
1125  * The call back function cb is called for each synchronization
1126  * variable with two arguments: a pointer to the synchronization
1127  * handle and the passed-in argument cbdata.
1128  * If cb returns a non-zero value, iterations are terminated.
1129  */
1130 #pragma weak td_ta_sync_iter = __td_ta_sync_iter
1131 td_err_e
1132 __td_ta_sync_iter(td_thragent_t *ta_p, td_sync_iter_f *cb, void *cbdata)
1133 {
1134         struct ps_prochandle *ph_p;
1135         td_err_e        return_val;
1136         int             i;
1137         register_sync_t enable;
1138         psaddr_t        next_desc;
1139         tdb_sync_stats_t sync_stats;
1140         td_synchandle_t synchandle;
1141         psaddr_t        psaddr;
1142         void            *vaddr;
1143         uint64_t        *sync_addr_hash = NULL;
1144 
1145         if (cb == NULL)
1146                 return (TD_ERR);
1147         if ((ph_p = ph_lock_ta(ta_p, &return_val)) == NULL)
1148                 return (return_val);
1149         if (ps_pstop(ph_p) != PS_OK) {
1150                 ph_unlock(ta_p);
1151                 return (TD_DBERR);
1152         }
1153         if (ps_pdread(ph_p, ta_p->tdb_register_sync_addr,
1154             &enable, sizeof (enable)) != PS_OK) {
1155                 return_val = TD_DBERR;
1156                 goto out;
1157         }
1158         if (enable != REGISTER_SYNC_ON)
1159                 goto out;
1160 
1161         /*
1162          * First read the hash table.
1163          * The hash table is large; allocate with mmap().
1164          */
1165         if ((vaddr = mmap(NULL, TDB_HASH_SIZE * sizeof (uint64_t),
1166             PROT_READ|PROT_WRITE, MAP_PRIVATE|MAP_ANON, -1, (off_t)0))
1167             == MAP_FAILED) {
1168                 return_val = TD_MALLOC;
1169                 goto out;
1170         }
1171         sync_addr_hash = vaddr;
1172 
1173         if (ta_p->model == PR_MODEL_NATIVE) {
1174                 if (ps_pdread(ph_p, ta_p->uberdata_addr +
1175                     offsetof(uberdata_t, tdb.tdb_sync_addr_hash),
1176                     &psaddr, sizeof (&psaddr)) != PS_OK) {
1177                         return_val = TD_DBERR;
1178                         goto out;
1179                 }
1180         } else {
1181 #ifdef  _SYSCALL32
1182                 caddr32_t addr;
1183 
1184                 if (ps_pdread(ph_p, ta_p->uberdata_addr +
1185                     offsetof(uberdata32_t, tdb.tdb_sync_addr_hash),
1186                     &addr, sizeof (addr)) != PS_OK) {
1187                         return_val = TD_DBERR;
1188                         goto out;
1189                 }
1190                 psaddr = addr;
1191 #else
1192                 return_val = TD_ERR;
1193                 goto out;
1194 #endif /* _SYSCALL32 */
1195         }
1196 
1197         if (psaddr == NULL)
1198                 goto out;
1199         if (ps_pdread(ph_p, psaddr, sync_addr_hash,
1200             TDB_HASH_SIZE * sizeof (uint64_t)) != PS_OK) {
1201                 return_val = TD_DBERR;
1202                 goto out;
1203         }
1204 
1205         /*
1206          * Now scan the hash table.
1207          */
1208         for (i = 0; i < TDB_HASH_SIZE; i++) {
1209                 for (next_desc = (psaddr_t)sync_addr_hash[i];
1210                     next_desc != NULL;
1211                     next_desc = (psaddr_t)sync_stats.next) {
1212                         if (ps_pdread(ph_p, next_desc,
1213                             &sync_stats, sizeof (sync_stats)) != PS_OK) {
1214                                 return_val = TD_DBERR;
1215                                 goto out;
1216                         }
1217                         if (sync_stats.un.type == TDB_NONE) {
1218                                 /* not registered since registration enabled */
1219                                 continue;
1220                         }
1221                         synchandle.sh_ta_p = ta_p;
1222                         synchandle.sh_unique = (psaddr_t)sync_stats.sync_addr;
1223                         if ((*cb)(&synchandle, cbdata) != 0)
1224                                 goto out;
1225                 }
1226         }
1227 
1228 out:
1229         if (sync_addr_hash != NULL)
1230                 (void) munmap((void *)sync_addr_hash,
1231                     TDB_HASH_SIZE * sizeof (uint64_t));
1232         (void) ps_pcontinue(ph_p);
1233         ph_unlock(ta_p);
1234         return (return_val);
1235 }
1236 
1237 /*
1238  * Enable process statistics collection.
1239  */
1240 #pragma weak td_ta_enable_stats = __td_ta_enable_stats
1241 /* ARGSUSED */
1242 td_err_e
1243 __td_ta_enable_stats(const td_thragent_t *ta_p, int onoff)
1244 {
1245         return (TD_NOCAPAB);
1246 }
1247 
1248 /*
1249  * Reset process statistics.
1250  */
1251 #pragma weak td_ta_reset_stats = __td_ta_reset_stats
1252 /* ARGSUSED */
1253 td_err_e
1254 __td_ta_reset_stats(const td_thragent_t *ta_p)
1255 {
1256         return (TD_NOCAPAB);
1257 }
1258 
1259 /*
1260  * Read process statistics.
1261  */
1262 #pragma weak td_ta_get_stats = __td_ta_get_stats
1263 /* ARGSUSED */
1264 td_err_e
1265 __td_ta_get_stats(const td_thragent_t *ta_p, td_ta_stats_t *tstats)
1266 {
1267         return (TD_NOCAPAB);
1268 }
1269 
1270 /*
1271  * Transfer information from lwp struct to thread information struct.
1272  * XXX -- lots of this needs cleaning up.
1273  */
1274 static void
1275 td_thr2to(td_thragent_t *ta_p, psaddr_t ts_addr,
1276         ulwp_t *ulwp, td_thrinfo_t *ti_p)
1277 {
1278         lwpid_t lwpid;
1279 
1280         if ((lwpid = ulwp->ul_lwpid) == 0)
1281                 lwpid = 1;
1282         (void) memset(ti_p, 0, sizeof (*ti_p));
1283         ti_p->ti_ta_p = ta_p;
1284         ti_p->ti_user_flags = ulwp->ul_usropts;
1285         ti_p->ti_tid = lwpid;
1286         ti_p->ti_exitval = ulwp->ul_rval;
1287         ti_p->ti_startfunc = (psaddr_t)ulwp->ul_startpc;
1288         if (!ulwp->ul_dead) {
1289                 /*
1290                  * The bloody fools got this backwards!
1291                  */
1292                 ti_p->ti_stkbase = (psaddr_t)ulwp->ul_stktop;
1293                 ti_p->ti_stksize = ulwp->ul_stksiz;
1294         }
1295         ti_p->ti_ro_area = ts_addr;
1296         ti_p->ti_ro_size = ulwp->ul_replace?
1297             REPLACEMENT_SIZE : sizeof (ulwp_t);
1298         ti_p->ti_state = ulwp->ul_dead? TD_THR_ZOMBIE :
1299             ulwp->ul_stop? TD_THR_STOPPED :
1300             ulwp->ul_wchan? TD_THR_SLEEP :
1301             TD_THR_ACTIVE;
1302         ti_p->ti_db_suspended = 0;
1303         ti_p->ti_type = TD_THR_USER;
1304         ti_p->ti_sp = ulwp->ul_sp;
1305         ti_p->ti_flags = 0;
1306         ti_p->ti_pri = ulwp->ul_pri;
1307         ti_p->ti_lid = lwpid;
1308         if (!ulwp->ul_dead)
1309                 ti_p->ti_sigmask = ulwp->ul_sigmask;
1310         ti_p->ti_traceme = 0;
1311         ti_p->ti_preemptflag = 0;
1312         ti_p->ti_pirecflag = 0;
1313         (void) sigemptyset(&ti_p->ti_pending);
1314         ti_p->ti_events = ulwp->ul_td_evbuf.eventmask;
1315 }
1316 
1317 #if defined(_LP64) && defined(_SYSCALL32)
1318 static void
1319 td_thr2to32(td_thragent_t *ta_p, psaddr_t ts_addr,
1320         ulwp32_t *ulwp, td_thrinfo_t *ti_p)
1321 {
1322         lwpid_t lwpid;
1323 
1324         if ((lwpid = ulwp->ul_lwpid) == 0)
1325                 lwpid = 1;
1326         (void) memset(ti_p, 0, sizeof (*ti_p));
1327         ti_p->ti_ta_p = ta_p;
1328         ti_p->ti_user_flags = ulwp->ul_usropts;
1329         ti_p->ti_tid = lwpid;
1330         ti_p->ti_exitval = (void *)(uintptr_t)ulwp->ul_rval;
1331         ti_p->ti_startfunc = (psaddr_t)ulwp->ul_startpc;
1332         if (!ulwp->ul_dead) {
1333                 /*
1334                  * The bloody fools got this backwards!
1335                  */
1336                 ti_p->ti_stkbase = (psaddr_t)ulwp->ul_stktop;
1337                 ti_p->ti_stksize = ulwp->ul_stksiz;
1338         }
1339         ti_p->ti_ro_area = ts_addr;
1340         ti_p->ti_ro_size = ulwp->ul_replace?
1341             REPLACEMENT_SIZE32 : sizeof (ulwp32_t);
1342         ti_p->ti_state = ulwp->ul_dead? TD_THR_ZOMBIE :
1343             ulwp->ul_stop? TD_THR_STOPPED :
1344             ulwp->ul_wchan? TD_THR_SLEEP :
1345             TD_THR_ACTIVE;
1346         ti_p->ti_db_suspended = 0;
1347         ti_p->ti_type = TD_THR_USER;
1348         ti_p->ti_sp = (uint32_t)ulwp->ul_sp;
1349         ti_p->ti_flags = 0;
1350         ti_p->ti_pri = ulwp->ul_pri;
1351         ti_p->ti_lid = lwpid;
1352         if (!ulwp->ul_dead)
1353                 ti_p->ti_sigmask = *(sigset_t *)&ulwp->ul_sigmask;
1354         ti_p->ti_traceme = 0;
1355         ti_p->ti_preemptflag = 0;
1356         ti_p->ti_pirecflag = 0;
1357         (void) sigemptyset(&ti_p->ti_pending);
1358         ti_p->ti_events = ulwp->ul_td_evbuf.eventmask;
1359 }
1360 #endif  /* _SYSCALL32 */
1361 
1362 /*
1363  * Get thread information.
1364  */
1365 #pragma weak td_thr_get_info = __td_thr_get_info
1366 td_err_e
1367 __td_thr_get_info(td_thrhandle_t *th_p, td_thrinfo_t *ti_p)
1368 {
1369         struct ps_prochandle *ph_p;
1370         td_thragent_t   *ta_p;
1371         td_err_e        return_val;
1372         psaddr_t        psaddr;
1373 
1374         if (ti_p == NULL)
1375                 return (TD_ERR);
1376         (void) memset(ti_p, NULL, sizeof (*ti_p));
1377 
1378         if ((ph_p = ph_lock_th(th_p, &return_val)) == NULL)
1379                 return (return_val);
1380         ta_p = th_p->th_ta_p;
1381         if (ps_pstop(ph_p) != PS_OK) {
1382                 ph_unlock(ta_p);
1383                 return (TD_DBERR);
1384         }
1385 
1386         /*
1387          * Read the ulwp struct from the process.
1388          * Transfer the ulwp struct to the thread information struct.
1389          */
1390         psaddr = th_p->th_unique;
1391         if (ta_p->model == PR_MODEL_NATIVE) {
1392                 ulwp_t ulwp;
1393 
1394                 if (ps_pdread(ph_p, psaddr, &ulwp, sizeof (ulwp)) != PS_OK &&
1395                     ((void) memset(&ulwp, 0, sizeof (ulwp)),
1396                     ps_pdread(ph_p, psaddr, &ulwp, REPLACEMENT_SIZE)) != PS_OK)
1397                         return_val = TD_DBERR;
1398                 else
1399                         td_thr2to(ta_p, psaddr, &ulwp, ti_p);
1400         } else {
1401 #if defined(_LP64) && defined(_SYSCALL32)
1402                 ulwp32_t ulwp;
1403 
1404                 if (ps_pdread(ph_p, psaddr, &ulwp, sizeof (ulwp)) != PS_OK &&
1405                     ((void) memset(&ulwp, 0, sizeof (ulwp)),
1406                     ps_pdread(ph_p, psaddr, &ulwp, REPLACEMENT_SIZE32)) !=
1407                     PS_OK)
1408                         return_val = TD_DBERR;
1409                 else
1410                         td_thr2to32(ta_p, psaddr, &ulwp, ti_p);
1411 #else
1412                 return_val = TD_ERR;
1413 #endif  /* _SYSCALL32 */
1414         }
1415 
1416         (void) ps_pcontinue(ph_p);
1417         ph_unlock(ta_p);
1418         return (return_val);
1419 }
1420 
1421 /*
1422  * Given a process and an event number, return information about
1423  * an address in the process or at which a breakpoint can be set
1424  * to monitor the event.
1425  */
1426 #pragma weak td_ta_event_addr = __td_ta_event_addr
1427 td_err_e
1428 __td_ta_event_addr(td_thragent_t *ta_p, td_event_e event, td_notify_t *notify_p)
1429 {
1430         if (ta_p == NULL)
1431                 return (TD_BADTA);
1432         if (event < TD_MIN_EVENT_NUM || event > TD_MAX_EVENT_NUM)
1433                 return (TD_NOEVENT);
1434         if (notify_p == NULL)
1435                 return (TD_ERR);
1436 
1437         notify_p->type = NOTIFY_BPT;
1438         notify_p->u.bptaddr = ta_p->tdb_events[event - TD_MIN_EVENT_NUM];
1439 
1440         return (TD_OK);
1441 }
1442 
1443 /*
1444  * Add the events in eventset 2 to eventset 1.
1445  */
1446 static void
1447 eventsetaddset(td_thr_events_t *event1_p, td_thr_events_t *event2_p)
1448 {
1449         int     i;
1450 
1451         for (i = 0; i < TD_EVENTSIZE; i++)
1452                 event1_p->event_bits[i] |= event2_p->event_bits[i];
1453 }
1454 
1455 /*
1456  * Delete the events in eventset 2 from eventset 1.
1457  */
1458 static void
1459 eventsetdelset(td_thr_events_t *event1_p, td_thr_events_t *event2_p)
1460 {
1461         int     i;
1462 
1463         for (i = 0; i < TD_EVENTSIZE; i++)
1464                 event1_p->event_bits[i] &= ~event2_p->event_bits[i];
1465 }
1466 
1467 /*
1468  * Either add or delete the given event set from a thread's event mask.
1469  */
1470 static td_err_e
1471 mod_eventset(td_thrhandle_t *th_p, td_thr_events_t *events, int onoff)
1472 {
1473         struct ps_prochandle *ph_p;
1474         td_err_e        return_val = TD_OK;
1475         char            enable;
1476         td_thr_events_t evset;
1477         psaddr_t        psaddr_evset;
1478         psaddr_t        psaddr_enab;
1479 
1480         if ((ph_p = ph_lock_th(th_p, &return_val)) == NULL)
1481                 return (return_val);
1482         if (th_p->th_ta_p->model == PR_MODEL_NATIVE) {
1483                 ulwp_t *ulwp = (ulwp_t *)th_p->th_unique;
1484                 psaddr_evset = (psaddr_t)&ulwp->ul_td_evbuf.eventmask;
1485                 psaddr_enab = (psaddr_t)&ulwp->ul_td_events_enable;
1486         } else {
1487 #if defined(_LP64) && defined(_SYSCALL32)
1488                 ulwp32_t *ulwp = (ulwp32_t *)th_p->th_unique;
1489                 psaddr_evset = (psaddr_t)&ulwp->ul_td_evbuf.eventmask;
1490                 psaddr_enab = (psaddr_t)&ulwp->ul_td_events_enable;
1491 #else
1492                 ph_unlock(th_p->th_ta_p);
1493                 return (TD_ERR);
1494 #endif  /* _SYSCALL32 */
1495         }
1496         if (ps_pstop(ph_p) != PS_OK) {
1497                 ph_unlock(th_p->th_ta_p);
1498                 return (TD_DBERR);
1499         }
1500 
1501         if (ps_pdread(ph_p, psaddr_evset, &evset, sizeof (evset)) != PS_OK)
1502                 return_val = TD_DBERR;
1503         else {
1504                 if (onoff)
1505                         eventsetaddset(&evset, events);
1506                 else
1507                         eventsetdelset(&evset, events);
1508                 if (ps_pdwrite(ph_p, psaddr_evset, &evset, sizeof (evset))
1509                     != PS_OK)
1510                         return_val = TD_DBERR;
1511                 else {
1512                         enable = 0;
1513                         if (td_eventismember(&evset, TD_EVENTS_ENABLE))
1514                                 enable = 1;
1515                         if (ps_pdwrite(ph_p, psaddr_enab,
1516                             &enable, sizeof (enable)) != PS_OK)
1517                                 return_val = TD_DBERR;
1518                 }
1519         }
1520 
1521         (void) ps_pcontinue(ph_p);
1522         ph_unlock(th_p->th_ta_p);
1523         return (return_val);
1524 }
1525 
1526 /*
1527  * Enable or disable tracing for a given thread.  Tracing
1528  * is filtered based on the event mask of each thread.  Tracing
1529  * can be turned on/off for the thread without changing thread
1530  * event mask.
1531  * Currently unused by dbx.
1532  */
1533 #pragma weak td_thr_event_enable = __td_thr_event_enable
1534 td_err_e
1535 __td_thr_event_enable(td_thrhandle_t *th_p, int onoff)
1536 {
1537         td_thr_events_t evset;
1538 
1539         td_event_emptyset(&evset);
1540         td_event_addset(&evset, TD_EVENTS_ENABLE);
1541         return (mod_eventset(th_p, &evset, onoff));
1542 }
1543 
1544 /*
1545  * Set event mask to enable event. event is turned on in
1546  * event mask for thread.  If a thread encounters an event
1547  * for which its event mask is on, notification will be sent
1548  * to the debugger.
1549  * Addresses for each event are provided to the
1550  * debugger.  It is assumed that a breakpoint of some type will
1551  * be placed at that address.  If the event mask for the thread
1552  * is on, the instruction at the address will be executed.
1553  * Otherwise, the instruction will be skipped.
1554  */
1555 #pragma weak td_thr_set_event = __td_thr_set_event
1556 td_err_e
1557 __td_thr_set_event(td_thrhandle_t *th_p, td_thr_events_t *events)
1558 {
1559         return (mod_eventset(th_p, events, 1));
1560 }
1561 
1562 /*
1563  * Enable or disable a set of events in the process-global event mask,
1564  * depending on the value of onoff.
1565  */
1566 static td_err_e
1567 td_ta_mod_event(td_thragent_t *ta_p, td_thr_events_t *events, int onoff)
1568 {
1569         struct ps_prochandle *ph_p;
1570         td_thr_events_t targ_eventset;
1571         td_err_e        return_val;
1572 
1573         if ((ph_p = ph_lock_ta(ta_p, &return_val)) == NULL)
1574                 return (return_val);
1575         if (ps_pstop(ph_p) != PS_OK) {
1576                 ph_unlock(ta_p);
1577                 return (TD_DBERR);
1578         }
1579         if (ps_pdread(ph_p, ta_p->tdb_eventmask_addr,
1580             &targ_eventset, sizeof (targ_eventset)) != PS_OK)
1581                 return_val = TD_DBERR;
1582         else {
1583                 if (onoff)
1584                         eventsetaddset(&targ_eventset, events);
1585                 else
1586                         eventsetdelset(&targ_eventset, events);
1587                 if (ps_pdwrite(ph_p, ta_p->tdb_eventmask_addr,
1588                     &targ_eventset, sizeof (targ_eventset)) != PS_OK)
1589                         return_val = TD_DBERR;
1590         }
1591         (void) ps_pcontinue(ph_p);
1592         ph_unlock(ta_p);
1593         return (return_val);
1594 }
1595 
1596 /*
1597  * Enable a set of events in the process-global event mask.
1598  */
1599 #pragma weak td_ta_set_event = __td_ta_set_event
1600 td_err_e
1601 __td_ta_set_event(td_thragent_t *ta_p, td_thr_events_t *events)
1602 {
1603         return (td_ta_mod_event(ta_p, events, 1));
1604 }
1605 
1606 /*
1607  * Set event mask to disable the given event set; these events are cleared
1608  * from the event mask of the thread.  Events that occur for a thread
1609  * with the event masked off will not cause notification to be
1610  * sent to the debugger (see td_thr_set_event for fuller description).
1611  */
1612 #pragma weak td_thr_clear_event = __td_thr_clear_event
1613 td_err_e
1614 __td_thr_clear_event(td_thrhandle_t *th_p, td_thr_events_t *events)
1615 {
1616         return (mod_eventset(th_p, events, 0));
1617 }
1618 
1619 /*
1620  * Disable a set of events in the process-global event mask.
1621  */
1622 #pragma weak td_ta_clear_event = __td_ta_clear_event
1623 td_err_e
1624 __td_ta_clear_event(td_thragent_t *ta_p, td_thr_events_t *events)
1625 {
1626         return (td_ta_mod_event(ta_p, events, 0));
1627 }
1628 
1629 /*
1630  * This function returns the most recent event message, if any,
1631  * associated with a thread.  Given a thread handle, return the message
1632  * corresponding to the event encountered by the thread.  Only one
1633  * message per thread is saved.  Messages from earlier events are lost
1634  * when later events occur.
1635  */
1636 #pragma weak td_thr_event_getmsg = __td_thr_event_getmsg
1637 td_err_e
1638 __td_thr_event_getmsg(td_thrhandle_t *th_p, td_event_msg_t *msg)
1639 {
1640         struct ps_prochandle *ph_p;
1641         td_err_e        return_val = TD_OK;
1642         psaddr_t        psaddr;
1643 
1644         if ((ph_p = ph_lock_th(th_p, &return_val)) == NULL)
1645                 return (return_val);
1646         if (ps_pstop(ph_p) != PS_OK) {
1647                 ph_unlock(th_p->th_ta_p);
1648                 return (TD_BADTA);
1649         }
1650         if (th_p->th_ta_p->model == PR_MODEL_NATIVE) {
1651                 ulwp_t *ulwp = (ulwp_t *)th_p->th_unique;
1652                 td_evbuf_t evbuf;
1653 
1654                 psaddr = (psaddr_t)&ulwp->ul_td_evbuf;
1655                 if (ps_pdread(ph_p, psaddr, &evbuf, sizeof (evbuf)) != PS_OK) {
1656                         return_val = TD_DBERR;
1657                 } else if (evbuf.eventnum == TD_EVENT_NONE) {
1658                         return_val = TD_NOEVENT;
1659                 } else {
1660                         msg->event = evbuf.eventnum;
1661                         msg->th_p = (td_thrhandle_t *)th_p;
1662                         msg->msg.data = (uintptr_t)evbuf.eventdata;
1663                         /* "Consume" the message */
1664                         evbuf.eventnum = TD_EVENT_NONE;
1665                         evbuf.eventdata = NULL;
1666                         if (ps_pdwrite(ph_p, psaddr, &evbuf, sizeof (evbuf))
1667                             != PS_OK)
1668                                 return_val = TD_DBERR;
1669                 }
1670         } else {
1671 #if defined(_LP64) && defined(_SYSCALL32)
1672                 ulwp32_t *ulwp = (ulwp32_t *)th_p->th_unique;
1673                 td_evbuf32_t evbuf;
1674 
1675                 psaddr = (psaddr_t)&ulwp->ul_td_evbuf;
1676                 if (ps_pdread(ph_p, psaddr, &evbuf, sizeof (evbuf)) != PS_OK) {
1677                         return_val = TD_DBERR;
1678                 } else if (evbuf.eventnum == TD_EVENT_NONE) {
1679                         return_val = TD_NOEVENT;
1680                 } else {
1681                         msg->event = evbuf.eventnum;
1682                         msg->th_p = (td_thrhandle_t *)th_p;
1683                         msg->msg.data = (uintptr_t)evbuf.eventdata;
1684                         /* "Consume" the message */
1685                         evbuf.eventnum = TD_EVENT_NONE;
1686                         evbuf.eventdata = NULL;
1687                         if (ps_pdwrite(ph_p, psaddr, &evbuf, sizeof (evbuf))
1688                             != PS_OK)
1689                                 return_val = TD_DBERR;
1690                 }
1691 #else
1692                 return_val = TD_ERR;
1693 #endif  /* _SYSCALL32 */
1694         }
1695 
1696         (void) ps_pcontinue(ph_p);
1697         ph_unlock(th_p->th_ta_p);
1698         return (return_val);
1699 }
1700 
1701 /*
1702  * The callback function td_ta_event_getmsg uses when looking for
1703  * a thread with an event.  A thin wrapper around td_thr_event_getmsg.
1704  */
1705 static int
1706 event_msg_cb(const td_thrhandle_t *th_p, void *arg)
1707 {
1708         static td_thrhandle_t th;
1709         td_event_msg_t *msg = arg;
1710 
1711         if (__td_thr_event_getmsg((td_thrhandle_t *)th_p, msg) == TD_OK) {
1712                 /*
1713                  * Got an event, stop iterating.
1714                  *
1715                  * Because of past mistakes in interface definition,
1716                  * we are forced to pass back a static local variable
1717                  * for the thread handle because th_p is a pointer
1718                  * to a local variable in __td_ta_thr_iter().
1719                  * Grr...
1720                  */
1721                 th = *th_p;
1722                 msg->th_p = &th;
1723                 return (1);
1724         }
1725         return (0);
1726 }
1727 
1728 /*
1729  * This function is just like td_thr_event_getmsg, except that it is
1730  * passed a process handle rather than a thread handle, and returns
1731  * an event message for some thread in the process that has an event
1732  * message pending.  If no thread has an event message pending, this
1733  * routine returns TD_NOEVENT.  Thus, all pending event messages may
1734  * be collected from a process by repeatedly calling this routine
1735  * until it returns TD_NOEVENT.
1736  */
1737 #pragma weak td_ta_event_getmsg = __td_ta_event_getmsg
1738 td_err_e
1739 __td_ta_event_getmsg(td_thragent_t *ta_p, td_event_msg_t *msg)
1740 {
1741         td_err_e return_val;
1742 
1743         if (ta_p == NULL)
1744                 return (TD_BADTA);
1745         if (ta_p->ph_p == NULL)
1746                 return (TD_BADPH);
1747         if (msg == NULL)
1748                 return (TD_ERR);
1749         msg->event = TD_EVENT_NONE;
1750         if ((return_val = __td_ta_thr_iter(ta_p, event_msg_cb, msg,
1751             TD_THR_ANY_STATE, TD_THR_LOWEST_PRIORITY, TD_SIGNO_MASK,
1752             TD_THR_ANY_USER_FLAGS)) != TD_OK)
1753                 return (return_val);
1754         if (msg->event == TD_EVENT_NONE)
1755                 return (TD_NOEVENT);
1756         return (TD_OK);
1757 }
1758 
1759 static lwpid_t
1760 thr_to_lwpid(const td_thrhandle_t *th_p)
1761 {
1762         struct ps_prochandle *ph_p = th_p->th_ta_p->ph_p;
1763         lwpid_t lwpid;
1764 
1765         /*
1766          * The caller holds the prochandle lock
1767          * and has already verfied everything.
1768          */
1769         if (th_p->th_ta_p->model == PR_MODEL_NATIVE) {
1770                 ulwp_t *ulwp = (ulwp_t *)th_p->th_unique;
1771 
1772                 if (ps_pdread(ph_p, (psaddr_t)&ulwp->ul_lwpid,
1773                     &lwpid, sizeof (lwpid)) != PS_OK)
1774                         lwpid = 0;
1775                 else if (lwpid == 0)
1776                         lwpid = 1;
1777         } else {
1778 #if defined(_LP64) && defined(_SYSCALL32)
1779                 ulwp32_t *ulwp = (ulwp32_t *)th_p->th_unique;
1780 
1781                 if (ps_pdread(ph_p, (psaddr_t)&ulwp->ul_lwpid,
1782                     &lwpid, sizeof (lwpid)) != PS_OK)
1783                         lwpid = 0;
1784                 else if (lwpid == 0)
1785                         lwpid = 1;
1786 #else
1787                 lwpid = 0;
1788 #endif  /* _SYSCALL32 */
1789         }
1790 
1791         return (lwpid);
1792 }
1793 
1794 /*
1795  * Suspend a thread.
1796  * XXX: What does this mean in a one-level model?
1797  */
1798 #pragma weak td_thr_dbsuspend = __td_thr_dbsuspend
1799 td_err_e
1800 __td_thr_dbsuspend(const td_thrhandle_t *th_p)
1801 {
1802         struct ps_prochandle *ph_p;
1803         td_err_e return_val;
1804 
1805         if ((ph_p = ph_lock_th(th_p, &return_val)) == NULL)
1806                 return (return_val);
1807         if (ps_lstop(ph_p, thr_to_lwpid(th_p)) != PS_OK)
1808                 return_val = TD_DBERR;
1809         ph_unlock(th_p->th_ta_p);
1810         return (return_val);
1811 }
1812 
1813 /*
1814  * Resume a suspended thread.
1815  * XXX: What does this mean in a one-level model?
1816  */
1817 #pragma weak td_thr_dbresume = __td_thr_dbresume
1818 td_err_e
1819 __td_thr_dbresume(const td_thrhandle_t *th_p)
1820 {
1821         struct ps_prochandle *ph_p;
1822         td_err_e return_val;
1823 
1824         if ((ph_p = ph_lock_th(th_p, &return_val)) == NULL)
1825                 return (return_val);
1826         if (ps_lcontinue(ph_p, thr_to_lwpid(th_p)) != PS_OK)
1827                 return_val = TD_DBERR;
1828         ph_unlock(th_p->th_ta_p);
1829         return (return_val);
1830 }
1831 
1832 /*
1833  * Set a thread's signal mask.
1834  * Currently unused by dbx.
1835  */
1836 #pragma weak td_thr_sigsetmask = __td_thr_sigsetmask
1837 /* ARGSUSED */
1838 td_err_e
1839 __td_thr_sigsetmask(const td_thrhandle_t *th_p, const sigset_t ti_sigmask)
1840 {
1841         return (TD_NOCAPAB);
1842 }
1843 
1844 /*
1845  * Set a thread's "signals-pending" set.
1846  * Currently unused by dbx.
1847  */
1848 #pragma weak td_thr_setsigpending = __td_thr_setsigpending
1849 /* ARGSUSED */
1850 td_err_e
1851 __td_thr_setsigpending(const td_thrhandle_t *th_p,
1852         uchar_t ti_pending_flag, const sigset_t ti_pending)
1853 {
1854         return (TD_NOCAPAB);
1855 }
1856 
1857 /*
1858  * Get a thread's general register set.
1859  */
1860 #pragma weak td_thr_getgregs = __td_thr_getgregs
1861 td_err_e
1862 __td_thr_getgregs(td_thrhandle_t *th_p, prgregset_t regset)
1863 {
1864         struct ps_prochandle *ph_p;
1865         td_err_e return_val;
1866 
1867         if ((ph_p = ph_lock_th(th_p, &return_val)) == NULL)
1868                 return (return_val);
1869         if (ps_pstop(ph_p) != PS_OK) {
1870                 ph_unlock(th_p->th_ta_p);
1871                 return (TD_DBERR);
1872         }
1873 
1874         if (ps_lgetregs(ph_p, thr_to_lwpid(th_p), regset) != PS_OK)
1875                 return_val = TD_DBERR;
1876 
1877         (void) ps_pcontinue(ph_p);
1878         ph_unlock(th_p->th_ta_p);
1879         return (return_val);
1880 }
1881 
1882 /*
1883  * Set a thread's general register set.
1884  */
1885 #pragma weak td_thr_setgregs = __td_thr_setgregs
1886 td_err_e
1887 __td_thr_setgregs(td_thrhandle_t *th_p, const prgregset_t regset)
1888 {
1889         struct ps_prochandle *ph_p;
1890         td_err_e return_val;
1891 
1892         if ((ph_p = ph_lock_th(th_p, &return_val)) == NULL)
1893                 return (return_val);
1894         if (ps_pstop(ph_p) != PS_OK) {
1895                 ph_unlock(th_p->th_ta_p);
1896                 return (TD_DBERR);
1897         }
1898 
1899         if (ps_lsetregs(ph_p, thr_to_lwpid(th_p), regset) != PS_OK)
1900                 return_val = TD_DBERR;
1901 
1902         (void) ps_pcontinue(ph_p);
1903         ph_unlock(th_p->th_ta_p);
1904         return (return_val);
1905 }
1906 
1907 /*
1908  * Get a thread's floating-point register set.
1909  */
1910 #pragma weak td_thr_getfpregs = __td_thr_getfpregs
1911 td_err_e
1912 __td_thr_getfpregs(td_thrhandle_t *th_p, prfpregset_t *fpregset)
1913 {
1914         struct ps_prochandle *ph_p;
1915         td_err_e return_val;
1916 
1917         if ((ph_p = ph_lock_th(th_p, &return_val)) == NULL)
1918                 return (return_val);
1919         if (ps_pstop(ph_p) != PS_OK) {
1920                 ph_unlock(th_p->th_ta_p);
1921                 return (TD_DBERR);
1922         }
1923 
1924         if (ps_lgetfpregs(ph_p, thr_to_lwpid(th_p), fpregset) != PS_OK)
1925                 return_val = TD_DBERR;
1926 
1927         (void) ps_pcontinue(ph_p);
1928         ph_unlock(th_p->th_ta_p);
1929         return (return_val);
1930 }
1931 
1932 /*
1933  * Set a thread's floating-point register set.
1934  */
1935 #pragma weak td_thr_setfpregs = __td_thr_setfpregs
1936 td_err_e
1937 __td_thr_setfpregs(td_thrhandle_t *th_p, const prfpregset_t *fpregset)
1938 {
1939         struct ps_prochandle *ph_p;
1940         td_err_e return_val;
1941 
1942         if ((ph_p = ph_lock_th(th_p, &return_val)) == NULL)
1943                 return (return_val);
1944         if (ps_pstop(ph_p) != PS_OK) {
1945                 ph_unlock(th_p->th_ta_p);
1946                 return (TD_DBERR);
1947         }
1948 
1949         if (ps_lsetfpregs(ph_p, thr_to_lwpid(th_p), fpregset) != PS_OK)
1950                 return_val = TD_DBERR;
1951 
1952         (void) ps_pcontinue(ph_p);
1953         ph_unlock(th_p->th_ta_p);
1954         return (return_val);
1955 }
1956 
1957 /*
1958  * Get the size of the extra state register set for this architecture.
1959  * Currently unused by dbx.
1960  */
1961 #pragma weak td_thr_getxregsize = __td_thr_getxregsize
1962 /* ARGSUSED */
1963 td_err_e
1964 __td_thr_getxregsize(td_thrhandle_t *th_p, int *xregsize)
1965 {
1966 #if defined(__sparc)
1967         struct ps_prochandle *ph_p;
1968         td_err_e return_val;
1969 
1970         if ((ph_p = ph_lock_th(th_p, &return_val)) == NULL)
1971                 return (return_val);
1972         if (ps_pstop(ph_p) != PS_OK) {
1973                 ph_unlock(th_p->th_ta_p);
1974                 return (TD_DBERR);
1975         }
1976 
1977         if (ps_lgetxregsize(ph_p, thr_to_lwpid(th_p), xregsize) != PS_OK)
1978                 return_val = TD_DBERR;
1979 
1980         (void) ps_pcontinue(ph_p);
1981         ph_unlock(th_p->th_ta_p);
1982         return (return_val);
1983 #else   /* __sparc */
1984         return (TD_NOXREGS);
1985 #endif  /* __sparc */
1986 }
1987 
1988 /*
1989  * Get a thread's extra state register set.
1990  */
1991 #pragma weak td_thr_getxregs = __td_thr_getxregs
1992 /* ARGSUSED */
1993 td_err_e
1994 __td_thr_getxregs(td_thrhandle_t *th_p, void *xregset)
1995 {
1996 #if defined(__sparc)
1997         struct ps_prochandle *ph_p;
1998         td_err_e return_val;
1999 
2000         if ((ph_p = ph_lock_th(th_p, &return_val)) == NULL)
2001                 return (return_val);
2002         if (ps_pstop(ph_p) != PS_OK) {
2003                 ph_unlock(th_p->th_ta_p);
2004                 return (TD_DBERR);
2005         }
2006 
2007         if (ps_lgetxregs(ph_p, thr_to_lwpid(th_p), (caddr_t)xregset) != PS_OK)
2008                 return_val = TD_DBERR;
2009 
2010         (void) ps_pcontinue(ph_p);
2011         ph_unlock(th_p->th_ta_p);
2012         return (return_val);
2013 #else   /* __sparc */
2014         return (TD_NOXREGS);
2015 #endif  /* __sparc */
2016 }
2017 
2018 /*
2019  * Set a thread's extra state register set.
2020  */
2021 #pragma weak td_thr_setxregs = __td_thr_setxregs
2022 /* ARGSUSED */
2023 td_err_e
2024 __td_thr_setxregs(td_thrhandle_t *th_p, const void *xregset)
2025 {
2026 #if defined(__sparc)
2027         struct ps_prochandle *ph_p;
2028         td_err_e return_val;
2029 
2030         if ((ph_p = ph_lock_th(th_p, &return_val)) == NULL)
2031                 return (return_val);
2032         if (ps_pstop(ph_p) != PS_OK) {
2033                 ph_unlock(th_p->th_ta_p);
2034                 return (TD_DBERR);
2035         }
2036 
2037         if (ps_lsetxregs(ph_p, thr_to_lwpid(th_p), (caddr_t)xregset) != PS_OK)
2038                 return_val = TD_DBERR;
2039 
2040         (void) ps_pcontinue(ph_p);
2041         ph_unlock(th_p->th_ta_p);
2042         return (return_val);
2043 #else   /* __sparc */
2044         return (TD_NOXREGS);
2045 #endif  /* __sparc */
2046 }
2047 
2048 struct searcher {
2049         psaddr_t        addr;
2050         int             status;
2051 };
2052 
2053 /*
2054  * Check the struct thread address in *th_p again first
2055  * value in "data".  If value in data is found, set second value
2056  * in "data" to 1 and return 1 to terminate iterations.
2057  * This function is used by td_thr_validate() to verify that
2058  * a thread handle is valid.
2059  */
2060 static int
2061 td_searcher(const td_thrhandle_t *th_p, void *data)
2062 {
2063         struct searcher *searcher_data = (struct searcher *)data;
2064 
2065         if (searcher_data->addr == th_p->th_unique) {
2066                 searcher_data->status = 1;
2067                 return (1);
2068         }
2069         return (0);
2070 }
2071 
2072 /*
2073  * Validate the thread handle.  Check that
2074  * a thread exists in the thread agent/process that
2075  * corresponds to thread with handle *th_p.
2076  * Currently unused by dbx.
2077  */
2078 #pragma weak td_thr_validate = __td_thr_validate
2079 td_err_e
2080 __td_thr_validate(const td_thrhandle_t *th_p)
2081 {
2082         td_err_e return_val;
2083         struct searcher searcher_data = {0, 0};
2084 
2085         if (th_p == NULL)
2086                 return (TD_BADTH);
2087         if (th_p->th_unique == NULL || th_p->th_ta_p == NULL)
2088                 return (TD_BADTH);
2089 
2090         /*
2091          * LOCKING EXCEPTION - Locking is not required
2092          * here because no use of the thread agent is made (other
2093          * than the sanity check) and checking of the thread
2094          * agent will be done in __td_ta_thr_iter.
2095          */
2096 
2097         searcher_data.addr = th_p->th_unique;
2098         return_val = __td_ta_thr_iter(th_p->th_ta_p,
2099             td_searcher, &searcher_data,
2100             TD_THR_ANY_STATE, TD_THR_LOWEST_PRIORITY,
2101             TD_SIGNO_MASK, TD_THR_ANY_USER_FLAGS);
2102 
2103         if (return_val == TD_OK && searcher_data.status == 0)
2104                 return_val = TD_NOTHR;
2105 
2106         return (return_val);
2107 }
2108 
2109 /*
2110  * Get a thread's private binding to a given thread specific
2111  * data(TSD) key(see thr_getspecific(3T).  If the thread doesn't
2112  * have a binding for a particular key, then NULL is returned.
2113  */
2114 #pragma weak td_thr_tsd = __td_thr_tsd
2115 td_err_e
2116 __td_thr_tsd(td_thrhandle_t *th_p, thread_key_t key, void **data_pp)
2117 {
2118         struct ps_prochandle *ph_p;
2119         td_thragent_t   *ta_p;
2120         td_err_e        return_val;
2121         int             maxkey;
2122         int             nkey;
2123         psaddr_t        tsd_paddr;
2124 
2125         if (data_pp == NULL)
2126                 return (TD_ERR);
2127         *data_pp = NULL;
2128         if ((ph_p = ph_lock_th(th_p, &return_val)) == NULL)
2129                 return (return_val);
2130         ta_p = th_p->th_ta_p;
2131         if (ps_pstop(ph_p) != PS_OK) {
2132                 ph_unlock(ta_p);
2133                 return (TD_DBERR);
2134         }
2135 
2136         if (ta_p->model == PR_MODEL_NATIVE) {
2137                 ulwp_t *ulwp = (ulwp_t *)th_p->th_unique;
2138                 tsd_metadata_t tsdm;
2139                 tsd_t stsd;
2140 
2141                 if (ps_pdread(ph_p,
2142                     ta_p->uberdata_addr + offsetof(uberdata_t, tsd_metadata),
2143                     &tsdm, sizeof (tsdm)) != PS_OK)
2144                         return_val = TD_DBERR;
2145                 else if (ps_pdread(ph_p, (psaddr_t)&ulwp->ul_stsd,
2146                     &tsd_paddr, sizeof (tsd_paddr)) != PS_OK)
2147                         return_val = TD_DBERR;
2148                 else if (tsd_paddr != NULL &&
2149                     ps_pdread(ph_p, tsd_paddr, &stsd, sizeof (stsd)) != PS_OK)
2150                         return_val = TD_DBERR;
2151                 else {
2152                         maxkey = tsdm.tsdm_nused;
2153                         nkey = tsd_paddr == NULL ? TSD_NFAST : stsd.tsd_nalloc;
2154 
2155                         if (key < TSD_NFAST)
2156                                 tsd_paddr = (psaddr_t)&ulwp->ul_ftsd[0];
2157                 }
2158         } else {
2159 #if defined(_LP64) && defined(_SYSCALL32)
2160                 ulwp32_t *ulwp = (ulwp32_t *)th_p->th_unique;
2161                 tsd_metadata32_t tsdm;
2162                 tsd32_t stsd;
2163                 caddr32_t addr;
2164 
2165                 if (ps_pdread(ph_p,
2166                     ta_p->uberdata_addr + offsetof(uberdata32_t, tsd_metadata),
2167                     &tsdm, sizeof (tsdm)) != PS_OK)
2168                         return_val = TD_DBERR;
2169                 else if (ps_pdread(ph_p, (psaddr_t)&ulwp->ul_stsd,
2170                     &addr, sizeof (addr)) != PS_OK)
2171                         return_val = TD_DBERR;
2172                 else if (addr != NULL &&
2173                     ps_pdread(ph_p, addr, &stsd, sizeof (stsd)) != PS_OK)
2174                         return_val = TD_DBERR;
2175                 else {
2176                         maxkey = tsdm.tsdm_nused;
2177                         nkey = addr == NULL ? TSD_NFAST : stsd.tsd_nalloc;
2178 
2179                         if (key < TSD_NFAST) {
2180                                 tsd_paddr = (psaddr_t)&ulwp->ul_ftsd[0];
2181                         } else {
2182                                 tsd_paddr = addr;
2183                         }
2184                 }
2185 #else
2186                 return_val = TD_ERR;
2187 #endif  /* _SYSCALL32 */
2188         }
2189 
2190         if (return_val == TD_OK && (key < 1 || key >= maxkey))
2191                 return_val = TD_NOTSD;
2192         if (return_val != TD_OK || key >= nkey) {
2193                 /* NULL has already been stored in data_pp */
2194                 (void) ps_pcontinue(ph_p);
2195                 ph_unlock(ta_p);
2196                 return (return_val);
2197         }
2198 
2199         /*
2200          * Read the value from the thread's tsd array.
2201          */
2202         if (ta_p->model == PR_MODEL_NATIVE) {
2203                 void *value;
2204 
2205                 if (ps_pdread(ph_p, tsd_paddr + key * sizeof (void *),
2206                     &value, sizeof (value)) != PS_OK)
2207                         return_val = TD_DBERR;
2208                 else
2209                         *data_pp = value;
2210 #if defined(_LP64) && defined(_SYSCALL32)
2211         } else {
2212                 caddr32_t value32;
2213 
2214                 if (ps_pdread(ph_p, tsd_paddr + key * sizeof (caddr32_t),
2215                     &value32, sizeof (value32)) != PS_OK)
2216                         return_val = TD_DBERR;
2217                 else
2218                         *data_pp = (void *)(uintptr_t)value32;
2219 #endif  /* _SYSCALL32 */
2220         }
2221 
2222         (void) ps_pcontinue(ph_p);
2223         ph_unlock(ta_p);
2224         return (return_val);
2225 }
2226 
2227 /*
2228  * Get the base address of a thread's thread local storage (TLS) block
2229  * for the module (executable or shared object) identified by 'moduleid'.
2230  */
2231 #pragma weak td_thr_tlsbase = __td_thr_tlsbase
2232 td_err_e
2233 __td_thr_tlsbase(td_thrhandle_t *th_p, ulong_t moduleid, psaddr_t *base)
2234 {
2235         struct ps_prochandle *ph_p;
2236         td_thragent_t   *ta_p;
2237         td_err_e        return_val;
2238 
2239         if (base == NULL)
2240                 return (TD_ERR);
2241         *base = NULL;
2242         if ((ph_p = ph_lock_th(th_p, &return_val)) == NULL)
2243                 return (return_val);
2244         ta_p = th_p->th_ta_p;
2245         if (ps_pstop(ph_p) != PS_OK) {
2246                 ph_unlock(ta_p);
2247                 return (TD_DBERR);
2248         }
2249 
2250         if (ta_p->model == PR_MODEL_NATIVE) {
2251                 ulwp_t *ulwp = (ulwp_t *)th_p->th_unique;
2252                 tls_metadata_t tls_metadata;
2253                 TLS_modinfo tlsmod;
2254                 tls_t tls;
2255 
2256                 if (ps_pdread(ph_p,
2257                     ta_p->uberdata_addr + offsetof(uberdata_t, tls_metadata),
2258                     &tls_metadata, sizeof (tls_metadata)) != PS_OK)
2259                         return_val = TD_DBERR;
2260                 else if (moduleid >= tls_metadata.tls_modinfo.tls_size)
2261                         return_val = TD_NOTLS;
2262                 else if (ps_pdread(ph_p,
2263                     (psaddr_t)((TLS_modinfo *)
2264                     tls_metadata.tls_modinfo.tls_data + moduleid),
2265                     &tlsmod, sizeof (tlsmod)) != PS_OK)
2266                         return_val = TD_DBERR;
2267                 else if (tlsmod.tm_memsz == 0)
2268                         return_val = TD_NOTLS;
2269                 else if (tlsmod.tm_flags & TM_FLG_STATICTLS)
2270                         *base = (psaddr_t)ulwp - tlsmod.tm_stattlsoffset;
2271                 else if (ps_pdread(ph_p, (psaddr_t)&ulwp->ul_tls,
2272                     &tls, sizeof (tls)) != PS_OK)
2273                         return_val = TD_DBERR;
2274                 else if (moduleid >= tls.tls_size)
2275                         return_val = TD_TLSDEFER;
2276                 else if (ps_pdread(ph_p,
2277                     (psaddr_t)((tls_t *)tls.tls_data + moduleid),
2278                     &tls, sizeof (tls)) != PS_OK)
2279                         return_val = TD_DBERR;
2280                 else if (tls.tls_size == 0)
2281                         return_val = TD_TLSDEFER;
2282                 else
2283                         *base = (psaddr_t)tls.tls_data;
2284         } else {
2285 #if defined(_LP64) && defined(_SYSCALL32)
2286                 ulwp32_t *ulwp = (ulwp32_t *)th_p->th_unique;
2287                 tls_metadata32_t tls_metadata;
2288                 TLS_modinfo32 tlsmod;
2289                 tls32_t tls;
2290 
2291                 if (ps_pdread(ph_p,
2292                     ta_p->uberdata_addr + offsetof(uberdata32_t, tls_metadata),
2293                     &tls_metadata, sizeof (tls_metadata)) != PS_OK)
2294                         return_val = TD_DBERR;
2295                 else if (moduleid >= tls_metadata.tls_modinfo.tls_size)
2296                         return_val = TD_NOTLS;
2297                 else if (ps_pdread(ph_p,
2298                     (psaddr_t)((TLS_modinfo32 *)
2299                     (uintptr_t)tls_metadata.tls_modinfo.tls_data + moduleid),
2300                     &tlsmod, sizeof (tlsmod)) != PS_OK)
2301                         return_val = TD_DBERR;
2302                 else if (tlsmod.tm_memsz == 0)
2303                         return_val = TD_NOTLS;
2304                 else if (tlsmod.tm_flags & TM_FLG_STATICTLS)
2305                         *base = (psaddr_t)ulwp - tlsmod.tm_stattlsoffset;
2306                 else if (ps_pdread(ph_p, (psaddr_t)&ulwp->ul_tls,
2307                     &tls, sizeof (tls)) != PS_OK)
2308                         return_val = TD_DBERR;
2309                 else if (moduleid >= tls.tls_size)
2310                         return_val = TD_TLSDEFER;
2311                 else if (ps_pdread(ph_p,
2312                     (psaddr_t)((tls32_t *)(uintptr_t)tls.tls_data + moduleid),
2313                     &tls, sizeof (tls)) != PS_OK)
2314                         return_val = TD_DBERR;
2315                 else if (tls.tls_size == 0)
2316                         return_val = TD_TLSDEFER;
2317                 else
2318                         *base = (psaddr_t)tls.tls_data;
2319 #else
2320                 return_val = TD_ERR;
2321 #endif  /* _SYSCALL32 */
2322         }
2323 
2324         (void) ps_pcontinue(ph_p);
2325         ph_unlock(ta_p);
2326         return (return_val);
2327 }
2328 
2329 /*
2330  * Change a thread's priority to the value specified by ti_pri.
2331  * Currently unused by dbx.
2332  */
2333 #pragma weak td_thr_setprio = __td_thr_setprio
2334 /* ARGSUSED */
2335 td_err_e
2336 __td_thr_setprio(td_thrhandle_t *th_p, int ti_pri)
2337 {
2338         return (TD_NOCAPAB);
2339 }
2340 
2341 /*
2342  * This structure links td_thr_lockowner and the lowner_cb callback function.
2343  */
2344 typedef struct {
2345         td_sync_iter_f  *owner_cb;
2346         void            *owner_cb_arg;
2347         td_thrhandle_t  *th_p;
2348 } lowner_cb_ctl_t;
2349 
2350 static int
2351 lowner_cb(const td_synchandle_t *sh_p, void *arg)
2352 {
2353         lowner_cb_ctl_t *ocb = arg;
2354         int trunc = 0;
2355         union {
2356                 rwlock_t rwl;
2357                 mutex_t mx;
2358         } rw_m;
2359 
2360         if (ps_pdread(sh_p->sh_ta_p->ph_p, sh_p->sh_unique,
2361             &rw_m, sizeof (rw_m)) != PS_OK) {
2362                 trunc = 1;
2363                 if (ps_pdread(sh_p->sh_ta_p->ph_p, sh_p->sh_unique,
2364                     &rw_m.mx, sizeof (rw_m.mx)) != PS_OK)
2365                         return (0);
2366         }
2367         if (rw_m.mx.mutex_magic == MUTEX_MAGIC &&
2368             rw_m.mx.mutex_owner == ocb->th_p->th_unique)
2369                 return ((ocb->owner_cb)(sh_p, ocb->owner_cb_arg));
2370         if (!trunc && rw_m.rwl.magic == RWL_MAGIC) {
2371                 mutex_t *rwlock = &rw_m.rwl.mutex;
2372                 if (rwlock->mutex_owner == ocb->th_p->th_unique)
2373                         return ((ocb->owner_cb)(sh_p, ocb->owner_cb_arg));
2374         }
2375         return (0);
2376 }
2377 
2378 /*
2379  * Iterate over the set of locks owned by a specified thread.
2380  * If cb returns a non-zero value, terminate iterations.
2381  */
2382 #pragma weak td_thr_lockowner = __td_thr_lockowner
2383 td_err_e
2384 __td_thr_lockowner(const td_thrhandle_t *th_p, td_sync_iter_f *cb,
2385         void *cb_data)
2386 {
2387         td_thragent_t   *ta_p;
2388         td_err_e        return_val;
2389         lowner_cb_ctl_t lcb;
2390 
2391         /*
2392          * Just sanity checks.
2393          */
2394         if (ph_lock_th((td_thrhandle_t *)th_p, &return_val) == NULL)
2395                 return (return_val);
2396         ta_p = th_p->th_ta_p;
2397         ph_unlock(ta_p);
2398 
2399         lcb.owner_cb = cb;
2400         lcb.owner_cb_arg = cb_data;
2401         lcb.th_p = (td_thrhandle_t *)th_p;
2402         return (__td_ta_sync_iter(ta_p, lowner_cb, &lcb));
2403 }
2404 
2405 /*
2406  * If a thread is asleep on a synchronization variable,
2407  * then get the synchronization handle.
2408  */
2409 #pragma weak td_thr_sleepinfo = __td_thr_sleepinfo
2410 td_err_e
2411 __td_thr_sleepinfo(const td_thrhandle_t *th_p, td_synchandle_t *sh_p)
2412 {
2413         struct ps_prochandle *ph_p;
2414         td_err_e        return_val = TD_OK;
2415         uintptr_t       wchan;
2416 
2417         if (sh_p == NULL)
2418                 return (TD_ERR);
2419         if ((ph_p = ph_lock_th((td_thrhandle_t *)th_p, &return_val)) == NULL)
2420                 return (return_val);
2421 
2422         /*
2423          * No need to stop the process for a simple read.
2424          */
2425         if (th_p->th_ta_p->model == PR_MODEL_NATIVE) {
2426                 ulwp_t *ulwp = (ulwp_t *)th_p->th_unique;
2427 
2428                 if (ps_pdread(ph_p, (psaddr_t)&ulwp->ul_wchan,
2429                     &wchan, sizeof (wchan)) != PS_OK)
2430                         return_val = TD_DBERR;
2431         } else {
2432 #if defined(_LP64) && defined(_SYSCALL32)
2433                 ulwp32_t *ulwp = (ulwp32_t *)th_p->th_unique;
2434                 caddr32_t wchan32;
2435 
2436                 if (ps_pdread(ph_p, (psaddr_t)&ulwp->ul_wchan,
2437                     &wchan32, sizeof (wchan32)) != PS_OK)
2438                         return_val = TD_DBERR;
2439                 wchan = wchan32;
2440 #else
2441                 return_val = TD_ERR;
2442 #endif  /* _SYSCALL32 */
2443         }
2444 
2445         if (return_val != TD_OK || wchan == NULL) {
2446                 sh_p->sh_ta_p = NULL;
2447                 sh_p->sh_unique = NULL;
2448                 if (return_val == TD_OK)
2449                         return_val = TD_ERR;
2450         } else {
2451                 sh_p->sh_ta_p = th_p->th_ta_p;
2452                 sh_p->sh_unique = (psaddr_t)wchan;
2453         }
2454 
2455         ph_unlock(th_p->th_ta_p);
2456         return (return_val);
2457 }
2458 
2459 /*
2460  * Which thread is running on an lwp?
2461  */
2462 #pragma weak td_ta_map_lwp2thr = __td_ta_map_lwp2thr
2463 td_err_e
2464 __td_ta_map_lwp2thr(td_thragent_t *ta_p, lwpid_t lwpid,
2465         td_thrhandle_t *th_p)
2466 {
2467         return (__td_ta_map_id2thr(ta_p, lwpid, th_p));
2468 }
2469 
2470 /*
2471  * Common code for td_sync_get_info() and td_sync_get_stats()
2472  */
2473 static td_err_e
2474 sync_get_info_common(const td_synchandle_t *sh_p, struct ps_prochandle *ph_p,
2475         td_syncinfo_t *si_p)
2476 {
2477         int trunc = 0;
2478         td_so_un_t generic_so;
2479 
2480         /*
2481          * Determine the sync. object type; a little type fudgery here.
2482          * First attempt to read the whole union.  If that fails, attempt
2483          * to read just the condvar.  A condvar is the smallest sync. object.
2484          */
2485         if (ps_pdread(ph_p, sh_p->sh_unique,
2486             &generic_so, sizeof (generic_so)) != PS_OK) {
2487                 trunc = 1;
2488                 if (ps_pdread(ph_p, sh_p->sh_unique, &generic_so.condition,
2489                     sizeof (generic_so.condition)) != PS_OK)
2490                         return (TD_DBERR);
2491         }
2492 
2493         switch (generic_so.condition.cond_magic) {
2494         case MUTEX_MAGIC:
2495                 if (trunc && ps_pdread(ph_p, sh_p->sh_unique,
2496                     &generic_so.lock, sizeof (generic_so.lock)) != PS_OK)
2497                         return (TD_DBERR);
2498                 si_p->si_type = TD_SYNC_MUTEX;
2499                 si_p->si_shared_type =
2500                     (generic_so.lock.mutex_type & USYNC_PROCESS);
2501                 (void) memcpy(si_p->si_flags, &generic_so.lock.mutex_flag,
2502                     sizeof (generic_so.lock.mutex_flag));
2503                 si_p->si_state.mutex_locked =
2504                     (generic_so.lock.mutex_lockw != 0);
2505                 si_p->si_size = sizeof (generic_so.lock);
2506                 si_p->si_has_waiters = generic_so.lock.mutex_waiters;
2507                 si_p->si_rcount = generic_so.lock.mutex_rcount;
2508                 si_p->si_prioceiling = generic_so.lock.mutex_ceiling;
2509                 if (si_p->si_state.mutex_locked) {
2510                         if (si_p->si_shared_type & USYNC_PROCESS)
2511                                 si_p->si_ownerpid =
2512                                     generic_so.lock.mutex_ownerpid;
2513                         si_p->si_owner.th_ta_p = sh_p->sh_ta_p;
2514                         si_p->si_owner.th_unique = generic_so.lock.mutex_owner;
2515                 }
2516                 break;
2517         case COND_MAGIC:
2518                 si_p->si_type = TD_SYNC_COND;
2519                 si_p->si_shared_type =
2520                     (generic_so.condition.cond_type & USYNC_PROCESS);
2521                 (void) memcpy(si_p->si_flags, generic_so.condition.flags.flag,
2522                     sizeof (generic_so.condition.flags.flag));
2523                 si_p->si_size = sizeof (generic_so.condition);
2524                 si_p->si_has_waiters =
2525                     (generic_so.condition.cond_waiters_user |
2526                     generic_so.condition.cond_waiters_kernel)? 1 : 0;
2527                 break;
2528         case SEMA_MAGIC:
2529                 if (trunc && ps_pdread(ph_p, sh_p->sh_unique,
2530                     &generic_so.semaphore, sizeof (generic_so.semaphore))
2531                     != PS_OK)
2532                         return (TD_DBERR);
2533                 si_p->si_type = TD_SYNC_SEMA;
2534                 si_p->si_shared_type =
2535                     (generic_so.semaphore.type & USYNC_PROCESS);
2536                 si_p->si_state.sem_count = generic_so.semaphore.count;
2537                 si_p->si_size = sizeof (generic_so.semaphore);
2538                 si_p->si_has_waiters =
2539                     ((lwp_sema_t *)&generic_so.semaphore)->flags[7];
2540                 /* this is useless but the old interface provided it */
2541                 si_p->si_data = (psaddr_t)generic_so.semaphore.count;
2542                 break;
2543         case RWL_MAGIC:
2544         {
2545                 uint32_t rwstate;
2546 
2547                 if (trunc && ps_pdread(ph_p, sh_p->sh_unique,
2548                     &generic_so.rwlock, sizeof (generic_so.rwlock)) != PS_OK)
2549                         return (TD_DBERR);
2550                 si_p->si_type = TD_SYNC_RWLOCK;
2551                 si_p->si_shared_type =
2552                     (generic_so.rwlock.rwlock_type & USYNC_PROCESS);
2553                 si_p->si_size = sizeof (generic_so.rwlock);
2554 
2555                 rwstate = (uint32_t)generic_so.rwlock.rwlock_readers;
2556                 if (rwstate & URW_WRITE_LOCKED) {
2557                         si_p->si_state.nreaders = -1;
2558                         si_p->si_is_wlock = 1;
2559                         si_p->si_owner.th_ta_p = sh_p->sh_ta_p;
2560                         si_p->si_owner.th_unique =
2561                             generic_so.rwlock.rwlock_owner;
2562                         if (si_p->si_shared_type & USYNC_PROCESS)
2563                                 si_p->si_ownerpid =
2564                                     generic_so.rwlock.rwlock_ownerpid;
2565                 } else {
2566                         si_p->si_state.nreaders = (rwstate & URW_READERS_MASK);
2567                 }
2568                 si_p->si_has_waiters = ((rwstate & URW_HAS_WAITERS) != 0);
2569 
2570                 /* this is useless but the old interface provided it */
2571                 si_p->si_data = (psaddr_t)generic_so.rwlock.readers;
2572                 break;
2573         }
2574         default:
2575                 return (TD_BADSH);
2576         }
2577 
2578         si_p->si_ta_p = sh_p->sh_ta_p;
2579         si_p->si_sv_addr = sh_p->sh_unique;
2580         return (TD_OK);
2581 }
2582 
2583 /*
2584  * Given a synchronization handle, fill in the
2585  * information for the synchronization variable into *si_p.
2586  */
2587 #pragma weak td_sync_get_info = __td_sync_get_info
2588 td_err_e
2589 __td_sync_get_info(const td_synchandle_t *sh_p, td_syncinfo_t *si_p)
2590 {
2591         struct ps_prochandle *ph_p;
2592         td_err_e return_val;
2593 
2594         if (si_p == NULL)
2595                 return (TD_ERR);
2596         (void) memset(si_p, 0, sizeof (*si_p));
2597         if ((ph_p = ph_lock_sh(sh_p, &return_val)) == NULL)
2598                 return (return_val);
2599         if (ps_pstop(ph_p) != PS_OK) {
2600                 ph_unlock(sh_p->sh_ta_p);
2601                 return (TD_DBERR);
2602         }
2603 
2604         return_val = sync_get_info_common(sh_p, ph_p, si_p);
2605 
2606         (void) ps_pcontinue(ph_p);
2607         ph_unlock(sh_p->sh_ta_p);
2608         return (return_val);
2609 }
2610 
2611 static uint_t
2612 tdb_addr_hash64(uint64_t addr)
2613 {
2614         uint64_t value60 = (addr >> 4);
2615         uint32_t value30 = (value60 >> 30) ^ (value60 & 0x3fffffff);
2616         return ((value30 >> 15) ^ (value30 & 0x7fff));
2617 }
2618 
2619 static uint_t
2620 tdb_addr_hash32(uint64_t addr)
2621 {
2622         uint32_t value30 = (addr >> 2);           /* 30 bits */
2623         return ((value30 >> 15) ^ (value30 & 0x7fff));
2624 }
2625 
2626 static td_err_e
2627 read_sync_stats(td_thragent_t *ta_p, psaddr_t hash_table,
2628         psaddr_t sync_obj_addr, tdb_sync_stats_t *sync_stats)
2629 {
2630         psaddr_t next_desc;
2631         uint64_t first;
2632         uint_t ix;
2633 
2634         /*
2635          * Compute the hash table index from the synch object's address.
2636          */
2637         if (ta_p->model == PR_MODEL_LP64)
2638                 ix = tdb_addr_hash64(sync_obj_addr);
2639         else
2640                 ix = tdb_addr_hash32(sync_obj_addr);
2641 
2642         /*
2643          * Get the address of the first element in the linked list.
2644          */
2645         if (ps_pdread(ta_p->ph_p, hash_table + ix * sizeof (uint64_t),
2646             &first, sizeof (first)) != PS_OK)
2647                 return (TD_DBERR);
2648 
2649         /*
2650          * Search the linked list for an entry for the synch object..
2651          */
2652         for (next_desc = (psaddr_t)first; next_desc != NULL;
2653             next_desc = (psaddr_t)sync_stats->next) {
2654                 if (ps_pdread(ta_p->ph_p, next_desc,
2655                     sync_stats, sizeof (*sync_stats)) != PS_OK)
2656                         return (TD_DBERR);
2657                 if (sync_stats->sync_addr == sync_obj_addr)
2658                         return (TD_OK);
2659         }
2660 
2661         (void) memset(sync_stats, 0, sizeof (*sync_stats));
2662         return (TD_OK);
2663 }
2664 
2665 /*
2666  * Given a synchronization handle, fill in the
2667  * statistics for the synchronization variable into *ss_p.
2668  */
2669 #pragma weak td_sync_get_stats = __td_sync_get_stats
2670 td_err_e
2671 __td_sync_get_stats(const td_synchandle_t *sh_p, td_syncstats_t *ss_p)
2672 {
2673         struct ps_prochandle *ph_p;
2674         td_thragent_t *ta_p;
2675         td_err_e return_val;
2676         register_sync_t enable;
2677         psaddr_t hashaddr;
2678         tdb_sync_stats_t sync_stats;
2679         size_t ix;
2680 
2681         if (ss_p == NULL)
2682                 return (TD_ERR);
2683         (void) memset(ss_p, 0, sizeof (*ss_p));
2684         if ((ph_p = ph_lock_sh(sh_p, &return_val)) == NULL)
2685                 return (return_val);
2686         ta_p = sh_p->sh_ta_p;
2687         if (ps_pstop(ph_p) != PS_OK) {
2688                 ph_unlock(ta_p);
2689                 return (TD_DBERR);
2690         }
2691 
2692         if ((return_val = sync_get_info_common(sh_p, ph_p, &ss_p->ss_info))
2693             != TD_OK) {
2694                 if (return_val != TD_BADSH)
2695                         goto out;
2696                 /* we can correct TD_BADSH */
2697                 (void) memset(&ss_p->ss_info, 0, sizeof (ss_p->ss_info));
2698                 ss_p->ss_info.si_ta_p = sh_p->sh_ta_p;
2699                 ss_p->ss_info.si_sv_addr = sh_p->sh_unique;
2700                 /* we correct si_type and si_size below */
2701                 return_val = TD_OK;
2702         }
2703         if (ps_pdread(ph_p, ta_p->tdb_register_sync_addr,
2704             &enable, sizeof (enable)) != PS_OK) {
2705                 return_val = TD_DBERR;
2706                 goto out;
2707         }
2708         if (enable != REGISTER_SYNC_ON)
2709                 goto out;
2710 
2711         /*
2712          * Get the address of the hash table in the target process.
2713          */
2714         if (ta_p->model == PR_MODEL_NATIVE) {
2715                 if (ps_pdread(ph_p, ta_p->uberdata_addr +
2716                     offsetof(uberdata_t, tdb.tdb_sync_addr_hash),
2717                     &hashaddr, sizeof (&hashaddr)) != PS_OK) {
2718                         return_val = TD_DBERR;
2719                         goto out;
2720                 }
2721         } else {
2722 #if defined(_LP64) && defined(_SYSCALL32)
2723                 caddr32_t addr;
2724 
2725                 if (ps_pdread(ph_p, ta_p->uberdata_addr +
2726                     offsetof(uberdata32_t, tdb.tdb_sync_addr_hash),
2727                     &addr, sizeof (addr)) != PS_OK) {
2728                         return_val = TD_DBERR;
2729                         goto out;
2730                 }
2731                 hashaddr = addr;
2732 #else
2733                 return_val = TD_ERR;
2734                 goto out;
2735 #endif  /* _SYSCALL32 */
2736         }
2737 
2738         if (hashaddr == 0)
2739                 return_val = TD_BADSH;
2740         else
2741                 return_val = read_sync_stats(ta_p, hashaddr,
2742                     sh_p->sh_unique, &sync_stats);
2743         if (return_val != TD_OK)
2744                 goto out;
2745 
2746         /*
2747          * We have the hash table entry.  Transfer the data to
2748          * the td_syncstats_t structure provided by the caller.
2749          */
2750         switch (sync_stats.un.type) {
2751         case TDB_MUTEX:
2752         {
2753                 td_mutex_stats_t *msp = &ss_p->ss_un.mutex;
2754 
2755                 ss_p->ss_info.si_type = TD_SYNC_MUTEX;
2756                 ss_p->ss_info.si_size = sizeof (mutex_t);
2757                 msp->mutex_lock =
2758                     sync_stats.un.mutex.mutex_lock;
2759                 msp->mutex_sleep =
2760                     sync_stats.un.mutex.mutex_sleep;
2761                 msp->mutex_sleep_time =
2762                     sync_stats.un.mutex.mutex_sleep_time;
2763                 msp->mutex_hold_time =
2764                     sync_stats.un.mutex.mutex_hold_time;
2765                 msp->mutex_try =
2766                     sync_stats.un.mutex.mutex_try;
2767                 msp->mutex_try_fail =
2768                     sync_stats.un.mutex.mutex_try_fail;
2769                 if (sync_stats.sync_addr >= ta_p->hash_table_addr &&
2770                     (ix = sync_stats.sync_addr - ta_p->hash_table_addr)
2771                     < ta_p->hash_size * sizeof (thr_hash_table_t))
2772                         msp->mutex_internal =
2773                             ix / sizeof (thr_hash_table_t) + 1;
2774                 break;
2775         }
2776         case TDB_COND:
2777         {
2778                 td_cond_stats_t *csp = &ss_p->ss_un.cond;
2779 
2780                 ss_p->ss_info.si_type = TD_SYNC_COND;
2781                 ss_p->ss_info.si_size = sizeof (cond_t);
2782                 csp->cond_wait =
2783                     sync_stats.un.cond.cond_wait;
2784                 csp->cond_timedwait =
2785                     sync_stats.un.cond.cond_timedwait;
2786                 csp->cond_wait_sleep_time =
2787                     sync_stats.un.cond.cond_wait_sleep_time;
2788                 csp->cond_timedwait_sleep_time =
2789                     sync_stats.un.cond.cond_timedwait_sleep_time;
2790                 csp->cond_timedwait_timeout =
2791                     sync_stats.un.cond.cond_timedwait_timeout;
2792                 csp->cond_signal =
2793                     sync_stats.un.cond.cond_signal;
2794                 csp->cond_broadcast =
2795                     sync_stats.un.cond.cond_broadcast;
2796                 if (sync_stats.sync_addr >= ta_p->hash_table_addr &&
2797                     (ix = sync_stats.sync_addr - ta_p->hash_table_addr)
2798                     < ta_p->hash_size * sizeof (thr_hash_table_t))
2799                         csp->cond_internal =
2800                             ix / sizeof (thr_hash_table_t) + 1;
2801                 break;
2802         }
2803         case TDB_RWLOCK:
2804         {
2805                 td_rwlock_stats_t *rwsp = &ss_p->ss_un.rwlock;
2806 
2807                 ss_p->ss_info.si_type = TD_SYNC_RWLOCK;
2808                 ss_p->ss_info.si_size = sizeof (rwlock_t);
2809                 rwsp->rw_rdlock =
2810                     sync_stats.un.rwlock.rw_rdlock;
2811                 rwsp->rw_rdlock_try =
2812                     sync_stats.un.rwlock.rw_rdlock_try;
2813                 rwsp->rw_rdlock_try_fail =
2814                     sync_stats.un.rwlock.rw_rdlock_try_fail;
2815                 rwsp->rw_wrlock =
2816                     sync_stats.un.rwlock.rw_wrlock;
2817                 rwsp->rw_wrlock_hold_time =
2818                     sync_stats.un.rwlock.rw_wrlock_hold_time;
2819                 rwsp->rw_wrlock_try =
2820                     sync_stats.un.rwlock.rw_wrlock_try;
2821                 rwsp->rw_wrlock_try_fail =
2822                     sync_stats.un.rwlock.rw_wrlock_try_fail;
2823                 break;
2824         }
2825         case TDB_SEMA:
2826         {
2827                 td_sema_stats_t *ssp = &ss_p->ss_un.sema;
2828 
2829                 ss_p->ss_info.si_type = TD_SYNC_SEMA;
2830                 ss_p->ss_info.si_size = sizeof (sema_t);
2831                 ssp->sema_wait =
2832                     sync_stats.un.sema.sema_wait;
2833                 ssp->sema_wait_sleep =
2834                     sync_stats.un.sema.sema_wait_sleep;
2835                 ssp->sema_wait_sleep_time =
2836                     sync_stats.un.sema.sema_wait_sleep_time;
2837                 ssp->sema_trywait =
2838                     sync_stats.un.sema.sema_trywait;
2839                 ssp->sema_trywait_fail =
2840                     sync_stats.un.sema.sema_trywait_fail;
2841                 ssp->sema_post =
2842                     sync_stats.un.sema.sema_post;
2843                 ssp->sema_max_count =
2844                     sync_stats.un.sema.sema_max_count;
2845                 ssp->sema_min_count =
2846                     sync_stats.un.sema.sema_min_count;
2847                 break;
2848         }
2849         default:
2850                 return_val = TD_BADSH;
2851                 break;
2852         }
2853 
2854 out:
2855         (void) ps_pcontinue(ph_p);
2856         ph_unlock(ta_p);
2857         return (return_val);
2858 }
2859 
2860 /*
2861  * Change the state of a synchronization variable.
2862  *      1) mutex lock state set to value
2863  *      2) semaphore's count set to value
2864  *      3) writer's lock set by value < 0
2865  *      4) reader's lock number of readers set to value >= 0
2866  * Currently unused by dbx.
2867  */
2868 #pragma weak td_sync_setstate = __td_sync_setstate
2869 td_err_e
2870 __td_sync_setstate(const td_synchandle_t *sh_p, long lvalue)
2871 {
2872         struct ps_prochandle *ph_p;
2873         int             trunc = 0;
2874         td_err_e        return_val;
2875         td_so_un_t      generic_so;
2876         uint32_t        *rwstate;
2877         int             value = (int)lvalue;
2878 
2879         if ((ph_p = ph_lock_sh(sh_p, &return_val)) == NULL)
2880                 return (return_val);
2881         if (ps_pstop(ph_p) != PS_OK) {
2882                 ph_unlock(sh_p->sh_ta_p);
2883                 return (TD_DBERR);
2884         }
2885 
2886         /*
2887          * Read the synch. variable information.
2888          * First attempt to read the whole union and if that fails
2889          * fall back to reading only the smallest member, the condvar.
2890          */
2891         if (ps_pdread(ph_p, sh_p->sh_unique, &generic_so,
2892             sizeof (generic_so)) != PS_OK) {
2893                 trunc = 1;
2894                 if (ps_pdread(ph_p, sh_p->sh_unique, &generic_so.condition,
2895                     sizeof (generic_so.condition)) != PS_OK) {
2896                         (void) ps_pcontinue(ph_p);
2897                         ph_unlock(sh_p->sh_ta_p);
2898                         return (TD_DBERR);
2899                 }
2900         }
2901 
2902         /*
2903          * Set the new value in the sync. variable, read the synch. variable
2904          * information. from the process, reset its value and write it back.
2905          */
2906         switch (generic_so.condition.mutex_magic) {
2907         case MUTEX_MAGIC:
2908                 if (trunc && ps_pdread(ph_p, sh_p->sh_unique,
2909                     &generic_so.lock, sizeof (generic_so.lock)) != PS_OK) {
2910                         return_val = TD_DBERR;
2911                         break;
2912                 }
2913                 generic_so.lock.mutex_lockw = (uint8_t)value;
2914                 if (ps_pdwrite(ph_p, sh_p->sh_unique, &generic_so.lock,
2915                     sizeof (generic_so.lock)) != PS_OK)
2916                         return_val = TD_DBERR;
2917                 break;
2918         case SEMA_MAGIC:
2919                 if (trunc && ps_pdread(ph_p, sh_p->sh_unique,
2920                     &generic_so.semaphore, sizeof (generic_so.semaphore))
2921                     != PS_OK) {
2922                         return_val = TD_DBERR;
2923                         break;
2924                 }
2925                 generic_so.semaphore.count = value;
2926                 if (ps_pdwrite(ph_p, sh_p->sh_unique, &generic_so.semaphore,
2927                     sizeof (generic_so.semaphore)) != PS_OK)
2928                         return_val = TD_DBERR;
2929                 break;
2930         case COND_MAGIC:
2931                 /* Operation not supported on a condition variable */
2932                 return_val = TD_ERR;
2933                 break;
2934         case RWL_MAGIC:
2935                 if (trunc && ps_pdread(ph_p, sh_p->sh_unique,
2936                     &generic_so.rwlock, sizeof (generic_so.rwlock)) != PS_OK) {
2937                         return_val = TD_DBERR;
2938                         break;
2939                 }
2940                 rwstate = (uint32_t *)&generic_so.rwlock.readers;
2941                 *rwstate &= URW_HAS_WAITERS;
2942                 if (value < 0)
2943                         *rwstate |= URW_WRITE_LOCKED;
2944                 else
2945                         *rwstate |= (value & URW_READERS_MASK);
2946                 if (ps_pdwrite(ph_p, sh_p->sh_unique, &generic_so.rwlock,
2947                     sizeof (generic_so.rwlock)) != PS_OK)
2948                         return_val = TD_DBERR;
2949                 break;
2950         default:
2951                 /* Bad sync. object type */
2952                 return_val = TD_BADSH;
2953                 break;
2954         }
2955 
2956         (void) ps_pcontinue(ph_p);
2957         ph_unlock(sh_p->sh_ta_p);
2958         return (return_val);
2959 }
2960 
2961 typedef struct {
2962         td_thr_iter_f   *waiter_cb;
2963         psaddr_t        sync_obj_addr;
2964         uint16_t        sync_magic;
2965         void            *waiter_cb_arg;
2966         td_err_e        errcode;
2967 } waiter_cb_ctl_t;
2968 
2969 static int
2970 waiters_cb(const td_thrhandle_t *th_p, void *arg)
2971 {
2972         td_thragent_t   *ta_p = th_p->th_ta_p;
2973         struct ps_prochandle *ph_p = ta_p->ph_p;
2974         waiter_cb_ctl_t *wcb = arg;
2975         caddr_t         wchan;
2976 
2977         if (ta_p->model == PR_MODEL_NATIVE) {
2978                 ulwp_t *ulwp = (ulwp_t *)th_p->th_unique;
2979 
2980                 if (ps_pdread(ph_p, (psaddr_t)&ulwp->ul_wchan,
2981                     &wchan, sizeof (wchan)) != PS_OK) {
2982                         wcb->errcode = TD_DBERR;
2983                         return (1);
2984                 }
2985         } else {
2986 #if defined(_LP64) && defined(_SYSCALL32)
2987                 ulwp32_t *ulwp = (ulwp32_t *)th_p->th_unique;
2988                 caddr32_t wchan32;
2989 
2990                 if (ps_pdread(ph_p, (psaddr_t)&ulwp->ul_wchan,
2991                     &wchan32, sizeof (wchan32)) != PS_OK) {
2992                         wcb->errcode = TD_DBERR;
2993                         return (1);
2994                 }
2995                 wchan = (caddr_t)(uintptr_t)wchan32;
2996 #else
2997                 wcb->errcode = TD_ERR;
2998                 return (1);
2999 #endif  /* _SYSCALL32 */
3000         }
3001 
3002         if (wchan == NULL)
3003                 return (0);
3004 
3005         if (wchan == (caddr_t)wcb->sync_obj_addr)
3006                 return ((*wcb->waiter_cb)(th_p, wcb->waiter_cb_arg));
3007 
3008         return (0);
3009 }
3010 
3011 /*
3012  * For a given synchronization variable, iterate over the
3013  * set of waiting threads.  The call back function is passed
3014  * two parameters, a pointer to a thread handle and a pointer
3015  * to extra call back data.
3016  */
3017 #pragma weak td_sync_waiters = __td_sync_waiters
3018 td_err_e
3019 __td_sync_waiters(const td_synchandle_t *sh_p, td_thr_iter_f *cb, void *cb_data)
3020 {
3021         struct ps_prochandle *ph_p;
3022         waiter_cb_ctl_t wcb;
3023         td_err_e        return_val;
3024 
3025         if ((ph_p = ph_lock_sh(sh_p, &return_val)) == NULL)
3026                 return (return_val);
3027         if (ps_pdread(ph_p,
3028             (psaddr_t)&((mutex_t *)sh_p->sh_unique)->mutex_magic,
3029             (caddr_t)&wcb.sync_magic, sizeof (wcb.sync_magic)) != PS_OK) {
3030                 ph_unlock(sh_p->sh_ta_p);
3031                 return (TD_DBERR);
3032         }
3033         ph_unlock(sh_p->sh_ta_p);
3034 
3035         switch (wcb.sync_magic) {
3036         case MUTEX_MAGIC:
3037         case COND_MAGIC:
3038         case SEMA_MAGIC:
3039         case RWL_MAGIC:
3040                 break;
3041         default:
3042                 return (TD_BADSH);
3043         }
3044 
3045         wcb.waiter_cb = cb;
3046         wcb.sync_obj_addr = sh_p->sh_unique;
3047         wcb.waiter_cb_arg = cb_data;
3048         wcb.errcode = TD_OK;
3049         return_val = __td_ta_thr_iter(sh_p->sh_ta_p, waiters_cb, &wcb,
3050             TD_THR_SLEEP, TD_THR_LOWEST_PRIORITY,
3051             TD_SIGNO_MASK, TD_THR_ANY_USER_FLAGS);
3052 
3053         if (return_val != TD_OK)
3054                 return (return_val);
3055 
3056         return (wcb.errcode);
3057 }