1 /* 2 * Copyright (c) 2004 Marcel Moolenaar 3 * Copyright (c) 2005 David Xu 4 * All rights reserved. 5 * 6 * Redistribution and use in source and binary forms, with or without 7 * modification, are permitted provided that the following conditions 8 * are met: 9 * 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 17 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 18 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 19 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 20 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 21 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 22 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 23 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 24 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 25 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 */ 27 28 #include <sys/cdefs.h> 29 __FBSDID("$FreeBSD$"); 30 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 TAILQ_HEAD(, pthread) thread_list; 205 psaddr_t pt; 206 long lwp; 207 int ret; 208 209 TDBG_FUNC(); 210 211 if (id == 0) 212 return (TD_NOTHR); 213 ret = ps_pread(ta->ph, ta->thread_list_addr, &thread_list, 214 sizeof(thread_list)); 215 if (ret != 0) 216 return (P2T(ret)); 217 /* Iterate through thread list to find pthread */ 218 pt = (psaddr_t)thread_list.tqh_first; 219 while (pt != NULL) { 220 ret = ps_pread(ta->ph, pt + ta->thread_off_tid, 221 &lwp, sizeof(lwp)); 222 if (ret != 0) 223 return (P2T(ret)); 224 if (lwp == id) 225 break; 226 /* get next thread */ 227 ret = ps_pread(ta->ph, 228 pt + ta->thread_off_next, 229 &pt, sizeof(pt)); 230 if (ret != 0) 231 return (P2T(ret)); 232 } 233 if (pt == NULL) 234 return (TD_NOTHR); 235 th->th_ta = ta; 236 th->th_tid = id; 237 th->th_thread = pt; 238 return (TD_OK); 239 } 240 241 static td_err_e 242 pt_ta_map_lwp2thr(const td_thragent_t *ta, lwpid_t lwp, td_thrhandle_t *th) 243 { 244 return (pt_ta_map_id2thr(ta, lwp, th)); 245 } 246 247 static td_err_e 248 pt_ta_thr_iter(const td_thragent_t *ta, 249 td_thr_iter_f *callback, void *cbdata_p, 250 td_thr_state_e state, int ti_pri, 251 sigset_t *ti_sigmask_p, 252 unsigned int ti_user_flags) 253 { 254 TAILQ_HEAD(, pthread) thread_list; 255 td_thrhandle_t th; 256 psaddr_t pt; 257 long lwp; 258 int ret; 259 260 TDBG_FUNC(); 261 262 ret = ps_pread(ta->ph, ta->thread_list_addr, &thread_list, 263 sizeof(thread_list)); 264 if (ret != 0) 265 return (P2T(ret)); 266 pt = (psaddr_t)thread_list.tqh_first; 267 while (pt != 0) { 268 ret = ps_pread(ta->ph, pt + ta->thread_off_tid, &lwp, 269 sizeof(lwp)); 270 if (ret != 0) 271 return (P2T(ret)); 272 if (lwp != 0 && lwp != TERMINATED) { 273 th.th_ta = ta; 274 th.th_tid = (thread_t)lwp; 275 th.th_thread = pt; 276 if ((*callback)(&th, cbdata_p)) 277 return (TD_DBERR); 278 } 279 /* get next thread */ 280 ret = ps_pread(ta->ph, pt + ta->thread_off_next, &pt, 281 sizeof(pt)); 282 if (ret != 0) 283 return (P2T(ret)); 284 } 285 return (TD_OK); 286 } 287 288 static td_err_e 289 pt_ta_tsd_iter(const td_thragent_t *ta, td_key_iter_f *ki, void *arg) 290 { 291 char *keytable; 292 void *destructor; 293 int i, ret, allocated; 294 295 TDBG_FUNC(); 296 297 keytable = malloc(ta->thread_max_keys * ta->thread_size_key); 298 if (keytable == NULL) 299 return (TD_MALLOC); 300 ret = ps_pread(ta->ph, (psaddr_t)ta->thread_keytable_addr, keytable, 301 ta->thread_max_keys * ta->thread_size_key); 302 if (ret != 0) { 303 free(keytable); 304 return (P2T(ret)); 305 } 306 for (i = 0; i < ta->thread_max_keys; i++) { 307 allocated = *(int *)(keytable + i * ta->thread_size_key + 308 ta->thread_off_key_allocated); 309 destructor = *(void **)(keytable + i * ta->thread_size_key + 310 ta->thread_off_key_destructor); 311 if (allocated) { 312 ret = (ki)(i, destructor, arg); 313 if (ret != 0) { 314 free(keytable); 315 return (TD_DBERR); 316 } 317 } 318 } 319 free(keytable); 320 return (TD_OK); 321 } 322 323 static td_err_e 324 pt_ta_event_addr(const td_thragent_t *ta, td_event_e event, td_notify_t *ptr) 325 { 326 327 TDBG_FUNC(); 328 329 switch (event) { 330 case TD_CREATE: 331 ptr->type = NOTIFY_BPT; 332 ptr->u.bptaddr = ta->thread_bp_create_addr; 333 return (0); 334 case TD_DEATH: 335 ptr->type = NOTIFY_BPT; 336 ptr->u.bptaddr = ta->thread_bp_death_addr; 337 return (0); 338 default: 339 return (TD_ERR); 340 } 341 } 342 343 static td_err_e 344 pt_ta_set_event(const td_thragent_t *ta, td_thr_events_t *events) 345 { 346 td_thr_events_t mask; 347 int ret; 348 349 TDBG_FUNC(); 350 ret = ps_pread(ta->ph, ta->thread_event_mask_addr, &mask, 351 sizeof(mask)); 352 if (ret != 0) 353 return (P2T(ret)); 354 mask |= *events; 355 ret = ps_pwrite(ta->ph, ta->thread_event_mask_addr, &mask, 356 sizeof(mask)); 357 return (P2T(ret)); 358 } 359 360 static td_err_e 361 pt_ta_clear_event(const td_thragent_t *ta, td_thr_events_t *events) 362 { 363 td_thr_events_t mask; 364 int ret; 365 366 TDBG_FUNC(); 367 ret = ps_pread(ta->ph, ta->thread_event_mask_addr, &mask, 368 sizeof(mask)); 369 if (ret != 0) 370 return (P2T(ret)); 371 mask &= ~*events; 372 ret = ps_pwrite(ta->ph, ta->thread_event_mask_addr, &mask, 373 sizeof(mask)); 374 return (P2T(ret)); 375 } 376 377 static td_err_e 378 pt_ta_event_getmsg(const td_thragent_t *ta, td_event_msg_t *msg) 379 { 380 static td_thrhandle_t handle; 381 382 psaddr_t pt, pt_temp; 383 td_thr_events_e tmp; 384 long lwp; 385 int ret; 386 387 TDBG_FUNC(); 388 389 ret = ps_pread(ta->ph, ta->thread_last_event_addr, &pt, sizeof(pt)); 390 if (ret != 0) 391 return (P2T(ret)); 392 if (pt == NULL) 393 return (TD_NOMSG); 394 /* 395 * Take the event pointer, at the time, libthr only reports event 396 * once a time, so it is not a link list. 397 */ 398 pt_temp = NULL; 399 ps_pwrite(ta->ph, ta->thread_last_event_addr, &pt_temp, sizeof(pt_temp)); 400 401 /* Read event info */ 402 ret = ps_pread(ta->ph, pt + ta->thread_off_event_buf, msg, sizeof(*msg)); 403 if (ret != 0) 404 return (P2T(ret)); 405 if (msg->event == 0) 406 return (TD_NOMSG); 407 /* Clear event */ 408 tmp = 0; 409 ps_pwrite(ta->ph, pt + ta->thread_off_event_buf, &tmp, sizeof(tmp)); 410 /* Convert event */ 411 pt = (psaddr_t)msg->th_p; 412 ret = ps_pread(ta->ph, pt + ta->thread_off_tid, &lwp, sizeof(lwp)); 413 if (ret != 0) 414 return (P2T(ret)); 415 handle.th_ta = ta; 416 handle.th_tid = lwp; 417 handle.th_thread = pt; 418 msg->th_p = &handle; 419 return (0); 420 } 421 422 static td_err_e 423 pt_dbsuspend(const td_thrhandle_t *th, int suspend) 424 { 425 td_thragent_t *ta = (td_thragent_t *)th->th_ta; 426 int ret; 427 428 TDBG_FUNC(); 429 430 ret = pt_validate(th); 431 if (ret) 432 return (ret); 433 434 if (suspend) 435 ret = ps_lstop(ta->ph, th->th_tid); 436 else 437 ret = ps_lcontinue(ta->ph, th->th_tid); 438 return (P2T(ret)); 439 } 440 441 static td_err_e 442 pt_thr_dbresume(const td_thrhandle_t *th) 443 { 444 TDBG_FUNC(); 445 446 return pt_dbsuspend(th, 0); 447 } 448 449 static td_err_e 450 pt_thr_dbsuspend(const td_thrhandle_t *th) 451 { 452 TDBG_FUNC(); 453 454 return pt_dbsuspend(th, 1); 455 } 456 457 static td_err_e 458 pt_thr_validate(const td_thrhandle_t *th) 459 { 460 td_thrhandle_t temp; 461 int ret; 462 463 TDBG_FUNC(); 464 465 ret = pt_ta_map_id2thr(th->th_ta, th->th_tid, &temp); 466 return (ret); 467 } 468 469 static td_err_e 470 pt_thr_get_info(const td_thrhandle_t *th, td_thrinfo_t *info) 471 { 472 const td_thragent_t *ta = th->th_ta; 473 struct ptrace_lwpinfo linfo; 474 int state; 475 int ret; 476 477 TDBG_FUNC(); 478 479 bzero(info, sizeof(*info)); 480 ret = pt_validate(th); 481 if (ret) 482 return (ret); 483 ret = ps_pread(ta->ph, th->th_thread + ta->thread_off_state, 484 &state, sizeof(state)); 485 if (ret != 0) 486 return (P2T(ret)); 487 ret = ps_pread(ta->ph, th->th_thread + ta->thread_off_report_events, 488 &info->ti_traceme, sizeof(int)); 489 if (ret != 0) 490 return (P2T(ret)); 491 ret = ps_pread(ta->ph, th->th_thread + ta->thread_off_event_mask, 492 &info->ti_events, sizeof(td_thr_events_t)); 493 if (ret != 0) 494 return (P2T(ret)); 495 ret = ps_pread(ta->ph, th->th_thread + ta->thread_off_tcb, 496 &info->ti_tls, sizeof(void *)); 497 info->ti_lid = th->th_tid; 498 info->ti_tid = th->th_tid; 499 info->ti_thread = th->th_thread; 500 info->ti_ta_p = th->th_ta; 501 ret = ps_linfo(ta->ph, th->th_tid, &linfo); 502 if (ret == PS_OK) { 503 info->ti_sigmask = linfo.pl_sigmask; 504 info->ti_pending = linfo.pl_siglist; 505 } else 506 return (ret); 507 if (state == ta->thread_state_running) 508 info->ti_state = TD_THR_RUN; 509 else if (state == ta->thread_state_zoombie) 510 info->ti_state = TD_THR_ZOMBIE; 511 else 512 info->ti_state = TD_THR_SLEEP; 513 info->ti_type = TD_THR_USER; 514 return (0); 515 } 516 517 #ifdef __i386__ 518 static td_err_e 519 pt_thr_getxmmregs(const td_thrhandle_t *th, char *fxsave) 520 { 521 const td_thragent_t *ta = th->th_ta; 522 int ret; 523 524 TDBG_FUNC(); 525 526 ret = pt_validate(th); 527 if (ret) 528 return (ret); 529 530 ret = ps_lgetxmmregs(ta->ph, th->th_tid, fxsave); 531 return (P2T(ret)); 532 } 533 #endif 534 535 static td_err_e 536 pt_thr_getfpregs(const td_thrhandle_t *th, prfpregset_t *fpregs) 537 { 538 const td_thragent_t *ta = th->th_ta; 539 int ret; 540 541 TDBG_FUNC(); 542 543 ret = pt_validate(th); 544 if (ret) 545 return (ret); 546 547 ret = ps_lgetfpregs(ta->ph, th->th_tid, fpregs); 548 return (P2T(ret)); 549 } 550 551 static td_err_e 552 pt_thr_getgregs(const td_thrhandle_t *th, prgregset_t gregs) 553 { 554 const td_thragent_t *ta = th->th_ta; 555 int ret; 556 557 TDBG_FUNC(); 558 559 ret = pt_validate(th); 560 if (ret) 561 return (ret); 562 563 ret = ps_lgetregs(ta->ph, th->th_tid, gregs); 564 return (P2T(ret)); 565 } 566 567 #ifdef __i386__ 568 static td_err_e 569 pt_thr_setxmmregs(const td_thrhandle_t *th, const char *fxsave) 570 { 571 const td_thragent_t *ta = th->th_ta; 572 int ret; 573 574 TDBG_FUNC(); 575 576 ret = pt_validate(th); 577 if (ret) 578 return (ret); 579 580 ret = ps_lsetxmmregs(ta->ph, th->th_tid, fxsave); 581 return (P2T(ret)); 582 } 583 #endif 584 585 static td_err_e 586 pt_thr_setfpregs(const td_thrhandle_t *th, const prfpregset_t *fpregs) 587 { 588 const td_thragent_t *ta = th->th_ta; 589 int ret; 590 591 TDBG_FUNC(); 592 593 ret = pt_validate(th); 594 if (ret) 595 return (ret); 596 597 ret = ps_lsetfpregs(ta->ph, th->th_tid, fpregs); 598 return (P2T(ret)); 599 } 600 601 static td_err_e 602 pt_thr_setgregs(const td_thrhandle_t *th, const prgregset_t gregs) 603 { 604 const td_thragent_t *ta = th->th_ta; 605 int ret; 606 607 TDBG_FUNC(); 608 609 ret = pt_validate(th); 610 if (ret) 611 return (ret); 612 613 ret = ps_lsetregs(ta->ph, th->th_tid, gregs); 614 return (P2T(ret)); 615 } 616 617 static td_err_e 618 pt_thr_event_enable(const td_thrhandle_t *th, int en) 619 { 620 const td_thragent_t *ta = th->th_ta; 621 int ret; 622 623 TDBG_FUNC(); 624 ret = ps_pwrite(ta->ph, th->th_thread + ta->thread_off_report_events, 625 &en, sizeof(int)); 626 return (P2T(ret)); 627 } 628 629 static td_err_e 630 pt_thr_set_event(const td_thrhandle_t *th, td_thr_events_t *setp) 631 { 632 const td_thragent_t *ta = th->th_ta; 633 td_thr_events_t mask; 634 int ret; 635 636 TDBG_FUNC(); 637 ret = ps_pread(ta->ph, th->th_thread + ta->thread_off_event_mask, 638 &mask, sizeof(mask)); 639 mask |= *setp; 640 ret = ps_pwrite(ta->ph, th->th_thread + ta->thread_off_event_mask, 641 &mask, sizeof(mask)); 642 return (P2T(ret)); 643 } 644 645 static td_err_e 646 pt_thr_clear_event(const td_thrhandle_t *th, td_thr_events_t *setp) 647 { 648 const td_thragent_t *ta = th->th_ta; 649 td_thr_events_t mask; 650 int ret; 651 652 TDBG_FUNC(); 653 ret = ps_pread(ta->ph, th->th_thread + ta->thread_off_event_mask, 654 &mask, sizeof(mask)); 655 mask &= ~*setp; 656 ret = ps_pwrite(ta->ph, th->th_thread + ta->thread_off_event_mask, 657 &mask, sizeof(mask)); 658 return (P2T(ret)); 659 } 660 661 static td_err_e 662 pt_thr_event_getmsg(const td_thrhandle_t *th, td_event_msg_t *msg) 663 { 664 static td_thrhandle_t handle; 665 td_thragent_t *ta = (td_thragent_t *)th->th_ta; 666 psaddr_t pt, pt_temp; 667 long lwp; 668 int ret; 669 td_thr_events_e tmp; 670 671 TDBG_FUNC(); 672 pt = th->th_thread; 673 ret = ps_pread(ta->ph, ta->thread_last_event_addr, &pt_temp, sizeof(pt_temp)); 674 if (ret != 0) 675 return (P2T(ret)); 676 /* Get event */ 677 ret = ps_pread(ta->ph, pt + ta->thread_off_event_buf, msg, sizeof(*msg)); 678 if (ret != 0) 679 return (P2T(ret)); 680 if (msg->event == 0) 681 return (TD_NOMSG); 682 /* 683 * Take the event pointer, at the time, libthr only reports event 684 * once a time, so it is not a link list. 685 */ 686 if (pt == pt_temp) { 687 pt_temp = NULL; 688 ps_pwrite(ta->ph, ta->thread_last_event_addr, &pt_temp, sizeof(pt_temp)); 689 } 690 /* Clear event */ 691 tmp = 0; 692 ps_pwrite(ta->ph, pt + ta->thread_off_event_buf, &tmp, sizeof(tmp)); 693 /* Convert event */ 694 pt = (psaddr_t)msg->th_p; 695 ret = ps_pread(ta->ph, pt + ta->thread_off_tid, &lwp, sizeof(lwp)); 696 if (ret != 0) 697 return (P2T(ret)); 698 handle.th_ta = ta; 699 handle.th_tid = lwp; 700 handle.th_thread = pt; 701 msg->th_p = &handle; 702 return (0); 703 } 704 705 static td_err_e 706 pt_thr_sstep(const td_thrhandle_t *th, int step) 707 { 708 TDBG_FUNC(); 709 710 return pt_validate(th); 711 } 712 713 static int 714 pt_validate(const td_thrhandle_t *th) 715 { 716 717 if (th->th_tid == 0 || th->th_thread == NULL) 718 return (TD_ERR); 719 return (TD_OK); 720 } 721 722 static td_err_e 723 pt_thr_tls_get_addr(const td_thrhandle_t *th, void *_linkmap, size_t offset, 724 void **address) 725 { 726 char *obj_entry; 727 const td_thragent_t *ta = th->th_ta; 728 psaddr_t tcb_addr, *dtv_addr; 729 int tls_index, ret; 730 731 /* linkmap is a member of Obj_Entry */ 732 obj_entry = (char *)_linkmap - ta->thread_off_linkmap; 733 734 /* get tlsindex of the object file */ 735 ret = ps_pread(ta->ph, 736 obj_entry + ta->thread_off_tlsindex, 737 &tls_index, sizeof(tls_index)); 738 if (ret != 0) 739 return (P2T(ret)); 740 741 /* get thread tcb */ 742 ret = ps_pread(ta->ph, th->th_thread + ta->thread_off_tcb, 743 &tcb_addr, sizeof(tcb_addr)); 744 if (ret != 0) 745 return (P2T(ret)); 746 747 /* get dtv array address */ 748 ret = ps_pread(ta->ph, tcb_addr + ta->thread_off_dtv, 749 &dtv_addr, sizeof(dtv_addr)); 750 if (ret != 0) 751 return (P2T(ret)); 752 /* now get the object's tls block base address */ 753 ret = ps_pread(ta->ph, &dtv_addr[tls_index+1], address, 754 sizeof(*address)); 755 if (ret != 0) 756 return (P2T(ret)); 757 758 *address += offset; 759 return (TD_OK); 760 } 761 762 struct ta_ops libthr_db_ops = { 763 .to_init = pt_init, 764 .to_ta_clear_event = pt_ta_clear_event, 765 .to_ta_delete = pt_ta_delete, 766 .to_ta_event_addr = pt_ta_event_addr, 767 .to_ta_event_getmsg = pt_ta_event_getmsg, 768 .to_ta_map_id2thr = pt_ta_map_id2thr, 769 .to_ta_map_lwp2thr = pt_ta_map_lwp2thr, 770 .to_ta_new = pt_ta_new, 771 .to_ta_set_event = pt_ta_set_event, 772 .to_ta_thr_iter = pt_ta_thr_iter, 773 .to_ta_tsd_iter = pt_ta_tsd_iter, 774 .to_thr_clear_event = pt_thr_clear_event, 775 .to_thr_dbresume = pt_thr_dbresume, 776 .to_thr_dbsuspend = pt_thr_dbsuspend, 777 .to_thr_event_enable = pt_thr_event_enable, 778 .to_thr_event_getmsg = pt_thr_event_getmsg, 779 .to_thr_get_info = pt_thr_get_info, 780 .to_thr_getfpregs = pt_thr_getfpregs, 781 .to_thr_getgregs = pt_thr_getgregs, 782 .to_thr_set_event = pt_thr_set_event, 783 .to_thr_setfpregs = pt_thr_setfpregs, 784 .to_thr_setgregs = pt_thr_setgregs, 785 .to_thr_validate = pt_thr_validate, 786 .to_thr_tls_get_addr = pt_thr_tls_get_addr, 787 788 /* FreeBSD specific extensions. */ 789 .to_thr_sstep = pt_thr_sstep, 790 #ifdef __i386__ 791 .to_thr_getxmmregs = pt_thr_getxmmregs, 792 .to_thr_setxmmregs = pt_thr_setxmmregs, 793 #endif 794 }; 795 796 DATA_SET(__ta_ops, libthr_db_ops); 797