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