libpthread_db.c revision 144663
1158559Snyan/* 2158559Snyan * Copyright (c) 2004 David Xu <davidxu@freebsd.org> 3158559Snyan * All rights reserved. 4158559Snyan * 5158559Snyan * Redistribution and use in source and binary forms, with or without 6158559Snyan * modification, are permitted provided that the following conditions 7158559Snyan * are met: 8158559Snyan * 1. Redistributions of source code must retain the above copyright 9158559Snyan * notice, this list of conditions and the following disclaimer. 10158559Snyan * 2. Redistributions in binary form must reproduce the above copyright 11158559Snyan * notice, this list of conditions and the following disclaimer in the 12158559Snyan * documentation and/or other materials provided with the distribution. 13158559Snyan * 14158559Snyan * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15158559Snyan * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16158559Snyan * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17158559Snyan * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18158559Snyan * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19158559Snyan * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20158559Snyan * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21158559Snyan * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22158559Snyan * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23158559Snyan * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24158559Snyan * SUCH DAMAGE. 25158559Snyan */ 26158559Snyan 27158559Snyan#include <sys/cdefs.h> 28158559Snyan__FBSDID("$FreeBSD: head/lib/libthread_db/libpthread_db.c 144663 2005-04-05 11:38:30Z davidxu $"); 29158559Snyan 30158559Snyan#include <stddef.h> 31158559Snyan#include <stdlib.h> 32158559Snyan#include <string.h> 33158559Snyan#include <unistd.h> 34158559Snyan#include <pthread.h> 35158559Snyan#include <sys/types.h> 36158559Snyan#include <sys/kse.h> 37158559Snyan#include <sys/ptrace.h> 38158559Snyan#include <proc_service.h> 39158559Snyan#include <thread_db.h> 40158559Snyan 41158559Snyan#include "libpthread_db.h" 42158559Snyan 43158559Snyan#define P2T(c) ps2td(c) 44158559Snyan 45158559Snyanstatic void pt_unmap_lwp(const td_thragent_t *ta, lwpid_t lwp); 46158559Snyanstatic int pt_validate(const td_thrhandle_t *th); 47158559Snyan 48158559Snyanstatic int 49158559Snyanps2td(int c) 50158559Snyan{ 51158559Snyan switch (c) { 52158559Snyan case PS_OK: 53158559Snyan return TD_OK; 54158559Snyan case PS_ERR: 55158559Snyan return TD_ERR; 56158559Snyan case PS_BADPID: 57158559Snyan return TD_BADPH; 58158559Snyan case PS_BADLID: 59158559Snyan return TD_NOLWP; 60158559Snyan case PS_BADADDR: 61158559Snyan return TD_ERR; 62158559Snyan case PS_NOSYM: 63158559Snyan return TD_NOLIBTHREAD; 64158559Snyan case PS_NOFREGS: 65158559Snyan return TD_NOFPREGS; 66158559Snyan default: 67158559Snyan return TD_ERR; 68158559Snyan } 69158559Snyan} 70158559Snyan 71158559Snyanstatic long 72158559Snyanpt_map_thread(const td_thragent_t *const_ta, psaddr_t pt, int type) 73158559Snyan{ 74158559Snyan td_thragent_t *ta = __DECONST(td_thragent_t *, const_ta); 75158559Snyan struct pt_map *new; 76158559Snyan int i, first = -1; 77158559Snyan 78158559Snyan /* leave zero out */ 79158559Snyan for (i = 1; i < ta->map_len; ++i) { 80158559Snyan if (ta->map[i].type == PT_NONE) { 81158559Snyan if (first == -1) 82158559Snyan first = i; 83158559Snyan } else if (ta->map[i].type == type && ta->map[i].thr == pt) { 84158559Snyan return (i); 85158559Snyan } 86158559Snyan } 87158559Snyan 88158559Snyan if (first == -1) { 89158559Snyan if (ta->map_len == 0) { 90158559Snyan ta->map = calloc(20, sizeof(struct pt_map)); 91158559Snyan if (ta->map == NULL) 92158559Snyan return (-1); 93158559Snyan ta->map_len = 20; 94158559Snyan first = 1; 95158559Snyan } else { 96158559Snyan new = realloc(ta->map, 97158559Snyan sizeof(struct pt_map) * ta->map_len * 2); 98158559Snyan if (new == NULL) 99158559Snyan return (-1); 100158559Snyan memset(new + ta->map_len, '\0', sizeof(struct pt_map) * 101158559Snyan ta->map_len); 102158559Snyan first = ta->map_len; 103158559Snyan ta->map = new; 104158559Snyan ta->map_len *= 2; 105158559Snyan } 106158559Snyan } 107158559Snyan 108158559Snyan ta->map[first].type = type; 109158559Snyan ta->map[first].thr = pt; 110158559Snyan return (first); 111158559Snyan} 112158559Snyan 113158559Snyanstatic td_err_e 114158559Snyanpt_init(void) 115158559Snyan{ 116158559Snyan pt_md_init(); 117158559Snyan return (0); 118158559Snyan} 119158559Snyan 120158559Snyanstatic td_err_e 121158559Snyanpt_ta_new(struct ps_prochandle *ph, td_thragent_t **pta) 122158559Snyan{ 123158559Snyan#define LOOKUP_SYM(proc, sym, addr) \ 124158559Snyan ret = ps_pglobal_lookup(proc, NULL, sym, addr); \ 125158559Snyan if (ret != 0) { \ 126158559Snyan TDBG("can not find symbol: %s\n", sym); \ 127158559Snyan ret = TD_NOLIBTHREAD; \ 128158559Snyan goto error; \ 129158559Snyan } 130158559Snyan 131158559Snyan#define LOOKUP_VAL(proc, sym, val) \ 132158559Snyan ret = ps_pglobal_lookup(proc, NULL, sym, &vaddr);\ 133158559Snyan if (ret != 0) { \ 134158559Snyan TDBG("can not find symbol: %s\n", sym); \ 135158559Snyan ret = TD_NOLIBTHREAD; \ 136158559Snyan goto error; \ 137158559Snyan } \ 138158559Snyan ret = ps_pread(proc, vaddr, val, sizeof(int)); \ 139158559Snyan if (ret != 0) { \ 140158559Snyan TDBG("can not read value of %s\n", sym);\ 141158559Snyan ret = TD_NOLIBTHREAD; \ 142158559Snyan goto error; \ 143158559Snyan } 144158559Snyan 145158559Snyan td_thragent_t *ta; 146158559Snyan psaddr_t vaddr; 147158559Snyan int dbg; 148158559Snyan int ret; 149158559Snyan 150158559Snyan TDBG_FUNC(); 151158559Snyan 152158559Snyan ta = malloc(sizeof(td_thragent_t)); 153158559Snyan if (ta == NULL) 154158559Snyan return (TD_MALLOC); 155158559Snyan 156158559Snyan ta->ph = ph; 157158559Snyan ta->thread_activated = 0; 158158559Snyan ta->map = NULL; 159158559Snyan ta->map_len = 0; 160158559Snyan 161158559Snyan LOOKUP_SYM(ph, "_libkse_debug", &ta->libkse_debug_addr); 162158559Snyan LOOKUP_SYM(ph, "_thread_list", &ta->thread_list_addr); 163158559Snyan LOOKUP_SYM(ph, "_thread_activated", &ta->thread_activated_addr); 164158559Snyan LOOKUP_SYM(ph, "_thread_active_threads",&ta->thread_active_threads_addr); 165158559Snyan LOOKUP_SYM(ph, "_thread_keytable", &ta->thread_keytable_addr); 166158559Snyan LOOKUP_VAL(ph, "_thread_off_dtv", &ta->thread_off_dtv); 167158559Snyan LOOKUP_VAL(ph, "_thread_off_kse_locklevel", &ta->thread_off_kse_locklevel); 168158559Snyan LOOKUP_VAL(ph, "_thread_off_kse", &ta->thread_off_kse); 169158559Snyan LOOKUP_VAL(ph, "_thread_off_tlsindex", &ta->thread_off_tlsindex); 170158559Snyan LOOKUP_VAL(ph, "_thread_off_attr_flags", &ta->thread_off_attr_flags); 171158559Snyan LOOKUP_VAL(ph, "_thread_size_key", &ta->thread_size_key); 172190146Snyan LOOKUP_VAL(ph, "_thread_off_tcb", &ta->thread_off_tcb); 173158559Snyan LOOKUP_VAL(ph, "_thread_off_linkmap", &ta->thread_off_linkmap); 174190146Snyan LOOKUP_VAL(ph, "_thread_off_tmbx", &ta->thread_off_tmbx); 175158559Snyan LOOKUP_VAL(ph, "_thread_off_thr_locklevel", &ta->thread_off_thr_locklevel); 176158559Snyan LOOKUP_VAL(ph, "_thread_off_next", &ta->thread_off_next); 177158559Snyan LOOKUP_VAL(ph, "_thread_off_state", &ta->thread_off_state); 178158559Snyan LOOKUP_VAL(ph, "_thread_max_keys", &ta->thread_max_keys); 179158559Snyan LOOKUP_VAL(ph, "_thread_off_key_allocated", &ta->thread_off_key_allocated); 180158559Snyan LOOKUP_VAL(ph, "_thread_off_key_destructor", &ta->thread_off_key_destructor); 181158559Snyan LOOKUP_VAL(ph, "_thread_state_running", &ta->thread_state_running); 182158559Snyan LOOKUP_VAL(ph, "_thread_state_zoombie", &ta->thread_state_zoombie); 183158559Snyan dbg = getpid(); 184158559Snyan /* 185158559Snyan * If this fails it probably means we're debugging a core file and 186158559Snyan * can't write to it. 187158559Snyan */ 188158559Snyan ps_pwrite(ph, ta->libkse_debug_addr, &dbg, sizeof(int)); 189158559Snyan *pta = ta; 190158559Snyan return (0); 191158559Snyan 192158559Snyanerror: 193158559Snyan free(ta); 194163897Smarcel return (ret); 195158559Snyan} 196158559Snyan 197158559Snyanstatic td_err_e 198158559Snyanpt_ta_delete(td_thragent_t *ta) 199158559Snyan{ 200158559Snyan int dbg; 201158559Snyan 202158559Snyan TDBG_FUNC(); 203158559Snyan 204158559Snyan dbg = 0; 205158559Snyan /* 206158559Snyan * Error returns from this write are not really a problem; 207158559Snyan * the process doesn't exist any more. 208158559Snyan */ 209158559Snyan ps_pwrite(ta->ph, ta->libkse_debug_addr, &dbg, sizeof(int)); 210158559Snyan if (ta->map) 211158559Snyan free(ta->map); 212158559Snyan free(ta); 213158559Snyan return (TD_OK); 214158559Snyan} 215158559Snyan 216158559Snyanstatic td_err_e 217158559Snyanpt_ta_map_id2thr(const td_thragent_t *ta, thread_t id, td_thrhandle_t *th) 218158559Snyan{ 219158559Snyan prgregset_t gregs; 220158559Snyan TAILQ_HEAD(, pthread) thread_list; 221158559Snyan psaddr_t pt, tcb_addr; 222158559Snyan lwpid_t lwp; 223158559Snyan int ret; 224158559Snyan 225158559Snyan TDBG_FUNC(); 226158559Snyan 227158559Snyan if (id < 0 || id >= ta->map_len || ta->map[id].type == PT_NONE) 228158559Snyan return (TD_NOTHR); 229163897Smarcel ret = ps_pread(ta->ph, ta->thread_list_addr, &thread_list, 230158559Snyan sizeof(thread_list)); 231158559Snyan if (ret != 0) 232158559Snyan return (P2T(ret)); 233158559Snyan pt = (psaddr_t)thread_list.tqh_first; 234190146Snyan if (ta->map[id].type == PT_LWP) { 235158559Snyan /* 236158559Snyan * if we are referencing a lwp, make sure it was not already 237158559Snyan * mapped to user thread. 238158559Snyan */ 239158559Snyan while (pt != 0) { 240158559Snyan ret = ps_pread(ta->ph, 241158559Snyan pt + ta->thread_off_tcb, 242158559Snyan &tcb_addr, sizeof(tcb_addr)); 243190146Snyan if (ret != 0) 244158559Snyan return (P2T(ret)); 245190146Snyan ret = ps_pread(ta->ph, 246158559Snyan tcb_addr + ta->thread_off_tmbx + 247158559Snyan offsetof(struct kse_thr_mailbox, tm_lwp), 248158559Snyan &lwp, sizeof(lwp)); 249158559Snyan if (ret != 0) 250158559Snyan return (P2T(ret)); 251158559Snyan /* 252158559Snyan * If the lwp was already mapped to userland thread, 253158559Snyan * we shouldn't reference it directly in future. 254158559Snyan */ 255158559Snyan if (lwp == ta->map[id].lwp) { 256190146Snyan ta->map[id].type = PT_NONE; 257190146Snyan return (TD_NOTHR); 258190146Snyan } 259158559Snyan /* get next thread */ 260158559Snyan ret = ps_pread(ta->ph, 261158559Snyan pt + ta->thread_off_next, 262190146Snyan &pt, sizeof(pt)); 263190146Snyan if (ret != 0) 264158559Snyan return (P2T(ret)); 265158559Snyan } 266158559Snyan /* check lwp */ 267158559Snyan ret = ptrace(PT_GETREGS, ta->map[id].lwp, (caddr_t)&gregs, 0); 268158559Snyan if (ret != 0) { 269158559Snyan /* no longer exists */ 270158559Snyan ta->map[id].type = PT_NONE; 271158559Snyan return (TD_NOTHR); 272158559Snyan } 273158559Snyan } else { 274158559Snyan while (pt != 0 && ta->map[id].thr != pt) { 275158559Snyan ret = ps_pread(ta->ph, 276158559Snyan pt + ta->thread_off_tcb, 277190146Snyan &tcb_addr, sizeof(tcb_addr)); 278190146Snyan if (ret != 0) 279190146Snyan return (P2T(ret)); 280190146Snyan /* get next thread */ 281190146Snyan ret = ps_pread(ta->ph, 282190146Snyan pt + ta->thread_off_next, 283190146Snyan &pt, sizeof(pt)); 284190146Snyan if (ret != 0) 285190146Snyan return (P2T(ret)); 286190146Snyan } 287190146Snyan 288190146Snyan if (pt == 0) { 289190146Snyan /* no longer exists */ 290190146Snyan ta->map[id].type = PT_NONE; 291190146Snyan return (TD_NOTHR); 292158559Snyan } 293190146Snyan } 294190146Snyan th->th_ta = ta; 295190146Snyan th->th_tid = id; 296190146Snyan th->th_thread = pt; 297190146Snyan return (TD_OK); 298190146Snyan} 299190146Snyan 300190146Snyanstatic td_err_e 301190146Snyanpt_ta_map_lwp2thr(const td_thragent_t *ta, lwpid_t lwp, td_thrhandle_t *th) 302190146Snyan{ 303190146Snyan TAILQ_HEAD(, pthread) thread_list; 304190146Snyan psaddr_t pt, ptr; 305190146Snyan lwpid_t tmp_lwp; 306190146Snyan int ret; 307190146Snyan 308190146Snyan TDBG_FUNC(); 309190146Snyan 310190146Snyan ret = ps_pread(ta->ph, ta->thread_list_addr, &thread_list, 311190146Snyan sizeof(thread_list)); 312190146Snyan if (ret != 0) 313190146Snyan return (P2T(ret)); 314190146Snyan pt = (psaddr_t)thread_list.tqh_first; 315190146Snyan while (pt != 0) { 316190146Snyan ret = ps_pread(ta->ph, pt + ta->thread_off_tcb, 317190146Snyan &ptr, sizeof(ptr)); 318158559Snyan if (ret != 0) 319158559Snyan return (P2T(ret)); 320190146Snyan ptr += ta->thread_off_tmbx + 321190147Snyan offsetof(struct kse_thr_mailbox, tm_lwp); 322190146Snyan ret = ps_pread(ta->ph, ptr, &tmp_lwp, sizeof(lwpid_t)); 323190146Snyan if (ret != 0) 324190147Snyan return (P2T(ret)); 325190147Snyan if (tmp_lwp == lwp) { 326158559Snyan th->th_ta = ta; 327226746Sjhb th->th_tid = pt_map_thread(ta, pt, PT_USER); 328190146Snyan if (th->th_tid == -1) 329190146Snyan return (TD_MALLOC); 330158559Snyan pt_unmap_lwp(ta, lwp); 331158559Snyan th->th_thread = pt; 332158559Snyan return (TD_OK); 333190146Snyan } 334158559Snyan 335190146Snyan /* get next thread */ 336190146Snyan ret = ps_pread(ta->ph, 337190146Snyan pt + ta->thread_off_next, 338190146Snyan &pt, sizeof(pt)); 339190146Snyan if (ret != 0) 340190146Snyan return (P2T(ret)); 341190146Snyan } 342190146Snyan 343190146Snyan return (TD_NOTHR); 344158559Snyan} 345158559Snyan 346158559Snyanstatic td_err_e 347158559Snyanpt_ta_thr_iter(const td_thragent_t *ta, 348158559Snyan td_thr_iter_f *callback, void *cbdata_p, 349158559Snyan td_thr_state_e state, int ti_pri, 350158559Snyan sigset_t *ti_sigmask_p, 351158559Snyan unsigned int ti_user_flags) 352158559Snyan{ 353158559Snyan TAILQ_HEAD(, pthread) thread_list; 354158559Snyan td_thrhandle_t th; 355158559Snyan psaddr_t pt; 356158559Snyan ps_err_e pserr; 357158559Snyan int activated; 358158559Snyan 359163897Smarcel TDBG_FUNC(); 360158559Snyan 361158559Snyan pserr = ps_pread(ta->ph, ta->thread_activated_addr, &activated, 362158559Snyan sizeof(int)); 363158559Snyan if (pserr != PS_OK) 364158559Snyan return (P2T(pserr)); 365158559Snyan if (!activated) 366158559Snyan return (TD_OK); 367158559Snyan 368158559Snyan pserr = ps_pread(ta->ph, ta->thread_list_addr, &thread_list, 369158559Snyan sizeof(thread_list)); 370158559Snyan if (pserr != 0) 371158559Snyan return (P2T(pserr)); 372158559Snyan pt = (psaddr_t)thread_list.tqh_first; 373158559Snyan while (pt != 0) { 374158559Snyan th.th_ta = ta; 375158559Snyan th.th_tid = pt_map_thread(ta, pt, PT_USER); 376172921Sjhb th.th_thread = pt; 377158559Snyan /* should we unmap lwp here ? */ 378158559Snyan if (th.th_tid == -1) 379158559Snyan return (TD_MALLOC); 380 if ((*callback)(&th, cbdata_p)) 381 return (TD_DBERR); 382 /* get next thread */ 383 pserr = ps_pread(ta->ph, 384 pt + ta->thread_off_next, &pt, 385 sizeof(pt)); 386 if (pserr != PS_OK) 387 return (P2T(pserr)); 388 } 389 return (TD_OK); 390} 391 392static td_err_e 393pt_ta_tsd_iter(const td_thragent_t *ta, td_key_iter_f *ki, void *arg) 394{ 395 char *keytable; 396 void *destructor; 397 int i, ret, allocated; 398 399 TDBG_FUNC(); 400 401 keytable = malloc(ta->thread_max_keys * ta->thread_size_key); 402 if (keytable == NULL) 403 return (TD_MALLOC); 404 ret = ps_pread(ta->ph, (psaddr_t)ta->thread_keytable_addr, keytable, 405 ta->thread_max_keys * ta->thread_size_key); 406 if (ret != 0) { 407 free(keytable); 408 return (P2T(ret)); 409 } 410 for (i = 0; i < ta->thread_max_keys; i++) { 411 allocated = *(int *)(keytable + i * ta->thread_size_key + 412 ta->thread_off_key_allocated); 413 destructor = *(void **)(keytable + i * ta->thread_size_key + 414 ta->thread_off_key_destructor); 415 if (allocated) { 416 ret = (ki)(i, destructor, arg); 417 if (ret != 0) { 418 free(keytable); 419 return (TD_DBERR); 420 } 421 } 422 } 423 free(keytable); 424 return (TD_OK); 425} 426 427static td_err_e 428pt_ta_event_addr(const td_thragent_t *ta, td_event_e event, td_notify_t *ptr) 429{ 430 TDBG_FUNC(); 431 return (TD_NOEVENT); 432} 433 434static td_err_e 435pt_ta_set_event(const td_thragent_t *ta, td_thr_events_t *events) 436{ 437 TDBG_FUNC(); 438 return (TD_ERR); 439} 440 441static td_err_e 442pt_ta_clear_event(const td_thragent_t *ta, td_thr_events_t *events) 443{ 444 TDBG_FUNC(); 445 return (TD_ERR); 446} 447 448static td_err_e 449pt_ta_event_getmsg(const td_thragent_t *ta, td_event_msg_t *msg) 450{ 451 TDBG_FUNC(); 452 return (TD_NOMSG); 453} 454 455static td_err_e 456pt_dbsuspend(const td_thrhandle_t *th, int suspend) 457{ 458 td_thragent_t *ta = (td_thragent_t *)th->th_ta; 459 psaddr_t tcb_addr, tmbx_addr, ptr; 460 lwpid_t lwp; 461 uint32_t dflags; 462 int attrflags, locklevel, ret; 463 464 TDBG_FUNC(); 465 466 ret = pt_validate(th); 467 if (ret) 468 return (ret); 469 470 if (ta->map[th->th_tid].type == PT_LWP) { 471 if (suspend) 472 ret = ps_lstop(ta->ph, ta->map[th->th_tid].lwp); 473 else 474 ret = ps_lcontinue(ta->ph, ta->map[th->th_tid].lwp); 475 return (P2T(ret)); 476 } 477 478 ret = ps_pread(ta->ph, ta->map[th->th_tid].thr + 479 ta->thread_off_attr_flags, 480 &attrflags, sizeof(attrflags)); 481 if (ret != 0) 482 return (P2T(ret)); 483 ret = ps_pread(ta->ph, ta->map[th->th_tid].thr + 484 ta->thread_off_tcb, 485 &tcb_addr, sizeof(tcb_addr)); 486 if (ret != 0) 487 return (P2T(ret)); 488 tmbx_addr = tcb_addr + ta->thread_off_tmbx; 489 ptr = tmbx_addr + offsetof(struct kse_thr_mailbox, tm_lwp); 490 ret = ps_pread(ta->ph, ptr, &lwp, sizeof(lwpid_t)); 491 if (ret != 0) 492 return (P2T(ret)); 493 494 if (lwp != 0) { 495 /* don't suspend signal thread */ 496 if (attrflags & 0x200) 497 return (0); 498 if (attrflags & PTHREAD_SCOPE_SYSTEM) { 499 /* 500 * don't suspend system scope thread if it is holding 501 * some low level locks 502 */ 503 ptr = ta->map[th->th_tid].thr + ta->thread_off_kse; 504 ret = ps_pread(ta->ph, ptr, &ptr, sizeof(ptr)); 505 if (ret != 0) 506 return (P2T(ret)); 507 ret = ps_pread(ta->ph, ptr + ta->thread_off_kse_locklevel, 508 &locklevel, sizeof(int)); 509 if (ret != 0) 510 return (P2T(ret)); 511 if (locklevel <= 0) { 512 ptr = ta->map[th->th_tid].thr + 513 ta->thread_off_thr_locklevel; 514 ret = ps_pread(ta->ph, ptr, &locklevel, 515 sizeof(int)); 516 if (ret != 0) 517 return (P2T(ret)); 518 } 519 if (suspend) { 520 if (locklevel <= 0) 521 ret = ps_lstop(ta->ph, lwp); 522 } else { 523 ret = ps_lcontinue(ta->ph, lwp); 524 } 525 if (ret != 0) 526 return (P2T(ret)); 527 /* FALLTHROUGH */ 528 } else { 529 struct ptrace_lwpinfo pl; 530 531 if (ptrace(PT_LWPINFO, lwp, (caddr_t) &pl, sizeof(pl))) 532 return (TD_ERR); 533 if (suspend) { 534 if (!(pl.pl_flags & PL_FLAG_BOUND)) 535 ret = ps_lstop(ta->ph, lwp); 536 } else { 537 ret = ps_lcontinue(ta->ph, lwp); 538 } 539 if (ret != 0) 540 return (P2T(ret)); 541 /* FALLTHROUGH */ 542 } 543 } 544 /* read tm_dflags */ 545 ret = ps_pread(ta->ph, 546 tmbx_addr + offsetof(struct kse_thr_mailbox, tm_dflags), 547 &dflags, sizeof(dflags)); 548 if (ret != 0) 549 return (P2T(ret)); 550 if (suspend) 551 dflags |= TMDF_SUSPEND; 552 else 553 dflags &= ~TMDF_SUSPEND; 554 ret = ps_pwrite(ta->ph, 555 tmbx_addr + offsetof(struct kse_thr_mailbox, tm_dflags), 556 &dflags, sizeof(dflags)); 557 return (P2T(ret)); 558} 559 560static td_err_e 561pt_thr_dbresume(const td_thrhandle_t *th) 562{ 563 TDBG_FUNC(); 564 565 return pt_dbsuspend(th, 0); 566} 567 568static td_err_e 569pt_thr_dbsuspend(const td_thrhandle_t *th) 570{ 571 TDBG_FUNC(); 572 573 return pt_dbsuspend(th, 1); 574} 575 576static td_err_e 577pt_thr_validate(const td_thrhandle_t *th) 578{ 579 td_thrhandle_t temp; 580 int ret; 581 582 TDBG_FUNC(); 583 584 ret = pt_ta_map_id2thr(th->th_ta, th->th_tid, 585 &temp); 586 return (ret); 587} 588 589static td_err_e 590pt_thr_get_info(const td_thrhandle_t *th, td_thrinfo_t *info) 591{ 592 const td_thragent_t *ta = th->th_ta; 593 psaddr_t tcb_addr; 594 uint32_t dflags; 595 int state; 596 int ret; 597 598 TDBG_FUNC(); 599 600 ret = pt_validate(th); 601 if (ret) 602 return (ret); 603 604 memset(info, 0, sizeof(*info)); 605 if (ta->map[th->th_tid].type == PT_LWP) { 606 info->ti_type = TD_THR_SYSTEM; 607 info->ti_lid = ta->map[th->th_tid].lwp; 608 info->ti_tid = th->th_tid; 609 info->ti_state = TD_THR_RUN; 610 info->ti_type = TD_THR_SYSTEM; 611 return (TD_OK); 612 } 613 ret = ps_pread(ta->ph, ta->map[th->th_tid].thr + ta->thread_off_tcb, 614 &tcb_addr, sizeof(tcb_addr)); 615 if (ret != 0) 616 return (P2T(ret)); 617 ret = ps_pread(ta->ph, ta->map[th->th_tid].thr + ta->thread_off_state, 618 &state, sizeof(state)); 619 ret = ps_pread(ta->ph, 620 tcb_addr + ta->thread_off_tmbx + 621 offsetof(struct kse_thr_mailbox, tm_lwp), 622 &info->ti_lid, sizeof(lwpid_t)); 623 if (ret != 0) 624 return (P2T(ret)); 625 ret = ps_pread(ta->ph, 626 tcb_addr + ta->thread_off_tmbx + 627 offsetof(struct kse_thr_mailbox, tm_dflags), 628 &dflags, sizeof(dflags)); 629 if (ret != 0) 630 return (P2T(ret)); 631 info->ti_ta_p = th->th_ta; 632 info->ti_tid = th->th_tid; 633 if (state == ta->thread_state_running) 634 info->ti_state = TD_THR_RUN; 635 else if (state == ta->thread_state_zoombie) 636 info->ti_state = TD_THR_ZOMBIE; 637 else 638 info->ti_state = TD_THR_SLEEP; 639 info->ti_db_suspended = ((dflags & TMDF_SUSPEND) != 0); 640 info->ti_type = TD_THR_USER; 641 return (0); 642} 643 644static td_err_e 645pt_thr_getfpregs(const td_thrhandle_t *th, prfpregset_t *fpregs) 646{ 647 const td_thragent_t *ta = th->th_ta; 648 struct kse_thr_mailbox tmbx; 649 psaddr_t tcb_addr, tmbx_addr, ptr; 650 lwpid_t lwp; 651 int ret; 652 653 TDBG_FUNC(); 654 655 ret = pt_validate(th); 656 if (ret) 657 return (ret); 658 659 if (ta->map[th->th_tid].type == PT_LWP) { 660 ret = ps_lgetfpregs(ta->ph, ta->map[th->th_tid].lwp, fpregs); 661 return (P2T(ret)); 662 } 663 664 ret = ps_pread(ta->ph, ta->map[th->th_tid].thr + ta->thread_off_tcb, 665 &tcb_addr, sizeof(tcb_addr)); 666 if (ret != 0) 667 return (P2T(ret)); 668 tmbx_addr = tcb_addr + ta->thread_off_tmbx; 669 ptr = tmbx_addr + offsetof(struct kse_thr_mailbox, tm_lwp); 670 ret = ps_pread(ta->ph, ptr, &lwp, sizeof(lwpid_t)); 671 if (ret != 0) 672 return (P2T(ret)); 673 if (lwp != 0) { 674 ret = ps_lgetfpregs(ta->ph, lwp, fpregs); 675 return (P2T(ret)); 676 } 677 678 ret = ps_pread(ta->ph, tmbx_addr, &tmbx, sizeof(tmbx)); 679 if (ret != 0) 680 return (P2T(ret)); 681 pt_ucontext_to_fpreg(&tmbx.tm_context, fpregs); 682 return (0); 683} 684 685static td_err_e 686pt_thr_getgregs(const td_thrhandle_t *th, prgregset_t gregs) 687{ 688 const td_thragent_t *ta = th->th_ta; 689 struct kse_thr_mailbox tmbx; 690 psaddr_t tcb_addr, tmbx_addr, ptr; 691 lwpid_t lwp; 692 int ret; 693 694 TDBG_FUNC(); 695 696 ret = pt_validate(th); 697 if (ret) 698 return (ret); 699 700 if (ta->map[th->th_tid].type == PT_LWP) { 701 ret = ps_lgetregs(ta->ph, 702 ta->map[th->th_tid].lwp, gregs); 703 return (P2T(ret)); 704 } 705 706 ret = ps_pread(ta->ph, ta->map[th->th_tid].thr + ta->thread_off_tcb, 707 &tcb_addr, sizeof(tcb_addr)); 708 if (ret != 0) 709 return (P2T(ret)); 710 tmbx_addr = tcb_addr + ta->thread_off_tmbx; 711 ptr = tmbx_addr + offsetof(struct kse_thr_mailbox, tm_lwp); 712 ret = ps_pread(ta->ph, ptr, &lwp, sizeof(lwpid_t)); 713 if (ret != 0) 714 return (P2T(ret)); 715 if (lwp != 0) { 716 ret = ps_lgetregs(ta->ph, lwp, gregs); 717 return (P2T(ret)); 718 } 719 ret = ps_pread(ta->ph, tmbx_addr, &tmbx, sizeof(tmbx)); 720 if (ret != 0) 721 return (P2T(ret)); 722 pt_ucontext_to_reg(&tmbx.tm_context, gregs); 723 return (0); 724} 725 726static td_err_e 727pt_thr_setfpregs(const td_thrhandle_t *th, const prfpregset_t *fpregs) 728{ 729 const td_thragent_t *ta = th->th_ta; 730 struct kse_thr_mailbox tmbx; 731 psaddr_t tcb_addr, tmbx_addr, ptr; 732 lwpid_t lwp; 733 int ret; 734 735 TDBG_FUNC(); 736 737 ret = pt_validate(th); 738 if (ret) 739 return (ret); 740 741 if (ta->map[th->th_tid].type == PT_LWP) { 742 ret = ps_lsetfpregs(ta->ph, ta->map[th->th_tid].lwp, fpregs); 743 return (P2T(ret)); 744 } 745 746 ret = ps_pread(ta->ph, ta->map[th->th_tid].thr + 747 ta->thread_off_tcb, 748 &tcb_addr, sizeof(tcb_addr)); 749 if (ret != 0) 750 return (P2T(ret)); 751 tmbx_addr = tcb_addr + ta->thread_off_tmbx; 752 ptr = tmbx_addr + offsetof(struct kse_thr_mailbox, tm_lwp); 753 ret = ps_pread(ta->ph, ptr, &lwp, sizeof(lwpid_t)); 754 if (ret != 0) 755 return (P2T(ret)); 756 if (lwp != 0) { 757 ret = ps_lsetfpregs(ta->ph, lwp, fpregs); 758 return (P2T(ret)); 759 } 760 /* 761 * Read a copy of context, this makes sure that registers 762 * not covered by structure reg won't be clobbered 763 */ 764 ret = ps_pread(ta->ph, tmbx_addr, &tmbx, sizeof(tmbx)); 765 if (ret != 0) 766 return (P2T(ret)); 767 768 pt_fpreg_to_ucontext(fpregs, &tmbx.tm_context); 769 ret = ps_pwrite(ta->ph, tmbx_addr, &tmbx, sizeof(tmbx)); 770 return (P2T(ret)); 771} 772 773static td_err_e 774pt_thr_setgregs(const td_thrhandle_t *th, const prgregset_t gregs) 775{ 776 const td_thragent_t *ta = th->th_ta; 777 struct kse_thr_mailbox tmbx; 778 psaddr_t tcb_addr, tmbx_addr, ptr; 779 lwpid_t lwp; 780 int ret; 781 782 TDBG_FUNC(); 783 784 ret = pt_validate(th); 785 if (ret) 786 return (ret); 787 788 if (ta->map[th->th_tid].type == PT_LWP) { 789 ret = ps_lsetregs(ta->ph, ta->map[th->th_tid].lwp, gregs); 790 return (P2T(ret)); 791 } 792 793 ret = ps_pread(ta->ph, ta->map[th->th_tid].thr + 794 ta->thread_off_tcb, 795 &tcb_addr, sizeof(tcb_addr)); 796 if (ret != 0) 797 return (P2T(ret)); 798 tmbx_addr = tcb_addr + ta->thread_off_tmbx; 799 ptr = tmbx_addr + offsetof(struct kse_thr_mailbox, tm_lwp); 800 ret = ps_pread(ta->ph, ptr, &lwp, sizeof(lwpid_t)); 801 if (ret != 0) 802 return (P2T(ret)); 803 if (lwp != 0) { 804 ret = ps_lsetregs(ta->ph, lwp, gregs); 805 return (P2T(ret)); 806 } 807 808 /* 809 * Read a copy of context, make sure that registers 810 * not covered by structure reg won't be clobbered 811 */ 812 ret = ps_pread(ta->ph, tmbx_addr, &tmbx, sizeof(tmbx)); 813 if (ret != 0) 814 return (P2T(ret)); 815 pt_reg_to_ucontext(gregs, &tmbx.tm_context); 816 ret = ps_pwrite(ta->ph, tmbx_addr, &tmbx, sizeof(tmbx)); 817 return (P2T(ret)); 818} 819 820static td_err_e 821pt_thr_event_enable(const td_thrhandle_t *th, int en) 822{ 823 TDBG_FUNC(); 824 return (TD_ERR); 825} 826 827static td_err_e 828pt_thr_set_event(const td_thrhandle_t *th, td_thr_events_t *setp) 829{ 830 TDBG_FUNC(); 831 return (TD_ERR); 832} 833 834static td_err_e 835pt_thr_clear_event(const td_thrhandle_t *th, td_thr_events_t *setp) 836{ 837 TDBG_FUNC(); 838 return (TD_ERR); 839} 840 841static td_err_e 842pt_thr_event_getmsg(const td_thrhandle_t *th, td_event_msg_t *msg) 843{ 844 TDBG_FUNC(); 845 return (TD_NOMSG); 846} 847 848static td_err_e 849pt_thr_sstep(const td_thrhandle_t *th, int step) 850{ 851 const td_thragent_t *ta = th->th_ta; 852 struct kse_thr_mailbox tmbx; 853 struct reg regs; 854 psaddr_t tcb_addr, tmbx_addr; 855 uint32_t dflags; 856 lwpid_t lwp; 857 int ret; 858 859 TDBG_FUNC(); 860 861 ret = pt_validate(th); 862 if (ret) 863 return (ret); 864 865 if (ta->map[th->th_tid].type == PT_LWP) 866 return (TD_BADTH); 867 868 ret = ps_pread(ta->ph, ta->map[th->th_tid].thr + 869 ta->thread_off_tcb, 870 &tcb_addr, sizeof(tcb_addr)); 871 if (ret != 0) 872 return (P2T(ret)); 873 874 /* Clear or set single step flag in thread mailbox */ 875 ret = ps_pread(ta->ph, 876 tcb_addr + ta->thread_off_tmbx + 877 offsetof(struct kse_thr_mailbox, tm_dflags), 878 &dflags, sizeof(uint32_t)); 879 if (ret != 0) 880 return (P2T(ret)); 881 if (step != 0) 882 dflags |= TMDF_SSTEP; 883 else 884 dflags &= ~TMDF_SSTEP; 885 ret = ps_pwrite(ta->ph, 886 tcb_addr + ta->thread_off_tmbx + 887 offsetof(struct kse_thr_mailbox, tm_dflags), 888 &dflags, sizeof(uint32_t)); 889 if (ret != 0) 890 return (P2T(ret)); 891 /* Get lwp */ 892 ret = ps_pread(ta->ph, 893 tcb_addr + ta->thread_off_tmbx + 894 offsetof(struct kse_thr_mailbox, tm_lwp), 895 &lwp, sizeof(lwpid_t)); 896 if (ret != 0) 897 return (P2T(ret)); 898 if (lwp != 0) 899 return (0); 900 901 tmbx_addr = tcb_addr + ta->thread_off_tmbx; 902 /* 903 * context is in userland, some architectures store 904 * single step status in registers, we should change 905 * these registers. 906 */ 907 ret = ps_pread(ta->ph, tmbx_addr, &tmbx, sizeof(tmbx)); 908 if (ret == 0) { 909 pt_ucontext_to_reg(&tmbx.tm_context, ®s); 910 /* only write out if it is really changed. */ 911 if (pt_reg_sstep(®s, step) != 0) { 912 pt_reg_to_ucontext(®s, &tmbx.tm_context); 913 ret = ps_pwrite(ta->ph, tmbx_addr, &tmbx, 914 sizeof(tmbx)); 915 } 916 } 917 return (P2T(ret)); 918} 919 920static void 921pt_unmap_lwp(const td_thragent_t *ta, lwpid_t lwp) 922{ 923 int i; 924 925 for (i = 0; i < ta->map_len; ++i) { 926 if (ta->map[i].type == PT_LWP && ta->map[i].lwp == lwp) { 927 ta->map[i].type = PT_NONE; 928 return; 929 } 930 } 931} 932 933static int 934pt_validate(const td_thrhandle_t *th) 935{ 936 937 if (th->th_tid < 0 || th->th_tid >= th->th_ta->map_len || 938 th->th_ta->map[th->th_tid].type == PT_NONE) 939 return (TD_NOTHR); 940 return (TD_OK); 941} 942 943td_err_e 944pt_thr_tls_get_addr(const td_thrhandle_t *th, void *_linkmap, size_t offset, 945 void **address) 946{ 947 char *obj_entry; 948 const td_thragent_t *ta = th->th_ta; 949 psaddr_t tcb_addr, *dtv_addr, tcb_tp; 950 int tls_index, ret; 951 952 /* linkmap is a member of Obj_Entry */ 953 obj_entry = (char *)_linkmap - ta->thread_off_linkmap; 954 955 /* get tlsindex of the object file */ 956 ret = ps_pread(ta->ph, 957 obj_entry + ta->thread_off_tlsindex, 958 &tls_index, sizeof(tls_index)); 959 if (ret != 0) 960 return (P2T(ret)); 961 962 /* get thread tcb */ 963 ret = ps_pread(ta->ph, ta->map[th->th_tid].thr + 964 ta->thread_off_tcb, 965 &tcb_addr, sizeof(tcb_addr)); 966 if (ret != 0) 967 return (P2T(ret)); 968 969 /* get dtv array address */ 970 ret = ps_pread(ta->ph, tcb_addr + ta->thread_off_dtv, 971 &dtv_addr, sizeof(dtv_addr)); 972 if (ret != 0) 973 return (P2T(ret)); 974 /* now get the object's tls block base address */ 975 ret = ps_pread(ta->ph, &dtv_addr[tls_index+1], address, 976 sizeof(*address)); 977 if (ret != 0) 978 return (P2T(ret)); 979 980 *address += offset; 981 return (TD_OK); 982} 983 984struct ta_ops libpthread_db_ops = { 985 .to_init = pt_init, 986 .to_ta_clear_event = pt_ta_clear_event, 987 .to_ta_delete = pt_ta_delete, 988 .to_ta_event_addr = pt_ta_event_addr, 989 .to_ta_event_getmsg = pt_ta_event_getmsg, 990 .to_ta_map_id2thr = pt_ta_map_id2thr, 991 .to_ta_map_lwp2thr = pt_ta_map_lwp2thr, 992 .to_ta_new = pt_ta_new, 993 .to_ta_set_event = pt_ta_set_event, 994 .to_ta_thr_iter = pt_ta_thr_iter, 995 .to_ta_tsd_iter = pt_ta_tsd_iter, 996 .to_thr_clear_event = pt_thr_clear_event, 997 .to_thr_dbresume = pt_thr_dbresume, 998 .to_thr_dbsuspend = pt_thr_dbsuspend, 999 .to_thr_event_enable = pt_thr_event_enable, 1000 .to_thr_event_getmsg = pt_thr_event_getmsg, 1001 .to_thr_get_info = pt_thr_get_info, 1002 .to_thr_getfpregs = pt_thr_getfpregs, 1003 .to_thr_getgregs = pt_thr_getgregs, 1004 .to_thr_set_event = pt_thr_set_event, 1005 .to_thr_setfpregs = pt_thr_setfpregs, 1006 .to_thr_setgregs = pt_thr_setgregs, 1007 .to_thr_validate = pt_thr_validate, 1008 .to_thr_tls_get_addr = pt_thr_tls_get_addr, 1009 1010 /* FreeBSD specific extensions. */ 1011 .to_thr_sstep = pt_thr_sstep, 1012}; 1013