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