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