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