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