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 * $DragonFly: src/lib/libthread_db/libthread_xu.c,v 1.3 2005/05/07 10:08:08 davidxu Exp $ 28 */ 29 30 #include <sys/cdefs.h> 31 32 #include <proc_service.h> 33 #include <stddef.h> 34 #include <stdlib.h> 35 #include <string.h> 36 #include <machine/tls.h> 37 #include <sys/types.h> 38 #include <sys/ptrace.h> 39 #include <rtld.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 libthread_xu_debug_addr; 50 psaddr_t thread_active_threads_addr; 51 psaddr_t thread_bp_create_addr; 52 psaddr_t thread_bp_death_addr; 53 psaddr_t thread_event_mask_addr; 54 psaddr_t thread_keytable_addr; 55 psaddr_t thread_last_event_addr; 56 psaddr_t thread_list_addr; 57 int thread_max_keys; 58 int thread_off_attr_flags; 59 int thread_off_dtv; 60 int thread_off_event_buf; 61 int thread_off_event_mask; 62 int thread_off_key_allocated; 63 int thread_off_key_destructor; 64 int thread_off_linkmap; 65 int thread_off_next; 66 int thread_off_report_events; 67 int thread_off_state; 68 int thread_off_tcb; 69 int thread_off_tid; 70 int thread_off_tlsindex; 71 int thread_size_key; 72 int thread_state_running; 73 int thread_state_zoombie; 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, "_libthread_xu_debug", &ta->libthread_xu_debug_addr); 148 LOOKUP_SYM(ph, "_thread_active_threads",&ta->thread_active_threads_addr); 149 LOOKUP_SYM(ph, "_thread_bp_create", &ta->thread_bp_create_addr); 150 LOOKUP_SYM(ph, "_thread_bp_death", &ta->thread_bp_death_addr); 151 LOOKUP_SYM(ph, "_thread_event_mask", &ta->thread_event_mask_addr); 152 LOOKUP_SYM(ph, "_thread_keytable", &ta->thread_keytable_addr); 153 LOOKUP_SYM(ph, "_thread_last_event", &ta->thread_last_event_addr); 154 LOOKUP_SYM(ph, "_thread_list", &ta->thread_list_addr); 155 LOOKUP_VAL(ph, "_thread_max_keys", &ta->thread_max_keys); 156 LOOKUP_VAL(ph, "_thread_off_attr_flags", &ta->thread_off_attr_flags); 157 LOOKUP_VAL(ph, "_thread_off_event_buf", &ta->thread_off_event_buf); 158 LOOKUP_VAL(ph, "_thread_off_event_mask", &ta->thread_off_event_mask); 159 LOOKUP_VAL(ph, "_thread_off_key_allocated", &ta->thread_off_key_allocated); 160 LOOKUP_VAL(ph, "_thread_off_key_destructor", &ta->thread_off_key_destructor); 161 LOOKUP_VAL(ph, "_thread_off_next", &ta->thread_off_next); 162 LOOKUP_VAL(ph, "_thread_off_report_events", &ta->thread_off_report_events); 163 LOOKUP_VAL(ph, "_thread_off_state", &ta->thread_off_state); 164 LOOKUP_VAL(ph, "_thread_off_tcb", &ta->thread_off_tcb); 165 LOOKUP_VAL(ph, "_thread_off_tid", &ta->thread_off_tid); 166 LOOKUP_VAL(ph, "_thread_size_key", &ta->thread_size_key); 167 LOOKUP_VAL(ph, "_thread_state_running", &ta->thread_state_running); 168 LOOKUP_VAL(ph, "_thread_state_zoombie", &ta->thread_state_zoombie); 169 170 ta->thread_off_linkmap = offsetof(Obj_Entry, linkmap); 171 ta->thread_off_tlsindex = offsetof(Obj_Entry, tlsindex); 172 ta->thread_off_dtv = offsetof(struct tls_tcb, tcb_dtv); 173 174 dbg = getpid(); 175 /* 176 * If this fails it probably means we're debugging a core file and 177 * can't write to it. 178 */ 179 ps_pwrite(ph, ta->libthread_xu_debug_addr, &dbg, sizeof(int)); 180 *pta = ta; 181 return (0); 182 183 error: 184 free(ta); 185 return (ret); 186 } 187 188 static td_err_e 189 pt_ta_delete(td_thragent_t *ta) 190 { 191 int dbg; 192 193 TDBG_FUNC(); 194 195 dbg = 0; 196 /* 197 * Error returns from this write are not really a problem; 198 * the process doesn't exist any more. 199 */ 200 ps_pwrite(ta->ph, ta->libthread_xu_debug_addr, &dbg, sizeof(int)); 201 free(ta); 202 return (TD_OK); 203 } 204 205 static td_err_e 206 pt_ta_map_id2thr(const td_thragent_t *ta, thread_t id, td_thrhandle_t *th) 207 { 208 prgregset_t gregs; 209 TAILQ_HEAD(, pthread) thread_list; 210 psaddr_t pt; 211 long lwp; 212 int ret; 213 214 TDBG_FUNC(); 215 216 if (id == 0) 217 return (TD_NOTHR); 218 ret = ps_pread(ta->ph, ta->thread_list_addr, &thread_list, 219 sizeof(thread_list)); 220 if (ret != 0) 221 return (P2T(ret)); 222 /* Iterate through thread list to find pthread */ 223 pt = (psaddr_t)thread_list.tqh_first; 224 while (pt != NULL) { 225 ret = ps_pread(ta->ph, pt + ta->thread_off_tid, 226 &lwp, sizeof(lwp)); 227 if (ret != 0) 228 return (P2T(ret)); 229 if (lwp == id) 230 break; 231 /* get next thread */ 232 ret = ps_pread(ta->ph, 233 pt + ta->thread_off_next, 234 &pt, sizeof(pt)); 235 if (ret != 0) 236 return (P2T(ret)); 237 } 238 if (pt == NULL) 239 return (TD_NOTHR); 240 th->th_ta = ta; 241 th->th_tid = id; 242 th->th_thread = pt; 243 return (TD_OK); 244 } 245 246 static td_err_e 247 pt_ta_map_lwp2thr(const td_thragent_t *ta, lwpid_t lwp, td_thrhandle_t *th) 248 { 249 return (pt_ta_map_id2thr(ta, lwp, th)); 250 } 251 252 static td_err_e 253 pt_ta_thr_iter(const td_thragent_t *ta, 254 td_thr_iter_f *callback, void *cbdata_p, 255 td_thr_state_e state, int ti_pri, 256 sigset_t *ti_sigmask_p, 257 unsigned int ti_user_flags) 258 { 259 TAILQ_HEAD(, pthread) thread_list; 260 td_thrhandle_t th; 261 psaddr_t pt; 262 long lwp; 263 int ret; 264 265 TDBG_FUNC(); 266 267 ret = ps_pread(ta->ph, ta->thread_list_addr, &thread_list, 268 sizeof(thread_list)); 269 if (ret != 0) 270 return (P2T(ret)); 271 pt = (psaddr_t)thread_list.tqh_first; 272 while (pt != 0) { 273 ret = ps_pread(ta->ph, pt + ta->thread_off_tid, &lwp, 274 sizeof(lwp)); 275 if (ret != 0) 276 return (P2T(ret)); 277 if (lwp != 0 && lwp != TERMINATED) { 278 th.th_ta = ta; 279 th.th_tid = (thread_t)lwp; 280 th.th_thread = pt; 281 if ((*callback)(&th, cbdata_p)) 282 return (TD_DBERR); 283 } 284 /* get next thread */ 285 ret = ps_pread(ta->ph, pt + ta->thread_off_next, &pt, 286 sizeof(pt)); 287 if (ret != 0) 288 return (P2T(ret)); 289 } 290 return (TD_OK); 291 } 292 293 static td_err_e 294 pt_ta_tsd_iter(const td_thragent_t *ta, td_key_iter_f *ki, void *arg) 295 { 296 char *keytable; 297 void *destructor; 298 int i, ret, allocated; 299 300 TDBG_FUNC(); 301 302 keytable = malloc(ta->thread_max_keys * ta->thread_size_key); 303 if (keytable == NULL) 304 return (TD_MALLOC); 305 ret = ps_pread(ta->ph, (psaddr_t)ta->thread_keytable_addr, keytable, 306 ta->thread_max_keys * ta->thread_size_key); 307 if (ret != 0) { 308 free(keytable); 309 return (P2T(ret)); 310 } 311 for (i = 0; i < ta->thread_max_keys; i++) { 312 allocated = *(int *)(keytable + i * ta->thread_size_key + 313 ta->thread_off_key_allocated); 314 destructor = *(void **)(keytable + i * ta->thread_size_key + 315 ta->thread_off_key_destructor); 316 if (allocated) { 317 ret = (ki)(i, destructor, arg); 318 if (ret != 0) { 319 free(keytable); 320 return (TD_DBERR); 321 } 322 } 323 } 324 free(keytable); 325 return (TD_OK); 326 } 327 328 static td_err_e 329 pt_ta_event_addr(const td_thragent_t *ta, td_event_e event, td_notify_t *ptr) 330 { 331 332 TDBG_FUNC(); 333 334 switch (event) { 335 case TD_CREATE: 336 ptr->type = NOTIFY_BPT; 337 ptr->u.bptaddr = ta->thread_bp_create_addr; 338 return (0); 339 case TD_DEATH: 340 ptr->type = NOTIFY_BPT; 341 ptr->u.bptaddr = ta->thread_bp_death_addr; 342 return (0); 343 default: 344 return (TD_ERR); 345 } 346 } 347 348 static td_err_e 349 pt_ta_set_event(const td_thragent_t *ta, td_thr_events_t *events) 350 { 351 td_thr_events_t mask; 352 int ret; 353 354 TDBG_FUNC(); 355 ret = ps_pread(ta->ph, ta->thread_event_mask_addr, &mask, 356 sizeof(mask)); 357 if (ret != 0) 358 return (P2T(ret)); 359 mask |= *events; 360 ret = ps_pwrite(ta->ph, ta->thread_event_mask_addr, &mask, 361 sizeof(mask)); 362 return (P2T(ret)); 363 } 364 365 static td_err_e 366 pt_ta_clear_event(const td_thragent_t *ta, td_thr_events_t *events) 367 { 368 td_thr_events_t mask; 369 int ret; 370 371 TDBG_FUNC(); 372 ret = ps_pread(ta->ph, ta->thread_event_mask_addr, &mask, 373 sizeof(mask)); 374 if (ret != 0) 375 return (P2T(ret)); 376 mask &= ~*events; 377 ret = ps_pwrite(ta->ph, ta->thread_event_mask_addr, &mask, 378 sizeof(mask)); 379 return (P2T(ret)); 380 } 381 382 static td_err_e 383 pt_ta_event_getmsg(const td_thragent_t *ta, td_event_msg_t *msg) 384 { 385 static td_thrhandle_t handle; 386 387 psaddr_t pt, pt_temp; 388 td_thr_events_e tmp; 389 long lwp; 390 int ret; 391 392 TDBG_FUNC(); 393 394 ret = ps_pread(ta->ph, ta->thread_last_event_addr, &pt, sizeof(pt)); 395 if (ret != 0) 396 return (P2T(ret)); 397 if (pt == NULL) 398 return (TD_NOMSG); 399 /* 400 * Take the event pointer, at the time, libthr only reports event 401 * once a time, so it is not a link list. 402 */ 403 pt_temp = NULL; 404 ps_pwrite(ta->ph, ta->thread_last_event_addr, &pt_temp, sizeof(pt_temp)); 405 406 /* Read event info */ 407 ret = ps_pread(ta->ph, pt + ta->thread_off_event_buf, msg, sizeof(*msg)); 408 if (ret != 0) 409 return (P2T(ret)); 410 if (msg->event == 0) 411 return (TD_NOMSG); 412 /* Clear event */ 413 tmp = 0; 414 ps_pwrite(ta->ph, pt + ta->thread_off_event_buf, &tmp, sizeof(tmp)); 415 /* Convert event */ 416 pt = (psaddr_t)msg->th_p; 417 ret = ps_pread(ta->ph, pt + ta->thread_off_tid, &lwp, sizeof(lwp)); 418 if (ret != 0) 419 return (P2T(ret)); 420 handle.th_ta = ta; 421 handle.th_tid = lwp; 422 handle.th_thread = pt; 423 msg->th_p = &handle; 424 return (0); 425 } 426 427 static td_err_e 428 pt_dbsuspend(const td_thrhandle_t *th, int suspend) 429 { 430 td_thragent_t *ta = (td_thragent_t *)th->th_ta; 431 int ret; 432 433 TDBG_FUNC(); 434 435 ret = pt_validate(th); 436 if (ret) 437 return (ret); 438 439 if (suspend) 440 ret = ps_lstop(ta->ph, th->th_tid); 441 else 442 ret = ps_lcontinue(ta->ph, th->th_tid); 443 return (P2T(ret)); 444 } 445 446 static td_err_e 447 pt_thr_dbresume(const td_thrhandle_t *th) 448 { 449 TDBG_FUNC(); 450 451 return pt_dbsuspend(th, 0); 452 } 453 454 static td_err_e 455 pt_thr_dbsuspend(const td_thrhandle_t *th) 456 { 457 TDBG_FUNC(); 458 459 return pt_dbsuspend(th, 1); 460 } 461 462 static td_err_e 463 pt_thr_validate(const td_thrhandle_t *th) 464 { 465 td_thrhandle_t temp; 466 int ret; 467 468 TDBG_FUNC(); 469 470 ret = pt_ta_map_id2thr(th->th_ta, th->th_tid, &temp); 471 return (ret); 472 } 473 474 static td_err_e 475 pt_thr_get_info(const td_thrhandle_t *th, td_thrinfo_t *info) 476 { 477 const td_thragent_t *ta = th->th_ta; 478 int state; 479 int ret; 480 481 TDBG_FUNC(); 482 483 ret = pt_validate(th); 484 if (ret) 485 return (ret); 486 ret = ps_pread(ta->ph, th->th_thread + ta->thread_off_state, 487 &state, sizeof(state)); 488 if (ret != 0) 489 return (P2T(ret)); 490 ret = ps_pread(ta->ph, th->th_thread + ta->thread_off_report_events, 491 &info->ti_traceme, sizeof(int)); 492 if (ret != 0) 493 return (P2T(ret)); 494 ret = ps_pread(ta->ph, th->th_thread + ta->thread_off_event_mask, 495 &info->ti_events, sizeof(td_thr_events_t)); 496 if (ret != 0) 497 return (P2T(ret)); 498 ret = ps_pread(ta->ph, th->th_thread + ta->thread_off_tcb, 499 &info->ti_tls, sizeof(void *)); 500 info->ti_lid = th->th_tid; 501 info->ti_tid = th->th_tid; 502 info->ti_thread = th->th_thread; 503 info->ti_ta_p = th->th_ta; 504 if (state == ta->thread_state_running) 505 info->ti_state = TD_THR_RUN; 506 else if (state == ta->thread_state_zoombie) 507 info->ti_state = TD_THR_ZOMBIE; 508 else 509 info->ti_state = TD_THR_SLEEP; 510 info->ti_type = TD_THR_USER; 511 return (0); 512 } 513 514 static td_err_e 515 pt_thr_getfpregs(const td_thrhandle_t *th, prfpregset_t *fpregs) 516 { 517 const td_thragent_t *ta = th->th_ta; 518 int ret; 519 520 TDBG_FUNC(); 521 522 ret = pt_validate(th); 523 if (ret) 524 return (ret); 525 526 ret = ps_lgetfpregs(ta->ph, th->th_tid, fpregs); 527 return (P2T(ret)); 528 } 529 530 static td_err_e 531 pt_thr_getgregs(const td_thrhandle_t *th, prgregset_t gregs) 532 { 533 const td_thragent_t *ta = th->th_ta; 534 int ret; 535 536 TDBG_FUNC(); 537 538 ret = pt_validate(th); 539 if (ret) 540 return (ret); 541 542 ret = ps_lgetregs(ta->ph, th->th_tid, gregs); 543 return (P2T(ret)); 544 } 545 546 static td_err_e 547 pt_thr_setfpregs(const td_thrhandle_t *th, const prfpregset_t *fpregs) 548 { 549 const td_thragent_t *ta = th->th_ta; 550 int ret; 551 552 TDBG_FUNC(); 553 554 ret = pt_validate(th); 555 if (ret) 556 return (ret); 557 558 ret = ps_lsetfpregs(ta->ph, th->th_tid, fpregs); 559 return (P2T(ret)); 560 } 561 562 static td_err_e 563 pt_thr_setgregs(const td_thrhandle_t *th, const prgregset_t gregs) 564 { 565 const td_thragent_t *ta = th->th_ta; 566 int ret; 567 568 TDBG_FUNC(); 569 570 ret = pt_validate(th); 571 if (ret) 572 return (ret); 573 574 ret = ps_lsetregs(ta->ph, th->th_tid, gregs); 575 return (P2T(ret)); 576 } 577 578 static td_err_e 579 pt_thr_event_enable(const td_thrhandle_t *th, int en) 580 { 581 const td_thragent_t *ta = th->th_ta; 582 int ret; 583 584 TDBG_FUNC(); 585 ret = ps_pwrite(ta->ph, th->th_thread + ta->thread_off_report_events, 586 &en, sizeof(int)); 587 return (P2T(ret)); 588 } 589 590 static td_err_e 591 pt_thr_set_event(const td_thrhandle_t *th, td_thr_events_t *setp) 592 { 593 const td_thragent_t *ta = th->th_ta; 594 td_thr_events_t mask; 595 int ret; 596 597 TDBG_FUNC(); 598 ret = ps_pread(ta->ph, th->th_thread + ta->thread_off_event_mask, 599 &mask, sizeof(mask)); 600 mask |= *setp; 601 ret = ps_pwrite(ta->ph, th->th_thread + ta->thread_off_event_mask, 602 &mask, sizeof(mask)); 603 return (P2T(ret)); 604 } 605 606 static td_err_e 607 pt_thr_clear_event(const td_thrhandle_t *th, td_thr_events_t *setp) 608 { 609 const td_thragent_t *ta = th->th_ta; 610 td_thr_events_t mask; 611 int ret; 612 613 TDBG_FUNC(); 614 ret = ps_pread(ta->ph, th->th_thread + ta->thread_off_event_mask, 615 &mask, sizeof(mask)); 616 mask &= ~*setp; 617 ret = ps_pwrite(ta->ph, th->th_thread + ta->thread_off_event_mask, 618 &mask, sizeof(mask)); 619 return (P2T(ret)); 620 } 621 622 static td_err_e 623 pt_thr_event_getmsg(const td_thrhandle_t *th, td_event_msg_t *msg) 624 { 625 static td_thrhandle_t handle; 626 td_thragent_t *ta = (td_thragent_t *)th->th_ta; 627 psaddr_t pt, pt_temp; 628 long lwp; 629 int ret; 630 td_thr_events_e tmp; 631 632 TDBG_FUNC(); 633 pt = th->th_thread; 634 ret = ps_pread(ta->ph, ta->thread_last_event_addr, &pt_temp, sizeof(pt_temp)); 635 if (ret != 0) 636 return (P2T(ret)); 637 /* Get event */ 638 ret = ps_pread(ta->ph, pt + ta->thread_off_event_buf, msg, sizeof(*msg)); 639 if (ret != 0) 640 return (P2T(ret)); 641 if (msg->event == 0) 642 return (TD_NOMSG); 643 /* 644 * Take the event pointer, at the time, libthr only reports event 645 * once a time, so it is not a link list. 646 */ 647 if (pt == pt_temp) { 648 pt_temp = NULL; 649 ps_pwrite(ta->ph, ta->thread_last_event_addr, &pt_temp, sizeof(pt_temp)); 650 } 651 /* Clear event */ 652 tmp = 0; 653 ps_pwrite(ta->ph, pt + ta->thread_off_event_buf, &tmp, sizeof(tmp)); 654 /* Convert event */ 655 pt = (psaddr_t)msg->th_p; 656 ret = ps_pread(ta->ph, pt + ta->thread_off_tid, &lwp, sizeof(lwp)); 657 if (ret != 0) 658 return (P2T(ret)); 659 handle.th_ta = ta; 660 handle.th_tid = lwp; 661 handle.th_thread = pt; 662 msg->th_p = &handle; 663 return (0); 664 } 665 666 static int 667 pt_validate(const td_thrhandle_t *th) 668 { 669 670 if (th->th_tid == 0 || th->th_thread == NULL) 671 return (TD_ERR); 672 return (TD_OK); 673 } 674 675 static td_err_e 676 pt_thr_tls_get_addr(const td_thrhandle_t *th, void *_linkmap, size_t offset, 677 void **address) 678 { 679 char *obj_entry; 680 const td_thragent_t *ta = th->th_ta; 681 psaddr_t tcb_addr, *dtv_addr, tcb_tp; 682 int tls_index, ret; 683 684 /* linkmap is a member of Obj_Entry */ 685 obj_entry = (char *)_linkmap - ta->thread_off_linkmap; 686 687 /* get tlsindex of the object file */ 688 ret = ps_pread(ta->ph, 689 obj_entry + ta->thread_off_tlsindex, 690 &tls_index, sizeof(tls_index)); 691 if (ret != 0) 692 return (P2T(ret)); 693 694 /* get thread tcb */ 695 ret = ps_pread(ta->ph, th->th_thread + ta->thread_off_tcb, 696 &tcb_addr, sizeof(tcb_addr)); 697 if (ret != 0) 698 return (P2T(ret)); 699 700 /* get dtv array address */ 701 ret = ps_pread(ta->ph, tcb_addr + ta->thread_off_dtv, 702 &dtv_addr, sizeof(dtv_addr)); 703 if (ret != 0) 704 return (P2T(ret)); 705 /* now get the object's tls block base address */ 706 ret = ps_pread(ta->ph, &dtv_addr[tls_index+1], address, 707 sizeof(*address)); 708 if (ret != 0) 709 return (P2T(ret)); 710 711 *address += offset; 712 return (TD_OK); 713 } 714 715 struct ta_ops libthread_xu_ops = { 716 .to_init = pt_init, 717 .to_ta_clear_event = pt_ta_clear_event, 718 .to_ta_delete = pt_ta_delete, 719 .to_ta_event_addr = pt_ta_event_addr, 720 .to_ta_event_getmsg = pt_ta_event_getmsg, 721 .to_ta_map_id2thr = pt_ta_map_id2thr, 722 .to_ta_map_lwp2thr = pt_ta_map_lwp2thr, 723 .to_ta_new = pt_ta_new, 724 .to_ta_set_event = pt_ta_set_event, 725 .to_ta_thr_iter = pt_ta_thr_iter, 726 .to_ta_tsd_iter = pt_ta_tsd_iter, 727 .to_thr_clear_event = pt_thr_clear_event, 728 .to_thr_dbresume = pt_thr_dbresume, 729 .to_thr_dbsuspend = pt_thr_dbsuspend, 730 .to_thr_event_enable = pt_thr_event_enable, 731 .to_thr_event_getmsg = pt_thr_event_getmsg, 732 .to_thr_get_info = pt_thr_get_info, 733 .to_thr_getfpregs = pt_thr_getfpregs, 734 .to_thr_getgregs = pt_thr_getgregs, 735 .to_thr_set_event = pt_thr_set_event, 736 .to_thr_setfpregs = pt_thr_setfpregs, 737 .to_thr_setgregs = pt_thr_setgregs, 738 .to_thr_validate = pt_thr_validate, 739 .to_thr_tls_get_addr = pt_thr_tls_get_addr, 740 }; 741