1 /*- 2 * SPDX-License-Identifier: BSD-2-Clause 3 * 4 * Copyright (c) 2004 Marcel Moolenaar 5 * Copyright (c) 2005 David Xu 6 * All rights reserved. 7 * 8 * Redistribution and use in source and binary forms, with or without 9 * modification, are permitted provided that the following conditions 10 * are met: 11 * 12 * 1. Redistributions of source code must retain the above copyright 13 * notice, this list of conditions and the following disclaimer. 14 * 2. Redistributions in binary form must reproduce the above copyright 15 * notice, this list of conditions and the following disclaimer in the 16 * documentation and/or other materials provided with the distribution. 17 * 18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 19 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 20 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 21 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 22 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 23 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 24 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 25 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 27 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 28 */ 29 30 #include <sys/cdefs.h> 31 __FBSDID("$FreeBSD$"); 32 33 #include <proc_service.h> 34 #include <stddef.h> 35 #include <stdlib.h> 36 #include <string.h> 37 #include <sys/types.h> 38 #include <sys/linker_set.h> 39 #include <sys/ptrace.h> 40 #include <thread_db.h> 41 #include <unistd.h> 42 43 #include "thread_db_int.h" 44 45 #define TERMINATED 1 46 47 struct td_thragent { 48 TD_THRAGENT_FIELDS; 49 psaddr_t libthr_debug_addr; 50 psaddr_t thread_list_addr; 51 psaddr_t thread_active_threads_addr; 52 psaddr_t thread_keytable_addr; 53 psaddr_t thread_last_event_addr; 54 psaddr_t thread_event_mask_addr; 55 psaddr_t thread_bp_create_addr; 56 psaddr_t thread_bp_death_addr; 57 int thread_off_dtv; 58 int thread_off_tlsindex; 59 int thread_off_attr_flags; 60 int thread_size_key; 61 int thread_off_tcb; 62 int thread_off_linkmap; 63 int thread_off_next; 64 int thread_off_state; 65 int thread_off_tid; 66 int thread_max_keys; 67 int thread_off_key_allocated; 68 int thread_off_key_destructor; 69 int thread_off_report_events; 70 int thread_off_event_mask; 71 int thread_off_event_buf; 72 int thread_state_zoombie; 73 int thread_state_running; 74 }; 75 76 #define P2T(c) ps2td(c) 77 78 static int pt_validate(const td_thrhandle_t *th); 79 80 static int 81 ps2td(int c) 82 { 83 switch (c) { 84 case PS_OK: 85 return TD_OK; 86 case PS_ERR: 87 return TD_ERR; 88 case PS_BADPID: 89 return TD_BADPH; 90 case PS_BADLID: 91 return TD_NOLWP; 92 case PS_BADADDR: 93 return TD_ERR; 94 case PS_NOSYM: 95 return TD_NOLIBTHREAD; 96 case PS_NOFREGS: 97 return TD_NOFPREGS; 98 default: 99 return TD_ERR; 100 } 101 } 102 103 static td_err_e 104 pt_init(void) 105 { 106 return (0); 107 } 108 109 static td_err_e 110 pt_ta_new(struct ps_prochandle *ph, td_thragent_t **pta) 111 { 112 #define LOOKUP_SYM(proc, sym, addr) \ 113 ret = ps_pglobal_lookup(proc, NULL, sym, addr); \ 114 if (ret != 0) { \ 115 TDBG("can not find symbol: %s\n", sym); \ 116 ret = TD_NOLIBTHREAD; \ 117 goto error; \ 118 } 119 120 #define LOOKUP_VAL(proc, sym, val) \ 121 ret = ps_pglobal_lookup(proc, NULL, sym, &vaddr);\ 122 if (ret != 0) { \ 123 TDBG("can not find symbol: %s\n", sym); \ 124 ret = TD_NOLIBTHREAD; \ 125 goto error; \ 126 } \ 127 ret = ps_pread(proc, vaddr, val, sizeof(int)); \ 128 if (ret != 0) { \ 129 TDBG("can not read value of %s\n", sym);\ 130 ret = TD_NOLIBTHREAD; \ 131 goto error; \ 132 } 133 134 td_thragent_t *ta; 135 psaddr_t vaddr; 136 int dbg; 137 int ret; 138 139 TDBG_FUNC(); 140 141 ta = malloc(sizeof(td_thragent_t)); 142 if (ta == NULL) 143 return (TD_MALLOC); 144 145 ta->ph = ph; 146 147 LOOKUP_SYM(ph, "_libthr_debug", &ta->libthr_debug_addr); 148 LOOKUP_SYM(ph, "_thread_list", &ta->thread_list_addr); 149 LOOKUP_SYM(ph, "_thread_active_threads",&ta->thread_active_threads_addr); 150 LOOKUP_SYM(ph, "_thread_keytable", &ta->thread_keytable_addr); 151 LOOKUP_SYM(ph, "_thread_last_event", &ta->thread_last_event_addr); 152 LOOKUP_SYM(ph, "_thread_event_mask", &ta->thread_event_mask_addr); 153 LOOKUP_SYM(ph, "_thread_bp_create", &ta->thread_bp_create_addr); 154 LOOKUP_SYM(ph, "_thread_bp_death", &ta->thread_bp_death_addr); 155 LOOKUP_VAL(ph, "_thread_off_dtv", &ta->thread_off_dtv); 156 LOOKUP_VAL(ph, "_thread_off_tlsindex", &ta->thread_off_tlsindex); 157 LOOKUP_VAL(ph, "_thread_off_attr_flags", &ta->thread_off_attr_flags); 158 LOOKUP_VAL(ph, "_thread_size_key", &ta->thread_size_key); 159 LOOKUP_VAL(ph, "_thread_off_tcb", &ta->thread_off_tcb); 160 LOOKUP_VAL(ph, "_thread_off_tid", &ta->thread_off_tid); 161 LOOKUP_VAL(ph, "_thread_off_linkmap", &ta->thread_off_linkmap); 162 LOOKUP_VAL(ph, "_thread_off_next", &ta->thread_off_next); 163 LOOKUP_VAL(ph, "_thread_off_state", &ta->thread_off_state); 164 LOOKUP_VAL(ph, "_thread_max_keys", &ta->thread_max_keys); 165 LOOKUP_VAL(ph, "_thread_off_key_allocated", &ta->thread_off_key_allocated); 166 LOOKUP_VAL(ph, "_thread_off_key_destructor", &ta->thread_off_key_destructor); 167 LOOKUP_VAL(ph, "_thread_state_running", &ta->thread_state_running); 168 LOOKUP_VAL(ph, "_thread_state_zoombie", &ta->thread_state_zoombie); 169 LOOKUP_VAL(ph, "_thread_off_report_events", &ta->thread_off_report_events); 170 LOOKUP_VAL(ph, "_thread_off_event_mask", &ta->thread_off_event_mask); 171 LOOKUP_VAL(ph, "_thread_off_event_buf", &ta->thread_off_event_buf); 172 dbg = getpid(); 173 /* 174 * If this fails it probably means we're debugging a core file and 175 * can't write to it. 176 */ 177 ps_pwrite(ph, ta->libthr_debug_addr, &dbg, sizeof(int)); 178 *pta = ta; 179 return (0); 180 181 error: 182 free(ta); 183 return (ret); 184 } 185 186 static td_err_e 187 pt_ta_delete(td_thragent_t *ta) 188 { 189 int dbg; 190 191 TDBG_FUNC(); 192 193 dbg = 0; 194 /* 195 * Error returns from this write are not really a problem; 196 * the process doesn't exist any more. 197 */ 198 ps_pwrite(ta->ph, ta->libthr_debug_addr, &dbg, sizeof(int)); 199 free(ta); 200 return (TD_OK); 201 } 202 203 static td_err_e 204 pt_ta_map_id2thr(const td_thragent_t *ta, thread_t id, td_thrhandle_t *th) 205 { 206 psaddr_t pt; 207 int64_t lwp; 208 int ret; 209 210 TDBG_FUNC(); 211 212 if (id == 0) 213 return (TD_NOTHR); 214 ret = thr_pread_ptr(ta, ta->thread_list_addr, &pt); 215 if (ret != 0) 216 return (TD_ERR); 217 /* Iterate through thread list to find pthread */ 218 while (pt != 0) { 219 ret = thr_pread_long(ta, pt + ta->thread_off_tid, &lwp); 220 if (ret != 0) 221 return (TD_ERR); 222 if (lwp == id) 223 break; 224 /* get next thread */ 225 ret = thr_pread_ptr(ta, pt + ta->thread_off_next, &pt); 226 if (ret != 0) 227 return (TD_ERR); 228 } 229 if (pt == 0) 230 return (TD_NOTHR); 231 th->th_ta = ta; 232 th->th_tid = id; 233 th->th_thread = pt; 234 return (TD_OK); 235 } 236 237 static td_err_e 238 pt_ta_map_lwp2thr(const td_thragent_t *ta, lwpid_t lwp, td_thrhandle_t *th) 239 { 240 return (pt_ta_map_id2thr(ta, lwp, th)); 241 } 242 243 static td_err_e 244 pt_ta_thr_iter(const td_thragent_t *ta, td_thr_iter_f *callback, 245 void *cbdata_p, td_thr_state_e state __unused, int ti_pri __unused, 246 sigset_t *ti_sigmask_p __unused, unsigned int ti_user_flags __unused) 247 { 248 td_thrhandle_t th; 249 psaddr_t pt; 250 int64_t lwp; 251 int ret; 252 253 TDBG_FUNC(); 254 255 ret = thr_pread_ptr(ta, ta->thread_list_addr, &pt); 256 if (ret != 0) 257 return (TD_ERR); 258 while (pt != 0) { 259 ret = thr_pread_long(ta, pt + ta->thread_off_tid, &lwp); 260 if (ret != 0) 261 return (TD_ERR); 262 if (lwp != 0 && lwp != TERMINATED) { 263 th.th_ta = ta; 264 th.th_tid = (thread_t)lwp; 265 th.th_thread = pt; 266 if ((*callback)(&th, cbdata_p)) 267 return (TD_DBERR); 268 } 269 /* get next thread */ 270 ret = thr_pread_ptr(ta, pt + ta->thread_off_next, &pt); 271 if (ret != 0) 272 return (TD_ERR); 273 } 274 return (TD_OK); 275 } 276 277 static td_err_e 278 pt_ta_tsd_iter(const td_thragent_t *ta, td_key_iter_f *ki, void *arg) 279 { 280 void *keytable; 281 void *destructor; 282 int i, ret, allocated; 283 284 TDBG_FUNC(); 285 286 keytable = malloc(ta->thread_max_keys * ta->thread_size_key); 287 if (keytable == NULL) 288 return (TD_MALLOC); 289 ret = ps_pread(ta->ph, (psaddr_t)ta->thread_keytable_addr, keytable, 290 ta->thread_max_keys * ta->thread_size_key); 291 if (ret != 0) { 292 free(keytable); 293 return (P2T(ret)); 294 } 295 for (i = 0; i < ta->thread_max_keys; i++) { 296 allocated = *(int *)(void *)((uintptr_t)keytable + 297 i * ta->thread_size_key + ta->thread_off_key_allocated); 298 destructor = *(void **)(void *)((uintptr_t)keytable + 299 i * ta->thread_size_key + ta->thread_off_key_destructor); 300 if (allocated) { 301 ret = (ki)(i, destructor, arg); 302 if (ret != 0) { 303 free(keytable); 304 return (TD_DBERR); 305 } 306 } 307 } 308 free(keytable); 309 return (TD_OK); 310 } 311 312 static td_err_e 313 pt_ta_event_addr(const td_thragent_t *ta, td_event_e event, td_notify_t *ptr) 314 { 315 316 TDBG_FUNC(); 317 318 switch (event) { 319 case TD_CREATE: 320 ptr->type = NOTIFY_BPT; 321 ptr->u.bptaddr = ta->thread_bp_create_addr; 322 return (0); 323 case TD_DEATH: 324 ptr->type = NOTIFY_BPT; 325 ptr->u.bptaddr = ta->thread_bp_death_addr; 326 return (0); 327 default: 328 return (TD_ERR); 329 } 330 } 331 332 static td_err_e 333 pt_ta_set_event(const td_thragent_t *ta, td_thr_events_t *events) 334 { 335 td_thr_events_t mask; 336 int ret; 337 338 TDBG_FUNC(); 339 ret = ps_pread(ta->ph, ta->thread_event_mask_addr, &mask, 340 sizeof(mask)); 341 if (ret != 0) 342 return (P2T(ret)); 343 mask |= *events; 344 ret = ps_pwrite(ta->ph, ta->thread_event_mask_addr, &mask, 345 sizeof(mask)); 346 return (P2T(ret)); 347 } 348 349 static td_err_e 350 pt_ta_clear_event(const td_thragent_t *ta, td_thr_events_t *events) 351 { 352 td_thr_events_t mask; 353 int ret; 354 355 TDBG_FUNC(); 356 ret = ps_pread(ta->ph, ta->thread_event_mask_addr, &mask, 357 sizeof(mask)); 358 if (ret != 0) 359 return (P2T(ret)); 360 mask &= ~*events; 361 ret = ps_pwrite(ta->ph, ta->thread_event_mask_addr, &mask, 362 sizeof(mask)); 363 return (P2T(ret)); 364 } 365 366 static td_err_e 367 pt_ta_event_getmsg(const td_thragent_t *ta, td_event_msg_t *msg) 368 { 369 static td_thrhandle_t handle; 370 371 psaddr_t pt; 372 td_thr_events_e tmp; 373 int64_t lwp; 374 int ret; 375 376 TDBG_FUNC(); 377 378 ret = thr_pread_ptr(ta, ta->thread_last_event_addr, &pt); 379 if (ret != 0) 380 return (TD_ERR); 381 if (pt == 0) 382 return (TD_NOMSG); 383 /* 384 * Take the event pointer, at the time, libthr only reports event 385 * once a time, so it is not a link list. 386 */ 387 thr_pwrite_ptr(ta, ta->thread_last_event_addr, 0); 388 389 /* Read event info */ 390 ret = ps_pread(ta->ph, pt + ta->thread_off_event_buf, msg, sizeof(*msg)); 391 if (ret != 0) 392 return (P2T(ret)); 393 if (msg->event == 0) 394 return (TD_NOMSG); 395 /* Clear event */ 396 tmp = 0; 397 ps_pwrite(ta->ph, pt + ta->thread_off_event_buf, &tmp, sizeof(tmp)); 398 /* Convert event */ 399 pt = msg->th_p; 400 ret = thr_pread_long(ta, pt + ta->thread_off_tid, &lwp); 401 if (ret != 0) 402 return (TD_ERR); 403 handle.th_ta = ta; 404 handle.th_tid = lwp; 405 handle.th_thread = pt; 406 msg->th_p = (uintptr_t)&handle; 407 return (0); 408 } 409 410 static td_err_e 411 pt_dbsuspend(const td_thrhandle_t *th, int suspend) 412 { 413 const td_thragent_t *ta = th->th_ta; 414 int ret; 415 416 TDBG_FUNC(); 417 418 ret = pt_validate(th); 419 if (ret) 420 return (ret); 421 422 if (suspend) 423 ret = ps_lstop(ta->ph, th->th_tid); 424 else 425 ret = ps_lcontinue(ta->ph, th->th_tid); 426 return (P2T(ret)); 427 } 428 429 static td_err_e 430 pt_thr_dbresume(const td_thrhandle_t *th) 431 { 432 TDBG_FUNC(); 433 434 return pt_dbsuspend(th, 0); 435 } 436 437 static td_err_e 438 pt_thr_dbsuspend(const td_thrhandle_t *th) 439 { 440 TDBG_FUNC(); 441 442 return pt_dbsuspend(th, 1); 443 } 444 445 static td_err_e 446 pt_thr_validate(const td_thrhandle_t *th) 447 { 448 td_thrhandle_t temp; 449 int ret; 450 451 TDBG_FUNC(); 452 453 ret = pt_ta_map_id2thr(th->th_ta, th->th_tid, &temp); 454 return (ret); 455 } 456 457 static td_err_e 458 pt_thr_get_info_common(const td_thrhandle_t *th, td_thrinfo_t *info, int old) 459 { 460 const td_thragent_t *ta = th->th_ta; 461 struct ptrace_lwpinfo linfo; 462 int traceme; 463 int state; 464 int ret; 465 466 TDBG_FUNC(); 467 468 bzero(info, sizeof(*info)); 469 ret = pt_validate(th); 470 if (ret) 471 return (ret); 472 ret = thr_pread_int(ta, th->th_thread + ta->thread_off_state, &state); 473 if (ret != 0) 474 return (TD_ERR); 475 ret = thr_pread_int(ta, th->th_thread + ta->thread_off_report_events, 476 &traceme); 477 info->ti_traceme = traceme; 478 if (ret != 0) 479 return (TD_ERR); 480 ret = ps_pread(ta->ph, th->th_thread + ta->thread_off_event_mask, 481 &info->ti_events, sizeof(td_thr_events_t)); 482 if (ret != 0) 483 return (P2T(ret)); 484 ret = ps_pread(ta->ph, th->th_thread + ta->thread_off_tcb, 485 &info->ti_tls, sizeof(void *)); 486 info->ti_lid = th->th_tid; 487 info->ti_tid = th->th_tid; 488 info->ti_thread = th->th_thread; 489 info->ti_ta_p = th->th_ta; 490 ret = ps_linfo(ta->ph, th->th_tid, &linfo); 491 if (ret == PS_OK) { 492 info->ti_sigmask = linfo.pl_sigmask; 493 info->ti_pending = linfo.pl_siglist; 494 if (!old) { 495 if ((linfo.pl_flags & PL_FLAG_SI) != 0) 496 info->ti_siginfo = linfo.pl_siginfo; 497 else 498 bzero(&info->ti_siginfo, 499 sizeof(info->ti_siginfo)); 500 } 501 } else 502 return (ret); 503 if (state == ta->thread_state_running) 504 info->ti_state = TD_THR_RUN; 505 else if (state == ta->thread_state_zoombie) 506 info->ti_state = TD_THR_ZOMBIE; 507 else 508 info->ti_state = TD_THR_SLEEP; 509 info->ti_type = TD_THR_USER; 510 return (0); 511 } 512 513 static td_err_e 514 pt_thr_old_get_info(const td_thrhandle_t *th, td_old_thrinfo_t *info) 515 { 516 517 return (pt_thr_get_info_common(th, (td_thrinfo_t *)info, 1)); 518 } 519 520 static td_err_e 521 pt_thr_get_info(const td_thrhandle_t *th, td_thrinfo_t *info) 522 { 523 524 return (pt_thr_get_info_common(th, info, 0)); 525 } 526 527 #ifdef __i386__ 528 static td_err_e 529 pt_thr_getxmmregs(const td_thrhandle_t *th, char *fxsave) 530 { 531 const td_thragent_t *ta = th->th_ta; 532 int ret; 533 534 TDBG_FUNC(); 535 536 ret = pt_validate(th); 537 if (ret) 538 return (ret); 539 540 ret = ps_lgetxmmregs(ta->ph, th->th_tid, fxsave); 541 return (P2T(ret)); 542 } 543 #endif 544 545 static td_err_e 546 pt_thr_getfpregs(const td_thrhandle_t *th, prfpregset_t *fpregs) 547 { 548 const td_thragent_t *ta = th->th_ta; 549 int ret; 550 551 TDBG_FUNC(); 552 553 ret = pt_validate(th); 554 if (ret) 555 return (ret); 556 557 ret = ps_lgetfpregs(ta->ph, th->th_tid, fpregs); 558 return (P2T(ret)); 559 } 560 561 static td_err_e 562 pt_thr_getgregs(const td_thrhandle_t *th, prgregset_t gregs) 563 { 564 const td_thragent_t *ta = th->th_ta; 565 int ret; 566 567 TDBG_FUNC(); 568 569 ret = pt_validate(th); 570 if (ret) 571 return (ret); 572 573 ret = ps_lgetregs(ta->ph, th->th_tid, gregs); 574 return (P2T(ret)); 575 } 576 577 #ifdef __i386__ 578 static td_err_e 579 pt_thr_setxmmregs(const td_thrhandle_t *th, const char *fxsave) 580 { 581 const td_thragent_t *ta = th->th_ta; 582 int ret; 583 584 TDBG_FUNC(); 585 586 ret = pt_validate(th); 587 if (ret) 588 return (ret); 589 590 ret = ps_lsetxmmregs(ta->ph, th->th_tid, fxsave); 591 return (P2T(ret)); 592 } 593 #endif 594 595 static td_err_e 596 pt_thr_setfpregs(const td_thrhandle_t *th, const prfpregset_t *fpregs) 597 { 598 const td_thragent_t *ta = th->th_ta; 599 int ret; 600 601 TDBG_FUNC(); 602 603 ret = pt_validate(th); 604 if (ret) 605 return (ret); 606 607 ret = ps_lsetfpregs(ta->ph, th->th_tid, fpregs); 608 return (P2T(ret)); 609 } 610 611 static td_err_e 612 pt_thr_setgregs(const td_thrhandle_t *th, const prgregset_t gregs) 613 { 614 const td_thragent_t *ta = th->th_ta; 615 int ret; 616 617 TDBG_FUNC(); 618 619 ret = pt_validate(th); 620 if (ret) 621 return (ret); 622 623 ret = ps_lsetregs(ta->ph, th->th_tid, gregs); 624 return (P2T(ret)); 625 } 626 627 static td_err_e 628 pt_thr_event_enable(const td_thrhandle_t *th, int en) 629 { 630 const td_thragent_t *ta = th->th_ta; 631 int ret; 632 633 TDBG_FUNC(); 634 ret = ps_pwrite(ta->ph, th->th_thread + ta->thread_off_report_events, 635 &en, sizeof(int)); 636 return (P2T(ret)); 637 } 638 639 static td_err_e 640 pt_thr_set_event(const td_thrhandle_t *th, td_thr_events_t *setp) 641 { 642 const td_thragent_t *ta = th->th_ta; 643 td_thr_events_t mask; 644 int ret; 645 646 TDBG_FUNC(); 647 ret = ps_pread(ta->ph, th->th_thread + ta->thread_off_event_mask, 648 &mask, sizeof(mask)); 649 mask |= *setp; 650 ret = ps_pwrite(ta->ph, th->th_thread + ta->thread_off_event_mask, 651 &mask, sizeof(mask)); 652 return (P2T(ret)); 653 } 654 655 static td_err_e 656 pt_thr_clear_event(const td_thrhandle_t *th, td_thr_events_t *setp) 657 { 658 const td_thragent_t *ta = th->th_ta; 659 td_thr_events_t mask; 660 int ret; 661 662 TDBG_FUNC(); 663 ret = ps_pread(ta->ph, th->th_thread + ta->thread_off_event_mask, 664 &mask, sizeof(mask)); 665 mask &= ~*setp; 666 ret = ps_pwrite(ta->ph, th->th_thread + ta->thread_off_event_mask, 667 &mask, sizeof(mask)); 668 return (P2T(ret)); 669 } 670 671 static td_err_e 672 pt_thr_event_getmsg(const td_thrhandle_t *th, td_event_msg_t *msg) 673 { 674 static td_thrhandle_t handle; 675 const td_thragent_t *ta = th->th_ta; 676 psaddr_t pt, pt_temp; 677 int64_t lwp; 678 int ret; 679 td_thr_events_e tmp; 680 681 TDBG_FUNC(); 682 pt = th->th_thread; 683 ret = thr_pread_ptr(ta, ta->thread_last_event_addr, &pt_temp); 684 if (ret != 0) 685 return (TD_ERR); 686 /* Get event */ 687 ret = ps_pread(ta->ph, pt + ta->thread_off_event_buf, msg, sizeof(*msg)); 688 if (ret != 0) 689 return (P2T(ret)); 690 if (msg->event == 0) 691 return (TD_NOMSG); 692 /* 693 * Take the event pointer, at the time, libthr only reports event 694 * once a time, so it is not a link list. 695 */ 696 if (pt == pt_temp) 697 thr_pwrite_ptr(ta, ta->thread_last_event_addr, 0); 698 699 /* Clear event */ 700 tmp = 0; 701 ps_pwrite(ta->ph, pt + ta->thread_off_event_buf, &tmp, sizeof(tmp)); 702 /* Convert event */ 703 pt = msg->th_p; 704 ret = thr_pread_long(ta, pt + ta->thread_off_tid, &lwp); 705 if (ret != 0) 706 return (TD_ERR); 707 handle.th_ta = ta; 708 handle.th_tid = lwp; 709 handle.th_thread = pt; 710 msg->th_p = (uintptr_t)&handle; 711 return (0); 712 } 713 714 static td_err_e 715 pt_thr_sstep(const td_thrhandle_t *th, int step __unused) 716 { 717 TDBG_FUNC(); 718 719 return pt_validate(th); 720 } 721 722 static int 723 pt_validate(const td_thrhandle_t *th) 724 { 725 726 if (th->th_tid == 0 || th->th_thread == 0) 727 return (TD_ERR); 728 return (TD_OK); 729 } 730 731 static td_err_e 732 pt_thr_tls_get_addr(const td_thrhandle_t *th, psaddr_t _linkmap, size_t offset, 733 psaddr_t *address) 734 { 735 const td_thragent_t *ta = th->th_ta; 736 psaddr_t dtv_addr, obj_entry, tcb_addr; 737 int tls_index, ret; 738 739 /* linkmap is a member of Obj_Entry */ 740 obj_entry = _linkmap - ta->thread_off_linkmap; 741 742 /* get tlsindex of the object file */ 743 ret = ps_pread(ta->ph, 744 obj_entry + ta->thread_off_tlsindex, 745 &tls_index, sizeof(tls_index)); 746 if (ret != 0) 747 return (P2T(ret)); 748 749 /* get thread tcb */ 750 ret = ps_pread(ta->ph, th->th_thread + ta->thread_off_tcb, 751 &tcb_addr, sizeof(tcb_addr)); 752 if (ret != 0) 753 return (P2T(ret)); 754 755 /* get dtv array address */ 756 ret = ps_pread(ta->ph, tcb_addr + ta->thread_off_dtv, 757 &dtv_addr, sizeof(dtv_addr)); 758 if (ret != 0) 759 return (P2T(ret)); 760 /* now get the object's tls block base address */ 761 ret = ps_pread(ta->ph, dtv_addr + sizeof(void *) * (tls_index+1), 762 address, sizeof(*address)); 763 if (ret != 0) 764 return (P2T(ret)); 765 766 *address += offset; 767 return (TD_OK); 768 } 769 770 static struct ta_ops libthr_db_ops = { 771 .to_init = pt_init, 772 .to_ta_clear_event = pt_ta_clear_event, 773 .to_ta_delete = pt_ta_delete, 774 .to_ta_event_addr = pt_ta_event_addr, 775 .to_ta_event_getmsg = pt_ta_event_getmsg, 776 .to_ta_map_id2thr = pt_ta_map_id2thr, 777 .to_ta_map_lwp2thr = pt_ta_map_lwp2thr, 778 .to_ta_new = pt_ta_new, 779 .to_ta_set_event = pt_ta_set_event, 780 .to_ta_thr_iter = pt_ta_thr_iter, 781 .to_ta_tsd_iter = pt_ta_tsd_iter, 782 .to_thr_clear_event = pt_thr_clear_event, 783 .to_thr_dbresume = pt_thr_dbresume, 784 .to_thr_dbsuspend = pt_thr_dbsuspend, 785 .to_thr_event_enable = pt_thr_event_enable, 786 .to_thr_event_getmsg = pt_thr_event_getmsg, 787 .to_thr_old_get_info = pt_thr_old_get_info, 788 .to_thr_get_info = pt_thr_get_info, 789 .to_thr_getfpregs = pt_thr_getfpregs, 790 .to_thr_getgregs = pt_thr_getgregs, 791 .to_thr_set_event = pt_thr_set_event, 792 .to_thr_setfpregs = pt_thr_setfpregs, 793 .to_thr_setgregs = pt_thr_setgregs, 794 .to_thr_validate = pt_thr_validate, 795 .to_thr_tls_get_addr = pt_thr_tls_get_addr, 796 797 /* FreeBSD specific extensions. */ 798 .to_thr_sstep = pt_thr_sstep, 799 #ifdef __i386__ 800 .to_thr_getxmmregs = pt_thr_getxmmregs, 801 .to_thr_setxmmregs = pt_thr_setxmmregs, 802 #endif 803 }; 804 805 DATA_SET(__ta_ops, libthr_db_ops); 806