1 /* 2 * Copyright (c) 2004 David Xu <davidxu@freebsd.org> 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_thr_dbresume(const td_thrhandle_t *th) 411 { 412 TDBG_FUNC(); 413 return (TD_ERR); 414 } 415 416 static td_err_e 417 pt_thr_dbsuspend(const td_thrhandle_t *th) 418 { 419 TDBG_FUNC(); 420 return (TD_ERR); 421 } 422 423 static td_err_e 424 pt_thr_validate(const td_thrhandle_t *th) 425 { 426 td_thrhandle_t temp; 427 int ret; 428 429 TDBG_FUNC(); 430 431 ret = pt_ta_map_id2thr(th->th_ta, th->th_tid, 432 &temp); 433 return (P2T(ret)); 434 } 435 436 static td_err_e 437 pt_thr_get_info(const td_thrhandle_t *th, td_thrinfo_t *info) 438 { 439 const td_thragent_t *ta = th->th_ta; 440 struct pthread pt; 441 int ret; 442 443 TDBG_FUNC(); 444 445 ret = pt_validate(th); 446 if (ret) 447 return (ret); 448 449 memset(info, 0, sizeof(*info)); 450 if (ta->map[th->th_tid].type == PT_LWP) { 451 info->ti_type = TD_THR_SYSTEM; 452 info->ti_lid = ta->map[th->th_tid].lwp; 453 info->ti_tid = th->th_tid; 454 info->ti_state = TD_THR_RUN; 455 info->ti_type = TD_THR_SYSTEM; 456 return (TD_OK); 457 } 458 459 ret = ps_pread(ta->ph, (psaddr_t)(ta->map[th->th_tid].thr), 460 &pt, sizeof(pt)); 461 if (ret != 0) 462 return (P2T(ret)); 463 if (pt.magic != THR_MAGIC) 464 return (TD_BADTH); 465 ret = ps_pread(ta->ph, 466 ((psaddr_t)pt.tcb) + offsetof(struct tcb, tcb_tmbx.tm_lwp), 467 &info->ti_lid, sizeof(lwpid_t)); 468 if (ret != 0) 469 return (P2T(ret)); 470 471 info->ti_ta_p = th->th_ta; 472 info->ti_tid = th->th_tid; 473 info->ti_tls = (char *)pt.specific; 474 info->ti_startfunc = (psaddr_t)pt.start_routine; 475 info->ti_stkbase = (psaddr_t) pt.attr.stackaddr_attr; 476 info->ti_stksize = pt.attr.stacksize_attr; 477 switch (pt.state) { 478 case PS_RUNNING: 479 info->ti_state = TD_THR_RUN; 480 break; 481 case PS_LOCKWAIT: 482 case PS_MUTEX_WAIT: 483 case PS_COND_WAIT: 484 case PS_SIGSUSPEND: 485 case PS_SIGWAIT: 486 case PS_JOIN: 487 case PS_SUSPENDED: 488 case PS_DEADLOCK: 489 case PS_SLEEP_WAIT: 490 info->ti_state = TD_THR_SLEEP; 491 break; 492 case PS_DEAD: 493 info->ti_state = TD_THR_ZOMBIE; 494 break; 495 default: 496 info->ti_state = TD_THR_UNKNOWN; 497 break; 498 } 499 500 info->ti_db_suspended = 0; 501 info->ti_type = TD_THR_USER; 502 info->ti_pri = pt.active_priority; 503 info->ti_sigmask = pt.sigmask; 504 info->ti_traceme = 0; 505 info->ti_pending = pt.sigpend; 506 info->ti_events = 0; 507 return (0); 508 } 509 510 static td_err_e 511 pt_thr_getfpregs(const td_thrhandle_t *th, prfpregset_t *fpregs) 512 { 513 const td_thragent_t *ta = th->th_ta; 514 struct kse_thr_mailbox tmbx; 515 psaddr_t tcb_addr, tmbx_addr, ptr; 516 lwpid_t lwp; 517 int ret; 518 519 TDBG_FUNC(); 520 521 ret = pt_validate(th); 522 if (ret) 523 return (ret); 524 525 if (ta->map[th->th_tid].type == PT_LWP) { 526 ret = ps_lgetfpregs(ta->ph, ta->map[th->th_tid].lwp, fpregs); 527 return (P2T(ret)); 528 } 529 530 ret = ps_pread(ta->ph, ta->map[th->th_tid].thr + 531 offsetof(struct pthread, tcb), 532 &tcb_addr, sizeof(tcb_addr)); 533 if (ret != 0) 534 return (P2T(ret)); 535 tmbx_addr = tcb_addr + offsetof(struct tcb, tcb_tmbx); 536 ptr = tmbx_addr + offsetof(struct kse_thr_mailbox, tm_lwp); 537 ret = ps_pread(ta->ph, ptr, &lwp, sizeof(lwpid_t)); 538 if (ret != 0) 539 return (P2T(ret)); 540 if (lwp != 0) { 541 ret = ps_lgetfpregs(ta->ph, lwp, fpregs); 542 return (P2T(ret)); 543 } 544 545 ret = ps_pread(ta->ph, tmbx_addr, &tmbx, sizeof(tmbx)); 546 if (ret != 0) 547 return (P2T(ret)); 548 pt_ucontext_to_fpreg(&tmbx.tm_context, fpregs); 549 return (0); 550 } 551 552 static td_err_e 553 pt_thr_getgregs(const td_thrhandle_t *th, prgregset_t gregs) 554 { 555 const td_thragent_t *ta = th->th_ta; 556 struct kse_thr_mailbox tmbx; 557 psaddr_t tcb_addr, tmbx_addr, ptr; 558 lwpid_t lwp; 559 int ret; 560 561 TDBG_FUNC(); 562 563 ret = pt_validate(th); 564 if (ret) 565 return (ret); 566 567 if (ta->map[th->th_tid].type == PT_LWP) { 568 ret = ps_lgetregs(ta->ph, 569 ta->map[th->th_tid].lwp, gregs); 570 return (P2T(ret)); 571 } 572 573 ret = ps_pread(ta->ph, ta->map[th->th_tid].thr + 574 offsetof(struct pthread, tcb), 575 &tcb_addr, sizeof(tcb_addr)); 576 if (ret != 0) 577 return (P2T(ret)); 578 tmbx_addr = tcb_addr + offsetof(struct tcb, tcb_tmbx); 579 ptr = tmbx_addr + offsetof(struct kse_thr_mailbox, tm_lwp); 580 ret = ps_pread(ta->ph, ptr, &lwp, sizeof(lwpid_t)); 581 if (ret != 0) 582 return (P2T(ret)); 583 if (lwp != 0) { 584 ret = ps_lgetregs(ta->ph, lwp, gregs); 585 return (P2T(ret)); 586 } 587 ret = ps_pread(ta->ph, tmbx_addr, &tmbx, sizeof(tmbx)); 588 if (ret != 0) 589 return (P2T(ret)); 590 pt_ucontext_to_reg(&tmbx.tm_context, gregs); 591 return (0); 592 } 593 594 static td_err_e 595 pt_thr_setfpregs(const td_thrhandle_t *th, const prfpregset_t *fpregs) 596 { 597 const td_thragent_t *ta = th->th_ta; 598 struct kse_thr_mailbox tmbx; 599 psaddr_t tcb_addr, tmbx_addr, ptr; 600 lwpid_t lwp; 601 int ret; 602 603 TDBG_FUNC(); 604 605 ret = pt_validate(th); 606 if (ret) 607 return (ret); 608 609 if (ta->map[th->th_tid].type == PT_LWP) { 610 ret = ps_lsetfpregs(ta->ph, ta->map[th->th_tid].lwp, fpregs); 611 return (P2T(ret)); 612 } 613 614 ret = ps_pread(ta->ph, ta->map[th->th_tid].thr + 615 offsetof(struct pthread, tcb), 616 &tcb_addr, sizeof(tcb_addr)); 617 if (ret != 0) 618 return (P2T(ret)); 619 tmbx_addr = tcb_addr + offsetof(struct tcb, tcb_tmbx); 620 ptr = tmbx_addr + offsetof(struct kse_thr_mailbox, tm_lwp); 621 ret = ps_pread(ta->ph, ptr, &lwp, sizeof(lwpid_t)); 622 if (ret != 0) 623 return (P2T(ret)); 624 if (lwp != 0) { 625 ret = ps_lsetfpregs(ta->ph, lwp, fpregs); 626 return (P2T(ret)); 627 } 628 /* 629 * Read a copy of context, this makes sure that registers 630 * not covered by structure reg won't be clobbered 631 */ 632 ret = ps_pread(ta->ph, tmbx_addr, &tmbx, sizeof(tmbx)); 633 if (ret != 0) 634 return (P2T(ret)); 635 636 pt_fpreg_to_ucontext(fpregs, &tmbx.tm_context); 637 ret = ps_pwrite(ta->ph, tmbx_addr, &tmbx, sizeof(tmbx)); 638 return (P2T(ret)); 639 } 640 641 static td_err_e 642 pt_thr_setgregs(const td_thrhandle_t *th, const prgregset_t gregs) 643 { 644 const td_thragent_t *ta = th->th_ta; 645 struct kse_thr_mailbox tmbx; 646 psaddr_t tcb_addr, tmbx_addr, ptr; 647 lwpid_t lwp; 648 int ret; 649 650 TDBG_FUNC(); 651 652 ret = pt_validate(th); 653 if (ret) 654 return (ret); 655 656 if (ta->map[th->th_tid].type == PT_LWP) { 657 ret = ps_lsetregs(ta->ph, ta->map[th->th_tid].lwp, gregs); 658 return (P2T(ret)); 659 } 660 661 ret = ps_pread(ta->ph, ta->map[th->th_tid].thr + 662 offsetof(struct pthread, tcb), 663 &tcb_addr, sizeof(tcb_addr)); 664 if (ret != 0) 665 return (P2T(ret)); 666 tmbx_addr = tcb_addr + offsetof(struct tcb, tcb_tmbx); 667 ptr = tmbx_addr + offsetof(struct kse_thr_mailbox, tm_lwp); 668 ret = ps_pread(ta->ph, ptr, &lwp, sizeof(lwpid_t)); 669 if (ret != 0) 670 return (P2T(ret)); 671 if (lwp != 0) { 672 ret = ps_lsetregs(ta->ph, lwp, gregs); 673 return (P2T(ret)); 674 } 675 676 /* 677 * Read a copy of context, make sure that registers 678 * not covered by structure reg won't be clobbered 679 */ 680 ret = ps_pread(ta->ph, tmbx_addr, &tmbx, sizeof(tmbx)); 681 if (ret != 0) 682 return (P2T(ret)); 683 pt_reg_to_ucontext(gregs, &tmbx.tm_context); 684 ret = ps_pwrite(ta->ph, tmbx_addr, &tmbx, sizeof(tmbx)); 685 return (P2T(ret)); 686 } 687 688 static td_err_e 689 pt_thr_event_enable(const td_thrhandle_t *th, int en) 690 { 691 TDBG_FUNC(); 692 return (TD_ERR); 693 } 694 695 static td_err_e 696 pt_thr_set_event(const td_thrhandle_t *th, td_thr_events_t *setp) 697 { 698 TDBG_FUNC(); 699 return (TD_ERR); 700 } 701 702 static td_err_e 703 pt_thr_clear_event(const td_thrhandle_t *th, td_thr_events_t *setp) 704 { 705 TDBG_FUNC(); 706 return (TD_ERR); 707 } 708 709 static td_err_e 710 pt_thr_event_getmsg(const td_thrhandle_t *th, td_event_msg_t *msg) 711 { 712 TDBG_FUNC(); 713 return (TD_NOMSG); 714 } 715 716 static td_err_e 717 pt_thr_sstep(const td_thrhandle_t *th, int step) 718 { 719 const td_thragent_t *ta = th->th_ta; 720 struct kse_thr_mailbox tmbx; 721 struct reg regs; 722 psaddr_t tcb_addr, tmbx_addr; 723 uint32_t tmp; 724 lwpid_t lwp; 725 int ret; 726 727 TDBG_FUNC(); 728 729 ret = pt_validate(th); 730 if (ret) 731 return (ret); 732 733 if (ta->map[th->th_tid].type == PT_LWP) 734 return (TD_BADTH); 735 736 ret = ps_pread(ta->ph, ta->map[th->th_tid].thr + 737 offsetof(struct pthread, tcb), 738 &tcb_addr, sizeof(tcb_addr)); 739 if (ret != 0) 740 return (P2T(ret)); 741 742 /* Clear or set single step flag in thread mailbox */ 743 tmp = step ? TMDF_SSTEP : 0; 744 ret = ps_pwrite(ta->ph, tcb_addr + offsetof(struct tcb, 745 tcb_tmbx.tm_dflags), &tmp, sizeof(tmp)); 746 if (ret != 0) 747 return (P2T(ret)); 748 /* Get lwp */ 749 ret = ps_pread(ta->ph, tcb_addr + offsetof(struct tcb, 750 tcb_tmbx.tm_lwp), &lwp, sizeof(lwpid_t)); 751 if (ret != 0) 752 return (P2T(ret)); 753 if (lwp != 0) 754 return (TD_BADTH); 755 756 tmbx_addr = tcb_addr + offsetof(struct tcb, tcb_tmbx); 757 /* 758 * context is in userland, some architectures store 759 * single step status in registers, we should change 760 * these registers. 761 */ 762 ret = ps_pread(ta->ph, tmbx_addr, &tmbx, sizeof(tmbx)); 763 if (ret == 0) { 764 pt_ucontext_to_reg(&tmbx.tm_context, ®s); 765 /* only write out if it is really changed. */ 766 if (pt_reg_sstep(®s, step) != 0) { 767 pt_reg_to_ucontext(®s, &tmbx.tm_context); 768 ret = ps_pwrite(ta->ph, tmbx_addr, &tmbx, 769 sizeof(tmbx)); 770 } 771 } 772 return (P2T(ret)); 773 } 774 775 static void 776 pt_unmap_lwp(const td_thragent_t *ta, lwpid_t lwp) 777 { 778 int i; 779 780 for (i = 0; i < ta->map_len; ++i) { 781 if (ta->map[i].type == PT_LWP && ta->map[i].lwp == lwp) { 782 ta->map[i].type = PT_NONE; 783 return; 784 } 785 } 786 } 787 788 static int 789 pt_validate(const td_thrhandle_t *th) 790 { 791 792 if (th->th_tid < 0 || th->th_tid >= th->th_ta->map_len || 793 th->th_ta->map[th->th_tid].type == PT_NONE) 794 return (TD_NOTHR); 795 return (TD_OK); 796 } 797 798 struct ta_ops libpthread_db_ops = { 799 .to_init = pt_init, 800 .to_ta_clear_event = pt_ta_clear_event, 801 .to_ta_delete = pt_ta_delete, 802 .to_ta_event_addr = pt_ta_event_addr, 803 .to_ta_event_getmsg = pt_ta_event_getmsg, 804 .to_ta_map_id2thr = pt_ta_map_id2thr, 805 .to_ta_map_lwp2thr = pt_ta_map_lwp2thr, 806 .to_ta_new = pt_ta_new, 807 .to_ta_set_event = pt_ta_set_event, 808 .to_ta_thr_iter = pt_ta_thr_iter, 809 .to_ta_tsd_iter = pt_ta_tsd_iter, 810 .to_thr_clear_event = pt_thr_clear_event, 811 .to_thr_dbresume = pt_thr_dbresume, 812 .to_thr_dbsuspend = pt_thr_dbsuspend, 813 .to_thr_event_enable = pt_thr_event_enable, 814 .to_thr_event_getmsg = pt_thr_event_getmsg, 815 .to_thr_get_info = pt_thr_get_info, 816 .to_thr_getfpregs = pt_thr_getfpregs, 817 .to_thr_getgregs = pt_thr_getgregs, 818 .to_thr_set_event = pt_thr_set_event, 819 .to_thr_setfpregs = pt_thr_setfpregs, 820 .to_thr_setgregs = pt_thr_setgregs, 821 .to_thr_validate = pt_thr_validate, 822 823 /* FreeBSD specific extensions. */ 824 .to_thr_sstep = pt_thr_sstep, 825 }; 826