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