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 180982 2008-07-30 00:59:19Z marcel $");
|
29__FBSDID("$FreeBSD: head/lib/libthread_db/libthr_db.c 181341 2008-08-06 03:14:18Z marcel $"); |
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 45struct 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 76static int pt_validate(const td_thrhandle_t *th); 77 78static int 79ps2td(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 101static td_err_e 102pt_init(void) 103{ 104 return (0); 105} 106 107static td_err_e 108pt_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 179error: 180 free(ta); 181 return (ret); 182} 183 184static td_err_e 185pt_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 201static td_err_e 202pt_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 != 0) { 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 == 0) 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 241static td_err_e 242pt_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 247static td_err_e
|
248pt_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)
|
248pt_ta_thr_iter(const td_thragent_t *ta, td_thr_iter_f *callback, 249 void *cbdata_p, td_thr_state_e state __unused, int ti_pri __unused, 250 sigset_t *ti_sigmask_p __unused, unsigned int ti_user_flags __unused) |
251{ 252 TAILQ_HEAD(, pthread) thread_list; 253 td_thrhandle_t th; 254 psaddr_t pt; 255 long lwp; 256 int ret; 257 258 TDBG_FUNC(); 259 260 ret = ps_pread(ta->ph, ta->thread_list_addr, &thread_list, 261 sizeof(thread_list)); 262 if (ret != 0) 263 return (P2T(ret)); 264 pt = (psaddr_t)thread_list.tqh_first; 265 while (pt != 0) { 266 ret = ps_pread(ta->ph, pt + ta->thread_off_tid, &lwp, 267 sizeof(lwp)); 268 if (ret != 0) 269 return (P2T(ret)); 270 if (lwp != 0 && lwp != TERMINATED) { 271 th.th_ta = ta; 272 th.th_tid = (thread_t)lwp; 273 th.th_thread = pt; 274 if ((*callback)(&th, cbdata_p)) 275 return (TD_DBERR); 276 } 277 /* get next thread */ 278 ret = ps_pread(ta->ph, pt + ta->thread_off_next, &pt, 279 sizeof(pt)); 280 if (ret != 0) 281 return (P2T(ret)); 282 } 283 return (TD_OK); 284} 285 286static td_err_e 287pt_ta_tsd_iter(const td_thragent_t *ta, td_key_iter_f *ki, void *arg) 288{
|
291 char *keytable;
|
289 void *keytable; |
290 void *destructor; 291 int i, ret, allocated; 292 293 TDBG_FUNC(); 294 295 keytable = malloc(ta->thread_max_keys * ta->thread_size_key); 296 if (keytable == NULL) 297 return (TD_MALLOC); 298 ret = ps_pread(ta->ph, (psaddr_t)ta->thread_keytable_addr, keytable, 299 ta->thread_max_keys * ta->thread_size_key); 300 if (ret != 0) { 301 free(keytable); 302 return (P2T(ret)); 303 } 304 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);
|
305 allocated = *(int *)(void *)((uintptr_t)keytable + 306 i * ta->thread_size_key + ta->thread_off_key_allocated); 307 destructor = *(void **)(void *)((uintptr_t)keytable + 308 i * ta->thread_size_key + ta->thread_off_key_destructor); |
309 if (allocated) { 310 ret = (ki)(i, destructor, arg); 311 if (ret != 0) { 312 free(keytable); 313 return (TD_DBERR); 314 } 315 } 316 } 317 free(keytable); 318 return (TD_OK); 319} 320 321static td_err_e 322pt_ta_event_addr(const td_thragent_t *ta, td_event_e event, td_notify_t *ptr) 323{ 324 325 TDBG_FUNC(); 326 327 switch (event) { 328 case TD_CREATE: 329 ptr->type = NOTIFY_BPT; 330 ptr->u.bptaddr = ta->thread_bp_create_addr; 331 return (0); 332 case TD_DEATH: 333 ptr->type = NOTIFY_BPT; 334 ptr->u.bptaddr = ta->thread_bp_death_addr; 335 return (0); 336 default: 337 return (TD_ERR); 338 } 339} 340 341static td_err_e 342pt_ta_set_event(const td_thragent_t *ta, td_thr_events_t *events) 343{ 344 td_thr_events_t mask; 345 int ret; 346 347 TDBG_FUNC(); 348 ret = ps_pread(ta->ph, ta->thread_event_mask_addr, &mask, 349 sizeof(mask)); 350 if (ret != 0) 351 return (P2T(ret)); 352 mask |= *events; 353 ret = ps_pwrite(ta->ph, ta->thread_event_mask_addr, &mask, 354 sizeof(mask)); 355 return (P2T(ret)); 356} 357 358static td_err_e 359pt_ta_clear_event(const td_thragent_t *ta, td_thr_events_t *events) 360{ 361 td_thr_events_t mask; 362 int ret; 363 364 TDBG_FUNC(); 365 ret = ps_pread(ta->ph, ta->thread_event_mask_addr, &mask, 366 sizeof(mask)); 367 if (ret != 0) 368 return (P2T(ret)); 369 mask &= ~*events; 370 ret = ps_pwrite(ta->ph, ta->thread_event_mask_addr, &mask, 371 sizeof(mask)); 372 return (P2T(ret)); 373} 374 375static td_err_e 376pt_ta_event_getmsg(const td_thragent_t *ta, td_event_msg_t *msg) 377{ 378 static td_thrhandle_t handle; 379 380 psaddr_t pt, pt_temp; 381 td_thr_events_e tmp; 382 long lwp; 383 int ret; 384 385 TDBG_FUNC(); 386 387 ret = ps_pread(ta->ph, ta->thread_last_event_addr, &pt, sizeof(pt)); 388 if (ret != 0) 389 return (P2T(ret)); 390 if (pt == 0) 391 return (TD_NOMSG); 392 /* 393 * Take the event pointer, at the time, libthr only reports event 394 * once a time, so it is not a link list. 395 */ 396 pt_temp = 0; 397 ps_pwrite(ta->ph, ta->thread_last_event_addr, &pt_temp, sizeof(pt_temp)); 398 399 /* Read event info */ 400 ret = ps_pread(ta->ph, pt + ta->thread_off_event_buf, msg, sizeof(*msg)); 401 if (ret != 0) 402 return (P2T(ret)); 403 if (msg->event == 0) 404 return (TD_NOMSG); 405 /* Clear event */ 406 tmp = 0; 407 ps_pwrite(ta->ph, pt + ta->thread_off_event_buf, &tmp, sizeof(tmp)); 408 /* Convert event */ 409 pt = (psaddr_t)msg->th_p; 410 ret = ps_pread(ta->ph, pt + ta->thread_off_tid, &lwp, sizeof(lwp)); 411 if (ret != 0) 412 return (P2T(ret)); 413 handle.th_ta = ta; 414 handle.th_tid = lwp; 415 handle.th_thread = pt; 416 msg->th_p = &handle; 417 return (0); 418} 419 420static td_err_e 421pt_dbsuspend(const td_thrhandle_t *th, int suspend) 422{
|
425 td_thragent_t *ta = (td_thragent_t *)th->th_ta;
|
423 const td_thragent_t *ta = th->th_ta; |
424 int ret; 425 426 TDBG_FUNC(); 427 428 ret = pt_validate(th); 429 if (ret) 430 return (ret); 431 432 if (suspend) 433 ret = ps_lstop(ta->ph, th->th_tid); 434 else 435 ret = ps_lcontinue(ta->ph, th->th_tid); 436 return (P2T(ret)); 437} 438 439static td_err_e 440pt_thr_dbresume(const td_thrhandle_t *th) 441{ 442 TDBG_FUNC(); 443 444 return pt_dbsuspend(th, 0); 445} 446 447static td_err_e 448pt_thr_dbsuspend(const td_thrhandle_t *th) 449{ 450 TDBG_FUNC(); 451 452 return pt_dbsuspend(th, 1); 453} 454 455static td_err_e 456pt_thr_validate(const td_thrhandle_t *th) 457{ 458 td_thrhandle_t temp; 459 int ret; 460 461 TDBG_FUNC(); 462 463 ret = pt_ta_map_id2thr(th->th_ta, th->th_tid, &temp); 464 return (ret); 465} 466 467static td_err_e 468pt_thr_get_info(const td_thrhandle_t *th, td_thrinfo_t *info) 469{ 470 const td_thragent_t *ta = th->th_ta; 471 struct ptrace_lwpinfo linfo; 472 int state; 473 int ret; 474 475 TDBG_FUNC(); 476 477 bzero(info, sizeof(*info)); 478 ret = pt_validate(th); 479 if (ret) 480 return (ret); 481 ret = ps_pread(ta->ph, th->th_thread + ta->thread_off_state, 482 &state, sizeof(state)); 483 if (ret != 0) 484 return (P2T(ret)); 485 ret = ps_pread(ta->ph, th->th_thread + ta->thread_off_report_events, 486 &info->ti_traceme, sizeof(int)); 487 if (ret != 0) 488 return (P2T(ret)); 489 ret = ps_pread(ta->ph, th->th_thread + ta->thread_off_event_mask, 490 &info->ti_events, sizeof(td_thr_events_t)); 491 if (ret != 0) 492 return (P2T(ret)); 493 ret = ps_pread(ta->ph, th->th_thread + ta->thread_off_tcb, 494 &info->ti_tls, sizeof(void *)); 495 info->ti_lid = th->th_tid; 496 info->ti_tid = th->th_tid; 497 info->ti_thread = th->th_thread; 498 info->ti_ta_p = th->th_ta; 499 ret = ps_linfo(ta->ph, th->th_tid, &linfo); 500 if (ret == PS_OK) { 501 info->ti_sigmask = linfo.pl_sigmask; 502 info->ti_pending = linfo.pl_siglist; 503 } else 504 return (ret); 505 if (state == ta->thread_state_running) 506 info->ti_state = TD_THR_RUN; 507 else if (state == ta->thread_state_zoombie) 508 info->ti_state = TD_THR_ZOMBIE; 509 else 510 info->ti_state = TD_THR_SLEEP; 511 info->ti_type = TD_THR_USER; 512 return (0); 513} 514 515#ifdef __i386__ 516static td_err_e 517pt_thr_getxmmregs(const td_thrhandle_t *th, char *fxsave) 518{ 519 const td_thragent_t *ta = th->th_ta; 520 int ret; 521 522 TDBG_FUNC(); 523 524 ret = pt_validate(th); 525 if (ret) 526 return (ret); 527 528 ret = ps_lgetxmmregs(ta->ph, th->th_tid, fxsave); 529 return (P2T(ret)); 530} 531#endif 532 533static td_err_e 534pt_thr_getfpregs(const td_thrhandle_t *th, prfpregset_t *fpregs) 535{ 536 const td_thragent_t *ta = th->th_ta; 537 int ret; 538 539 TDBG_FUNC(); 540 541 ret = pt_validate(th); 542 if (ret) 543 return (ret); 544 545 ret = ps_lgetfpregs(ta->ph, th->th_tid, fpregs); 546 return (P2T(ret)); 547} 548 549static td_err_e 550pt_thr_getgregs(const td_thrhandle_t *th, prgregset_t gregs) 551{ 552 const td_thragent_t *ta = th->th_ta; 553 int ret; 554 555 TDBG_FUNC(); 556 557 ret = pt_validate(th); 558 if (ret) 559 return (ret); 560 561 ret = ps_lgetregs(ta->ph, th->th_tid, gregs); 562 return (P2T(ret)); 563} 564 565#ifdef __i386__ 566static td_err_e 567pt_thr_setxmmregs(const td_thrhandle_t *th, const char *fxsave) 568{ 569 const td_thragent_t *ta = th->th_ta; 570 int ret; 571 572 TDBG_FUNC(); 573 574 ret = pt_validate(th); 575 if (ret) 576 return (ret); 577 578 ret = ps_lsetxmmregs(ta->ph, th->th_tid, fxsave); 579 return (P2T(ret)); 580} 581#endif 582 583static td_err_e 584pt_thr_setfpregs(const td_thrhandle_t *th, const prfpregset_t *fpregs) 585{ 586 const td_thragent_t *ta = th->th_ta; 587 int ret; 588 589 TDBG_FUNC(); 590 591 ret = pt_validate(th); 592 if (ret) 593 return (ret); 594 595 ret = ps_lsetfpregs(ta->ph, th->th_tid, fpregs); 596 return (P2T(ret)); 597} 598 599static td_err_e 600pt_thr_setgregs(const td_thrhandle_t *th, const prgregset_t gregs) 601{ 602 const td_thragent_t *ta = th->th_ta; 603 int ret; 604 605 TDBG_FUNC(); 606 607 ret = pt_validate(th); 608 if (ret) 609 return (ret); 610 611 ret = ps_lsetregs(ta->ph, th->th_tid, gregs); 612 return (P2T(ret)); 613} 614 615static td_err_e 616pt_thr_event_enable(const td_thrhandle_t *th, int en) 617{ 618 const td_thragent_t *ta = th->th_ta; 619 int ret; 620 621 TDBG_FUNC(); 622 ret = ps_pwrite(ta->ph, th->th_thread + ta->thread_off_report_events, 623 &en, sizeof(int)); 624 return (P2T(ret)); 625} 626 627static td_err_e 628pt_thr_set_event(const td_thrhandle_t *th, td_thr_events_t *setp) 629{ 630 const td_thragent_t *ta = th->th_ta; 631 td_thr_events_t mask; 632 int ret; 633 634 TDBG_FUNC(); 635 ret = ps_pread(ta->ph, th->th_thread + ta->thread_off_event_mask, 636 &mask, sizeof(mask)); 637 mask |= *setp; 638 ret = ps_pwrite(ta->ph, th->th_thread + ta->thread_off_event_mask, 639 &mask, sizeof(mask)); 640 return (P2T(ret)); 641} 642 643static td_err_e 644pt_thr_clear_event(const td_thrhandle_t *th, td_thr_events_t *setp) 645{ 646 const td_thragent_t *ta = th->th_ta; 647 td_thr_events_t mask; 648 int ret; 649 650 TDBG_FUNC(); 651 ret = ps_pread(ta->ph, th->th_thread + ta->thread_off_event_mask, 652 &mask, sizeof(mask)); 653 mask &= ~*setp; 654 ret = ps_pwrite(ta->ph, th->th_thread + ta->thread_off_event_mask, 655 &mask, sizeof(mask)); 656 return (P2T(ret)); 657} 658 659static td_err_e 660pt_thr_event_getmsg(const td_thrhandle_t *th, td_event_msg_t *msg) 661{ 662 static td_thrhandle_t handle;
|
665 td_thragent_t *ta = (td_thragent_t *)th->th_ta;
|
663 const td_thragent_t *ta = th->th_ta; |
664 psaddr_t pt, pt_temp; 665 long lwp; 666 int ret; 667 td_thr_events_e tmp; 668 669 TDBG_FUNC(); 670 pt = th->th_thread; 671 ret = ps_pread(ta->ph, ta->thread_last_event_addr, &pt_temp, sizeof(pt_temp)); 672 if (ret != 0) 673 return (P2T(ret)); 674 /* Get event */ 675 ret = ps_pread(ta->ph, pt + ta->thread_off_event_buf, msg, sizeof(*msg)); 676 if (ret != 0) 677 return (P2T(ret)); 678 if (msg->event == 0) 679 return (TD_NOMSG); 680 /* 681 * Take the event pointer, at the time, libthr only reports event 682 * once a time, so it is not a link list. 683 */ 684 if (pt == pt_temp) { 685 pt_temp = 0; 686 ps_pwrite(ta->ph, ta->thread_last_event_addr, &pt_temp, sizeof(pt_temp)); 687 } 688 /* Clear event */ 689 tmp = 0; 690 ps_pwrite(ta->ph, pt + ta->thread_off_event_buf, &tmp, sizeof(tmp)); 691 /* Convert event */ 692 pt = (psaddr_t)msg->th_p; 693 ret = ps_pread(ta->ph, pt + ta->thread_off_tid, &lwp, sizeof(lwp)); 694 if (ret != 0) 695 return (P2T(ret)); 696 handle.th_ta = ta; 697 handle.th_tid = lwp; 698 handle.th_thread = pt; 699 msg->th_p = &handle; 700 return (0); 701} 702 703static td_err_e
|
706pt_thr_sstep(const td_thrhandle_t *th, int step)
|
704pt_thr_sstep(const td_thrhandle_t *th, int step __unused) |
705{ 706 TDBG_FUNC(); 707 708 return pt_validate(th); 709} 710 711static int 712pt_validate(const td_thrhandle_t *th) 713{ 714 715 if (th->th_tid == 0 || th->th_thread == 0) 716 return (TD_ERR); 717 return (TD_OK); 718} 719 720static td_err_e 721pt_thr_tls_get_addr(const td_thrhandle_t *th, psaddr_t _linkmap, size_t offset, 722 psaddr_t *address) 723{ 724 const td_thragent_t *ta = th->th_ta; 725 psaddr_t dtv_addr, obj_entry, tcb_addr; 726 int tls_index, ret; 727 728 /* linkmap is a member of Obj_Entry */ 729 obj_entry = _linkmap - ta->thread_off_linkmap; 730 731 /* get tlsindex of the object file */ 732 ret = ps_pread(ta->ph, 733 obj_entry + ta->thread_off_tlsindex, 734 &tls_index, sizeof(tls_index)); 735 if (ret != 0) 736 return (P2T(ret)); 737 738 /* get thread tcb */ 739 ret = ps_pread(ta->ph, th->th_thread + ta->thread_off_tcb, 740 &tcb_addr, sizeof(tcb_addr)); 741 if (ret != 0) 742 return (P2T(ret)); 743 744 /* get dtv array address */ 745 ret = ps_pread(ta->ph, tcb_addr + ta->thread_off_dtv, 746 &dtv_addr, sizeof(dtv_addr)); 747 if (ret != 0) 748 return (P2T(ret)); 749 /* now get the object's tls block base address */ 750 ret = ps_pread(ta->ph, dtv_addr + sizeof(void *) * (tls_index+1), 751 address, sizeof(*address)); 752 if (ret != 0) 753 return (P2T(ret)); 754 755 *address += offset; 756 return (TD_OK); 757} 758 759struct ta_ops libthr_db_ops = { 760 .to_init = pt_init, 761 .to_ta_clear_event = pt_ta_clear_event, 762 .to_ta_delete = pt_ta_delete, 763 .to_ta_event_addr = pt_ta_event_addr, 764 .to_ta_event_getmsg = pt_ta_event_getmsg, 765 .to_ta_map_id2thr = pt_ta_map_id2thr, 766 .to_ta_map_lwp2thr = pt_ta_map_lwp2thr, 767 .to_ta_new = pt_ta_new, 768 .to_ta_set_event = pt_ta_set_event, 769 .to_ta_thr_iter = pt_ta_thr_iter, 770 .to_ta_tsd_iter = pt_ta_tsd_iter, 771 .to_thr_clear_event = pt_thr_clear_event, 772 .to_thr_dbresume = pt_thr_dbresume, 773 .to_thr_dbsuspend = pt_thr_dbsuspend, 774 .to_thr_event_enable = pt_thr_event_enable, 775 .to_thr_event_getmsg = pt_thr_event_getmsg, 776 .to_thr_get_info = pt_thr_get_info, 777 .to_thr_getfpregs = pt_thr_getfpregs, 778 .to_thr_getgregs = pt_thr_getgregs, 779 .to_thr_set_event = pt_thr_set_event, 780 .to_thr_setfpregs = pt_thr_setfpregs, 781 .to_thr_setgregs = pt_thr_setgregs, 782 .to_thr_validate = pt_thr_validate, 783 .to_thr_tls_get_addr = pt_thr_tls_get_addr, 784 785 /* FreeBSD specific extensions. */ 786 .to_thr_sstep = pt_thr_sstep, 787#ifdef __i386__ 788 .to_thr_getxmmregs = pt_thr_getxmmregs, 789 .to_thr_setxmmregs = pt_thr_setxmmregs, 790#endif 791}; 792 793DATA_SET(__ta_ops, libthr_db_ops);
|