1 /* 2 * Copyright (c) 2004 David Xu <[email protected]> 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24 * SUCH DAMAGE. 25 */ 26 27 #include <sys/cdefs.h> 28 __FBSDID("$FreeBSD$"); 29 30 #include <stddef.h> 31 #include <stdlib.h> 32 #include <string.h> 33 #include <unistd.h> 34 #include <pthread.h> 35 #include <sys/types.h> 36 #include <sys/kse.h> 37 #include <sys/ptrace.h> 38 #include <proc_service.h> 39 #include <thread_db.h> 40 41 #include "libpthread.h" 42 #include "libpthread_db.h" 43 44 #define P2T(c) ps2td(c) 45 46 static void pt_unmap_lwp(const td_thragent_t *ta, lwpid_t lwp); 47 static int pt_validate(const td_thrhandle_t *th); 48 49 static int 50 ps2td(int c) 51 { 52 switch (c) { 53 case PS_OK: 54 return TD_OK; 55 case PS_ERR: 56 return TD_ERR; 57 case PS_BADPID: 58 return TD_BADPH; 59 case PS_BADLID: 60 return TD_NOLWP; 61 case PS_BADADDR: 62 return TD_ERR; 63 case PS_NOSYM: 64 return TD_NOLIBTHREAD; 65 case PS_NOFREGS: 66 return TD_NOFPREGS; 67 default: 68 return TD_ERR; 69 } 70 } 71 72 static long 73 pt_map_thread(const td_thragent_t *const_ta, psaddr_t pt, int type) 74 { 75 td_thragent_t *ta = __DECONST(td_thragent_t *, const_ta); 76 struct pt_map *new; 77 int i, first = -1; 78 79 /* leave zero out */ 80 for (i = 1; i < ta->map_len; ++i) { 81 if (ta->map[i].type == PT_NONE) { 82 if (first == -1) 83 first = i; 84 } else if (ta->map[i].type == type && ta->map[i].thr == pt) { 85 return (i); 86 } 87 } 88 89 if (first == -1) { 90 if (ta->map_len == 0) { 91 ta->map = calloc(20, sizeof(struct pt_map)); 92 if (ta->map == NULL) 93 return (-1); 94 ta->map_len = 20; 95 first = 1; 96 } else { 97 new = realloc(ta->map, 98 sizeof(struct pt_map) * ta->map_len * 2); 99 if (new == NULL) 100 return (-1); 101 memset(new + ta->map_len, '\0', sizeof(struct pt_map) * 102 ta->map_len); 103 first = ta->map_len; 104 ta->map = new; 105 ta->map_len *= 2; 106 } 107 } 108 109 ta->map[first].type = type; 110 ta->map[first].thr = pt; 111 return (first); 112 } 113 114 static td_err_e 115 pt_init(void) 116 { 117 pt_md_init(); 118 return (0); 119 } 120 121 static td_err_e 122 pt_ta_new(struct ps_prochandle *ph, td_thragent_t **pta) 123 { 124 #define LOOKUP_SYM(proc, sym, addr) \ 125 ret = ps_pglobal_lookup(proc, NULL, sym, addr); \ 126 if (ret != 0) { \ 127 TDBG("can not find symbol: %s\n", sym); \ 128 ret = TD_NOLIBTHREAD; \ 129 goto error; \ 130 } 131 132 td_thragent_t *ta; 133 int dbg; 134 int ret; 135 136 TDBG_FUNC(); 137 138 ta = malloc(sizeof(td_thragent_t)); 139 if (ta == NULL) 140 return (TD_MALLOC); 141 142 ta->ph = ph; 143 ta->thread_activated = 0; 144 ta->map = NULL; 145 ta->map_len = 0; 146 147 LOOKUP_SYM(ph, "_libkse_debug", &ta->libkse_debug_addr); 148 LOOKUP_SYM(ph, "_thread_list", &ta->thread_list_addr); 149 LOOKUP_SYM(ph, "_thread_activated", &ta->thread_activated_addr); 150 LOOKUP_SYM(ph, "_thread_active_threads",&ta->thread_active_threads_addr); 151 LOOKUP_SYM(ph, "_thread_keytable", &ta->thread_keytable_addr); 152 153 dbg = getpid(); 154 /* 155 * If this fails it probably means we're debugging a core file and 156 * can't write to it. 157 */ 158 ps_pwrite(ph, ta->libkse_debug_addr, &dbg, sizeof(int)); 159 *pta = ta; 160 return (0); 161 162 error: 163 free(ta); 164 return (ret); 165 } 166 167 static td_err_e 168 pt_ta_delete(td_thragent_t *ta) 169 { 170 int dbg; 171 172 TDBG_FUNC(); 173 174 dbg = 0; 175 /* 176 * Error returns from this write are not really a problem; 177 * the process doesn't exist any more. 178 */ 179 ps_pwrite(ta->ph, ta->libkse_debug_addr, &dbg, sizeof(int)); 180 if (ta->map) 181 free(ta->map); 182 free(ta); 183 return (TD_OK); 184 } 185 186 static td_err_e 187 pt_ta_map_id2thr(const td_thragent_t *ta, thread_t id, td_thrhandle_t *th) 188 { 189 prgregset_t gregs; 190 TAILQ_HEAD(, pthread) thread_list; 191 psaddr_t pt, tcb_addr; 192 lwpid_t lwp; 193 int ret; 194 195 TDBG_FUNC(); 196 197 if (id < 0 || id >= ta->map_len || ta->map[id].type == PT_NONE) 198 return (TD_NOTHR); 199 ret = ps_pread(ta->ph, ta->thread_list_addr, &thread_list, 200 sizeof(thread_list)); 201 if (ret != 0) 202 return (P2T(ret)); 203 pt = (psaddr_t)thread_list.tqh_first; 204 if (ta->map[id].type == PT_LWP) { 205 /* 206 * if we are referencing a lwp, make sure it was not already 207 * mapped to user thread. 208 */ 209 while (pt != 0) { 210 ret = ps_pread(ta->ph, 211 pt + offsetof(struct pthread, tcb), 212 &tcb_addr, sizeof(tcb_addr)); 213 if (ret != 0) 214 return (P2T(ret)); 215 ret = ps_pread(ta->ph, 216 tcb_addr + offsetof(struct tcb, 217 tcb_tmbx.tm_lwp), 218 &lwp, sizeof(lwp)); 219 if (ret != 0) 220 return (P2T(ret)); 221 /* 222 * If the lwp was already mapped to userland thread, 223 * we shouldn't reference it directly in future. 224 */ 225 if (lwp == ta->map[id].lwp) { 226 ta->map[id].type = PT_NONE; 227 return (TD_NOTHR); 228 } 229 /* get next thread */ 230 ret = ps_pread(ta->ph, 231 pt + offsetof(struct pthread, tle.tqe_next), 232 &pt, sizeof(pt)); 233 if (ret != 0) 234 return (P2T(ret)); 235 } 236 /* check lwp */ 237 ret = ptrace(PT_GETREGS, ta->map[id].lwp, (caddr_t)&gregs, 0); 238 if (ret != 0) { 239 /* no longer exists */ 240 ta->map[id].type = PT_NONE; 241 return (TD_NOTHR); 242 } 243 } else { 244 while (pt != 0 && ta->map[id].thr != pt) { 245 ret = ps_pread(ta->ph, 246 pt + offsetof(struct pthread, tcb), 247 &tcb_addr, sizeof(tcb_addr)); 248 if (ret != 0) 249 return (P2T(ret)); 250 /* get next thread */ 251 ret = ps_pread(ta->ph, 252 pt + offsetof(struct pthread, tle.tqe_next), 253 &pt, sizeof(pt)); 254 if (ret != 0) 255 return (P2T(ret)); 256 } 257 258 if (pt == 0) { 259 /* no longer exists */ 260 ta->map[id].type = PT_NONE; 261 return (TD_NOTHR); 262 } 263 } 264 th->th_ta = ta; 265 th->th_tid = id; 266 return (TD_OK); 267 } 268 269 static td_err_e 270 pt_ta_map_lwp2thr(const td_thragent_t *ta, lwpid_t lwp, td_thrhandle_t *th) 271 { 272 TAILQ_HEAD(, pthread) thread_list; 273 psaddr_t pt, ptr; 274 lwpid_t tmp_lwp; 275 int ret; 276 277 TDBG_FUNC(); 278 279 ret = ps_pread(ta->ph, ta->thread_list_addr, &thread_list, 280 sizeof(thread_list)); 281 if (ret != 0) 282 return (P2T(ret)); 283 pt = (psaddr_t)thread_list.tqh_first; 284 while (pt != 0) { 285 ret = ps_pread(ta->ph, pt + offsetof(struct pthread, tcb), 286 &ptr, sizeof(ptr)); 287 if (ret != 0) 288 return (P2T(ret)); 289 ptr += offsetof(struct tcb, tcb_tmbx.tm_lwp); 290 ret = ps_pread(ta->ph, ptr, &tmp_lwp, sizeof(lwpid_t)); 291 if (ret != 0) 292 return (P2T(ret)); 293 if (tmp_lwp == lwp) { 294 th->th_ta = ta; 295 th->th_tid = pt_map_thread(ta, pt, PT_USER); 296 if (th->th_tid == -1) 297 return (TD_MALLOC); 298 pt_unmap_lwp(ta, lwp); 299 return (TD_OK); 300 } 301 302 /* get next thread */ 303 ret = ps_pread(ta->ph, 304 pt + offsetof(struct pthread, tle.tqe_next), 305 &pt, sizeof(pt)); 306 if (ret != 0) 307 return (P2T(ret)); 308 } 309 310 return (TD_NOTHR); 311 } 312 313 static td_err_e 314 pt_ta_thr_iter(const td_thragent_t *ta, 315 td_thr_iter_f *callback, void *cbdata_p, 316 td_thr_state_e state, int ti_pri, 317 sigset_t *ti_sigmask_p, 318 unsigned int ti_user_flags) 319 { 320 TAILQ_HEAD(, pthread) thread_list; 321 td_thrhandle_t th; 322 psaddr_t pt; 323 ps_err_e pserr; 324 int activated; 325 326 TDBG_FUNC(); 327 328 pserr = ps_pread(ta->ph, ta->thread_activated_addr, &activated, 329 sizeof(int)); 330 if (pserr != PS_OK) 331 return (P2T(pserr)); 332 if (!activated) 333 return (TD_OK); 334 335 pserr = ps_pread(ta->ph, ta->thread_list_addr, &thread_list, 336 sizeof(thread_list)); 337 if (pserr != 0) 338 return (P2T(pserr)); 339 pt = (psaddr_t)thread_list.tqh_first; 340 while (pt != 0) { 341 th.th_ta = ta; 342 th.th_tid = pt_map_thread(ta, pt, PT_USER); 343 /* should we unmap lwp here ? */ 344 if (th.th_tid == -1) 345 return (TD_MALLOC); 346 if ((*callback)(&th, cbdata_p)) 347 return (TD_DBERR); 348 /* get next thread */ 349 pserr = ps_pread(ta->ph, 350 pt + offsetof(struct pthread, tle.tqe_next), &pt, 351 sizeof(pt)); 352 if (pserr != PS_OK) 353 return (P2T(pserr)); 354 } 355 return (TD_OK); 356 } 357 358 static td_err_e 359 pt_ta_tsd_iter(const td_thragent_t *ta, td_key_iter_f *ki, void *arg) 360 { 361 struct pthread_key keytable[PTHREAD_KEYS_MAX]; 362 int i, ret; 363 364 TDBG_FUNC(); 365 366 ret = ps_pread(ta->ph, (psaddr_t)ta->thread_keytable_addr, keytable, 367 sizeof(keytable)); 368 if (ret != 0) 369 return (P2T(ret)); 370 371 for (i = 0; i < PTHREAD_KEYS_MAX; i++) { 372 if (keytable[i].allocated) { 373 ret = (ki)(i, keytable[i].destructor, arg); 374 if (ret != 0) 375 return (TD_DBERR); 376 } 377 } 378 return (TD_OK); 379 } 380 381 static td_err_e 382 pt_ta_event_addr(const td_thragent_t *ta, td_event_e event, td_notify_t *ptr) 383 { 384 TDBG_FUNC(); 385 return (TD_NOEVENT); 386 } 387 388 static td_err_e 389 pt_ta_set_event(const td_thragent_t *ta, td_thr_events_t *events) 390 { 391 TDBG_FUNC(); 392 return (TD_ERR); 393 } 394 395 static td_err_e 396 pt_ta_clear_event(const td_thragent_t *ta, td_thr_events_t *events) 397 { 398 TDBG_FUNC(); 399 return (TD_ERR); 400 } 401 402 static td_err_e 403 pt_ta_event_getmsg(const td_thragent_t *ta, td_event_msg_t *msg) 404 { 405 TDBG_FUNC(); 406 return (TD_NOMSG); 407 } 408 409 static td_err_e 410 pt_dbsuspend(const td_thrhandle_t *th, int suspend) 411 { 412 td_thragent_t *ta = (td_thragent_t *)th->th_ta; 413 psaddr_t tcb_addr, tmbx_addr, ptr; 414 lwpid_t lwp; 415 uint32_t dflags; 416 int attrflags; 417 int ret; 418 419 TDBG_FUNC(); 420 421 ret = pt_validate(th); 422 if (ret) 423 return (ret); 424 425 if (ta->map[th->th_tid].type == PT_LWP) { 426 if (suspend) 427 ret = ps_lstop(ta->ph, ta->map[th->th_tid].lwp); 428 else 429 ret = ps_lcontinue(ta->ph, ta->map[th->th_tid].lwp); 430 return (P2T(ret)); 431 } 432 433 ret = ps_pread(ta->ph, ta->map[th->th_tid].thr + 434 offsetof(struct pthread, attr.flags), 435 &attrflags, sizeof(attrflags)); 436 if (ret != 0) 437 return (P2T(ret)); 438 ret = ps_pread(ta->ph, ta->map[th->th_tid].thr + 439 offsetof(struct pthread, tcb), 440 &tcb_addr, sizeof(tcb_addr)); 441 if (ret != 0) 442 return (P2T(ret)); 443 tmbx_addr = tcb_addr + offsetof(struct tcb, tcb_tmbx); 444 ptr = tmbx_addr + offsetof(struct kse_thr_mailbox, tm_lwp); 445 ret = ps_pread(ta->ph, ptr, &lwp, sizeof(lwpid_t)); 446 if (ret != 0) 447 return (P2T(ret)); 448 /* 449 * Don't stop lwp assigned to a M:N thread, it belongs 450 * to UTS, UTS shouldn't be stopped. 451 */ 452 if (lwp != 0 && (attrflags & PTHREAD_SCOPE_SYSTEM)) { 453 /* dont' suspend signal thread */ 454 if (attrflags & THR_SIGNAL_THREAD) 455 return 0; 456 ptr = ta->map[th->th_tid].thr + 457 offsetof(struct pthread, kse); 458 /* Too many indirect level :-( */ 459 /* read struct kse * */ 460 ret = ps_pread(ta->ph, ptr, &ptr, sizeof(ptr)); 461 if (ret != 0) 462 return (P2T(ret)); 463 ptr = ptr + offsetof(struct kse, k_kcb); 464 /* read k_kcb * */ 465 ret = ps_pread(ta->ph, ptr, &ptr, sizeof(ptr)); 466 if (ret != 0) 467 return (P2T(ret)); 468 /* read kcb.kcb_kmbx.km_curthread */ 469 ptr = ptr + offsetof(struct kcb, kcb_kmbx.km_curthread); 470 ret = ps_pread(ta->ph, ptr, &ptr, sizeof(ptr)); 471 if (ret != 0) 472 return (P2T(ret)); 473 if (ptr != 0) { /* not in critical */ 474 if (suspend) 475 ret = ps_lstop(ta->ph, lwp); 476 else 477 ret = ps_lcontinue(ta->ph, lwp); 478 if (ret != 0) 479 return (P2T(ret)); 480 } 481 /* FALLTHROUGH */ 482 } 483 /* read tm_dflags */ 484 ret = ps_pread(ta->ph, 485 tmbx_addr + offsetof(struct kse_thr_mailbox, tm_dflags), 486 &dflags, sizeof(dflags)); 487 if (ret != 0) 488 return (P2T(ret)); 489 if (suspend) 490 dflags |= TMDF_DONOTRUNUSER; 491 else 492 dflags &= ~TMDF_DONOTRUNUSER; 493 ret = ps_pwrite(ta->ph, 494 tmbx_addr + offsetof(struct kse_thr_mailbox, tm_dflags), 495 &dflags, sizeof(dflags)); 496 return (P2T(ret)); 497 } 498 499 static td_err_e 500 pt_thr_dbresume(const td_thrhandle_t *th) 501 { 502 TDBG_FUNC(); 503 504 return pt_dbsuspend(th, 0); 505 } 506 507 static td_err_e 508 pt_thr_dbsuspend(const td_thrhandle_t *th) 509 { 510 TDBG_FUNC(); 511 512 return pt_dbsuspend(th, 1); 513 } 514 515 static td_err_e 516 pt_thr_validate(const td_thrhandle_t *th) 517 { 518 td_thrhandle_t temp; 519 int ret; 520 521 TDBG_FUNC(); 522 523 ret = pt_ta_map_id2thr(th->th_ta, th->th_tid, 524 &temp); 525 return (ret); 526 } 527 528 static td_err_e 529 pt_thr_get_info(const td_thrhandle_t *th, td_thrinfo_t *info) 530 { 531 const td_thragent_t *ta = th->th_ta; 532 struct pthread pt; 533 int ret; 534 uint32_t dflags; 535 536 TDBG_FUNC(); 537 538 ret = pt_validate(th); 539 if (ret) 540 return (ret); 541 542 memset(info, 0, sizeof(*info)); 543 if (ta->map[th->th_tid].type == PT_LWP) { 544 info->ti_type = TD_THR_SYSTEM; 545 info->ti_lid = ta->map[th->th_tid].lwp; 546 info->ti_tid = th->th_tid; 547 info->ti_state = TD_THR_RUN; 548 info->ti_type = TD_THR_SYSTEM; 549 return (TD_OK); 550 } 551 552 ret = ps_pread(ta->ph, (psaddr_t)(ta->map[th->th_tid].thr), 553 &pt, sizeof(pt)); 554 if (ret != 0) 555 return (P2T(ret)); 556 if (pt.magic != THR_MAGIC) 557 return (TD_BADTH); 558 ret = ps_pread(ta->ph, 559 ((psaddr_t)pt.tcb) + offsetof(struct tcb, tcb_tmbx.tm_lwp), 560 &info->ti_lid, sizeof(lwpid_t)); 561 if (ret != 0) 562 return (P2T(ret)); 563 ret = ps_pread(ta->ph, 564 ((psaddr_t)pt.tcb) + offsetof(struct tcb, tcb_tmbx.tm_dflags), 565 &dflags, sizeof(dflags)); 566 if (ret != 0) 567 return (P2T(ret)); 568 info->ti_ta_p = th->th_ta; 569 info->ti_tid = th->th_tid; 570 info->ti_tls = (char *)pt.specific; 571 info->ti_startfunc = (psaddr_t)pt.start_routine; 572 info->ti_stkbase = (psaddr_t) pt.attr.stackaddr_attr; 573 info->ti_stksize = pt.attr.stacksize_attr; 574 switch (pt.state) { 575 case PS_RUNNING: 576 info->ti_state = TD_THR_RUN; 577 break; 578 case PS_LOCKWAIT: 579 case PS_MUTEX_WAIT: 580 case PS_COND_WAIT: 581 case PS_SIGSUSPEND: 582 case PS_SIGWAIT: 583 case PS_JOIN: 584 case PS_SUSPENDED: 585 case PS_DEADLOCK: 586 case PS_SLEEP_WAIT: 587 info->ti_state = TD_THR_SLEEP; 588 break; 589 case PS_DEAD: 590 info->ti_state = TD_THR_ZOMBIE; 591 break; 592 default: 593 info->ti_state = TD_THR_UNKNOWN; 594 break; 595 } 596 597 info->ti_db_suspended = ((dflags & TMDF_DONOTRUNUSER) != 0); 598 info->ti_type = TD_THR_USER; 599 info->ti_pri = pt.active_priority; 600 info->ti_sigmask = pt.sigmask; 601 info->ti_traceme = 0; 602 info->ti_pending = pt.sigpend; 603 info->ti_events = 0; 604 return (0); 605 } 606 607 static td_err_e 608 pt_thr_getfpregs(const td_thrhandle_t *th, prfpregset_t *fpregs) 609 { 610 const td_thragent_t *ta = th->th_ta; 611 struct kse_thr_mailbox tmbx; 612 psaddr_t tcb_addr, tmbx_addr, ptr; 613 lwpid_t lwp; 614 int ret; 615 616 TDBG_FUNC(); 617 618 ret = pt_validate(th); 619 if (ret) 620 return (ret); 621 622 if (ta->map[th->th_tid].type == PT_LWP) { 623 ret = ps_lgetfpregs(ta->ph, ta->map[th->th_tid].lwp, fpregs); 624 return (P2T(ret)); 625 } 626 627 ret = ps_pread(ta->ph, ta->map[th->th_tid].thr + 628 offsetof(struct pthread, tcb), 629 &tcb_addr, sizeof(tcb_addr)); 630 if (ret != 0) 631 return (P2T(ret)); 632 tmbx_addr = tcb_addr + offsetof(struct tcb, tcb_tmbx); 633 ptr = tmbx_addr + offsetof(struct kse_thr_mailbox, tm_lwp); 634 ret = ps_pread(ta->ph, ptr, &lwp, sizeof(lwpid_t)); 635 if (ret != 0) 636 return (P2T(ret)); 637 if (lwp != 0) { 638 ret = ps_lgetfpregs(ta->ph, lwp, fpregs); 639 return (P2T(ret)); 640 } 641 642 ret = ps_pread(ta->ph, tmbx_addr, &tmbx, sizeof(tmbx)); 643 if (ret != 0) 644 return (P2T(ret)); 645 pt_ucontext_to_fpreg(&tmbx.tm_context, fpregs); 646 return (0); 647 } 648 649 static td_err_e 650 pt_thr_getgregs(const td_thrhandle_t *th, prgregset_t gregs) 651 { 652 const td_thragent_t *ta = th->th_ta; 653 struct kse_thr_mailbox tmbx; 654 psaddr_t tcb_addr, tmbx_addr, ptr; 655 lwpid_t lwp; 656 int ret; 657 658 TDBG_FUNC(); 659 660 ret = pt_validate(th); 661 if (ret) 662 return (ret); 663 664 if (ta->map[th->th_tid].type == PT_LWP) { 665 ret = ps_lgetregs(ta->ph, 666 ta->map[th->th_tid].lwp, gregs); 667 return (P2T(ret)); 668 } 669 670 ret = ps_pread(ta->ph, ta->map[th->th_tid].thr + 671 offsetof(struct pthread, tcb), 672 &tcb_addr, sizeof(tcb_addr)); 673 if (ret != 0) 674 return (P2T(ret)); 675 tmbx_addr = tcb_addr + offsetof(struct tcb, tcb_tmbx); 676 ptr = tmbx_addr + offsetof(struct kse_thr_mailbox, tm_lwp); 677 ret = ps_pread(ta->ph, ptr, &lwp, sizeof(lwpid_t)); 678 if (ret != 0) 679 return (P2T(ret)); 680 if (lwp != 0) { 681 ret = ps_lgetregs(ta->ph, lwp, gregs); 682 return (P2T(ret)); 683 } 684 ret = ps_pread(ta->ph, tmbx_addr, &tmbx, sizeof(tmbx)); 685 if (ret != 0) 686 return (P2T(ret)); 687 pt_ucontext_to_reg(&tmbx.tm_context, gregs); 688 return (0); 689 } 690 691 static td_err_e 692 pt_thr_setfpregs(const td_thrhandle_t *th, const prfpregset_t *fpregs) 693 { 694 const td_thragent_t *ta = th->th_ta; 695 struct kse_thr_mailbox tmbx; 696 psaddr_t tcb_addr, tmbx_addr, ptr; 697 lwpid_t lwp; 698 int ret; 699 700 TDBG_FUNC(); 701 702 ret = pt_validate(th); 703 if (ret) 704 return (ret); 705 706 if (ta->map[th->th_tid].type == PT_LWP) { 707 ret = ps_lsetfpregs(ta->ph, ta->map[th->th_tid].lwp, fpregs); 708 return (P2T(ret)); 709 } 710 711 ret = ps_pread(ta->ph, ta->map[th->th_tid].thr + 712 offsetof(struct pthread, tcb), 713 &tcb_addr, sizeof(tcb_addr)); 714 if (ret != 0) 715 return (P2T(ret)); 716 tmbx_addr = tcb_addr + offsetof(struct tcb, tcb_tmbx); 717 ptr = tmbx_addr + offsetof(struct kse_thr_mailbox, tm_lwp); 718 ret = ps_pread(ta->ph, ptr, &lwp, sizeof(lwpid_t)); 719 if (ret != 0) 720 return (P2T(ret)); 721 if (lwp != 0) { 722 ret = ps_lsetfpregs(ta->ph, lwp, fpregs); 723 return (P2T(ret)); 724 } 725 /* 726 * Read a copy of context, this makes sure that registers 727 * not covered by structure reg won't be clobbered 728 */ 729 ret = ps_pread(ta->ph, tmbx_addr, &tmbx, sizeof(tmbx)); 730 if (ret != 0) 731 return (P2T(ret)); 732 733 pt_fpreg_to_ucontext(fpregs, &tmbx.tm_context); 734 ret = ps_pwrite(ta->ph, tmbx_addr, &tmbx, sizeof(tmbx)); 735 return (P2T(ret)); 736 } 737 738 static td_err_e 739 pt_thr_setgregs(const td_thrhandle_t *th, const prgregset_t gregs) 740 { 741 const td_thragent_t *ta = th->th_ta; 742 struct kse_thr_mailbox tmbx; 743 psaddr_t tcb_addr, tmbx_addr, ptr; 744 lwpid_t lwp; 745 int ret; 746 747 TDBG_FUNC(); 748 749 ret = pt_validate(th); 750 if (ret) 751 return (ret); 752 753 if (ta->map[th->th_tid].type == PT_LWP) { 754 ret = ps_lsetregs(ta->ph, ta->map[th->th_tid].lwp, gregs); 755 return (P2T(ret)); 756 } 757 758 ret = ps_pread(ta->ph, ta->map[th->th_tid].thr + 759 offsetof(struct pthread, tcb), 760 &tcb_addr, sizeof(tcb_addr)); 761 if (ret != 0) 762 return (P2T(ret)); 763 tmbx_addr = tcb_addr + offsetof(struct tcb, tcb_tmbx); 764 ptr = tmbx_addr + offsetof(struct kse_thr_mailbox, tm_lwp); 765 ret = ps_pread(ta->ph, ptr, &lwp, sizeof(lwpid_t)); 766 if (ret != 0) 767 return (P2T(ret)); 768 if (lwp != 0) { 769 ret = ps_lsetregs(ta->ph, lwp, gregs); 770 return (P2T(ret)); 771 } 772 773 /* 774 * Read a copy of context, make sure that registers 775 * not covered by structure reg won't be clobbered 776 */ 777 ret = ps_pread(ta->ph, tmbx_addr, &tmbx, sizeof(tmbx)); 778 if (ret != 0) 779 return (P2T(ret)); 780 pt_reg_to_ucontext(gregs, &tmbx.tm_context); 781 ret = ps_pwrite(ta->ph, tmbx_addr, &tmbx, sizeof(tmbx)); 782 return (P2T(ret)); 783 } 784 785 static td_err_e 786 pt_thr_event_enable(const td_thrhandle_t *th, int en) 787 { 788 TDBG_FUNC(); 789 return (TD_ERR); 790 } 791 792 static td_err_e 793 pt_thr_set_event(const td_thrhandle_t *th, td_thr_events_t *setp) 794 { 795 TDBG_FUNC(); 796 return (TD_ERR); 797 } 798 799 static td_err_e 800 pt_thr_clear_event(const td_thrhandle_t *th, td_thr_events_t *setp) 801 { 802 TDBG_FUNC(); 803 return (TD_ERR); 804 } 805 806 static td_err_e 807 pt_thr_event_getmsg(const td_thrhandle_t *th, td_event_msg_t *msg) 808 { 809 TDBG_FUNC(); 810 return (TD_NOMSG); 811 } 812 813 static td_err_e 814 pt_thr_sstep(const td_thrhandle_t *th, int step) 815 { 816 const td_thragent_t *ta = th->th_ta; 817 struct kse_thr_mailbox tmbx; 818 struct reg regs; 819 psaddr_t tcb_addr, tmbx_addr; 820 uint32_t dflags; 821 lwpid_t lwp; 822 int ret; 823 824 TDBG_FUNC(); 825 826 ret = pt_validate(th); 827 if (ret) 828 return (ret); 829 830 if (ta->map[th->th_tid].type == PT_LWP) 831 return (TD_BADTH); 832 833 ret = ps_pread(ta->ph, ta->map[th->th_tid].thr + 834 offsetof(struct pthread, tcb), 835 &tcb_addr, sizeof(tcb_addr)); 836 if (ret != 0) 837 return (P2T(ret)); 838 839 /* Clear or set single step flag in thread mailbox */ 840 ret = ps_pread(ta->ph, tcb_addr + offsetof(struct tcb, 841 tcb_tmbx.tm_dflags), &dflags, sizeof(uint32_t)); 842 if (ret != 0) 843 return (P2T(ret)); 844 if (step != 0) 845 dflags |= TMDF_SSTEP; 846 else 847 dflags &= ~TMDF_SSTEP; 848 ret = ps_pwrite(ta->ph, tcb_addr + offsetof(struct tcb, 849 tcb_tmbx.tm_dflags), &dflags, sizeof(uint32_t)); 850 if (ret != 0) 851 return (P2T(ret)); 852 /* Get lwp */ 853 ret = ps_pread(ta->ph, tcb_addr + offsetof(struct tcb, 854 tcb_tmbx.tm_lwp), &lwp, sizeof(lwpid_t)); 855 if (ret != 0) 856 return (P2T(ret)); 857 if (lwp != 0) 858 return (0); 859 860 tmbx_addr = tcb_addr + offsetof(struct tcb, tcb_tmbx); 861 /* 862 * context is in userland, some architectures store 863 * single step status in registers, we should change 864 * these registers. 865 */ 866 ret = ps_pread(ta->ph, tmbx_addr, &tmbx, sizeof(tmbx)); 867 if (ret == 0) { 868 pt_ucontext_to_reg(&tmbx.tm_context, ®s); 869 /* only write out if it is really changed. */ 870 if (pt_reg_sstep(®s, step) != 0) { 871 pt_reg_to_ucontext(®s, &tmbx.tm_context); 872 ret = ps_pwrite(ta->ph, tmbx_addr, &tmbx, 873 sizeof(tmbx)); 874 } 875 } 876 return (P2T(ret)); 877 } 878 879 static void 880 pt_unmap_lwp(const td_thragent_t *ta, lwpid_t lwp) 881 { 882 int i; 883 884 for (i = 0; i < ta->map_len; ++i) { 885 if (ta->map[i].type == PT_LWP && ta->map[i].lwp == lwp) { 886 ta->map[i].type = PT_NONE; 887 return; 888 } 889 } 890 } 891 892 static int 893 pt_validate(const td_thrhandle_t *th) 894 { 895 896 if (th->th_tid < 0 || th->th_tid >= th->th_ta->map_len || 897 th->th_ta->map[th->th_tid].type == PT_NONE) 898 return (TD_NOTHR); 899 return (TD_OK); 900 } 901 902 struct ta_ops libpthread_db_ops = { 903 .to_init = pt_init, 904 .to_ta_clear_event = pt_ta_clear_event, 905 .to_ta_delete = pt_ta_delete, 906 .to_ta_event_addr = pt_ta_event_addr, 907 .to_ta_event_getmsg = pt_ta_event_getmsg, 908 .to_ta_map_id2thr = pt_ta_map_id2thr, 909 .to_ta_map_lwp2thr = pt_ta_map_lwp2thr, 910 .to_ta_new = pt_ta_new, 911 .to_ta_set_event = pt_ta_set_event, 912 .to_ta_thr_iter = pt_ta_thr_iter, 913 .to_ta_tsd_iter = pt_ta_tsd_iter, 914 .to_thr_clear_event = pt_thr_clear_event, 915 .to_thr_dbresume = pt_thr_dbresume, 916 .to_thr_dbsuspend = pt_thr_dbsuspend, 917 .to_thr_event_enable = pt_thr_event_enable, 918 .to_thr_event_getmsg = pt_thr_event_getmsg, 919 .to_thr_get_info = pt_thr_get_info, 920 .to_thr_getfpregs = pt_thr_getfpregs, 921 .to_thr_getgregs = pt_thr_getgregs, 922 .to_thr_set_event = pt_thr_set_event, 923 .to_thr_setfpregs = pt_thr_setfpregs, 924 .to_thr_setgregs = pt_thr_setgregs, 925 .to_thr_validate = pt_thr_validate, 926 927 /* FreeBSD specific extensions. */ 928 .to_thr_sstep = pt_thr_sstep, 929 }; 930