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