libpthread_db.c revision 132332
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: head/lib/libthread_db/libpthread_db.c 132332 2004-07-18 04:17:15Z marcel $"); 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 46static void pt_unmap_lwp(const td_thragent_t *ta, lwpid_t lwp); 47static int pt_validate(const td_thrhandle_t *th); 48 49static int 50ps2td(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 72static long 73pt_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 114static td_err_e 115pt_init(void) 116{ 117 pt_md_init(); 118 return (0); 119} 120 121static td_err_e 122pt_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 162error: 163 free(ta); 164 return (ret); 165} 166 167static td_err_e 168pt_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 186static td_err_e 187pt_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 269static td_err_e 270pt_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 313static td_err_e 314pt_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 358static td_err_e 359pt_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 381static td_err_e 382pt_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 388static td_err_e 389pt_ta_set_event(const td_thragent_t *ta, td_thr_events_t *events) 390{ 391 TDBG_FUNC(); 392 return (TD_ERR); 393} 394 395static td_err_e 396pt_ta_clear_event(const td_thragent_t *ta, td_thr_events_t *events) 397{ 398 TDBG_FUNC(); 399 return (TD_ERR); 400} 401 402static td_err_e 403pt_ta_event_getmsg(const td_thragent_t *ta, td_event_msg_t *msg) 404{ 405 TDBG_FUNC(); 406 return (TD_NOMSG); 407} 408 409static td_err_e 410pt_thr_dbresume(const td_thrhandle_t *th) 411{ 412 TDBG_FUNC(); 413 return (TD_ERR); 414} 415 416static td_err_e 417pt_thr_dbsuspend(const td_thrhandle_t *th) 418{ 419 TDBG_FUNC(); 420 return (TD_ERR); 421} 422 423static td_err_e 424pt_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 436static td_err_e 437pt_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 510static td_err_e 511pt_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 552static td_err_e 553pt_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 594static td_err_e 595pt_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 641static td_err_e 642pt_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 688static td_err_e 689pt_thr_event_enable(const td_thrhandle_t *th, int en) 690{ 691 TDBG_FUNC(); 692 return (TD_ERR); 693} 694 695static td_err_e 696pt_thr_set_event(const td_thrhandle_t *th, td_thr_events_t *setp) 697{ 698 TDBG_FUNC(); 699 return (TD_ERR); 700} 701 702static td_err_e 703pt_thr_clear_event(const td_thrhandle_t *th, td_thr_events_t *setp) 704{ 705 TDBG_FUNC(); 706 return (TD_ERR); 707} 708 709static td_err_e 710pt_thr_event_getmsg(const td_thrhandle_t *th, td_event_msg_t *msg) 711{ 712 TDBG_FUNC(); 713 return (TD_NOMSG); 714} 715 716static td_err_e 717pt_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 775static void 776pt_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 788static int 789pt_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 798struct 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