libpthread_db.c revision 133805
1132332Smarcel/* 2132332Smarcel * Copyright (c) 2004 David Xu <davidxu@freebsd.org> 3132332Smarcel * All rights reserved. 4132332Smarcel * 5132332Smarcel * Redistribution and use in source and binary forms, with or without 6132332Smarcel * modification, are permitted provided that the following conditions 7132332Smarcel * are met: 8132332Smarcel * 1. Redistributions of source code must retain the above copyright 9132332Smarcel * notice, this list of conditions and the following disclaimer. 10132332Smarcel * 2. Redistributions in binary form must reproduce the above copyright 11132332Smarcel * notice, this list of conditions and the following disclaimer in the 12132332Smarcel * documentation and/or other materials provided with the distribution. 13132332Smarcel * 14132332Smarcel * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15132332Smarcel * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16132332Smarcel * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17132332Smarcel * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18132332Smarcel * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19132332Smarcel * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20132332Smarcel * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21132332Smarcel * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22132332Smarcel * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23132332Smarcel * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24132332Smarcel * SUCH DAMAGE. 25132332Smarcel */ 26132332Smarcel 27132332Smarcel#include <sys/cdefs.h> 28132332Smarcel__FBSDID("$FreeBSD: head/lib/libthread_db/libpthread_db.c 133805 2004-08-16 05:20:12Z davidxu $"); 29132332Smarcel 30132332Smarcel#include <stddef.h> 31132332Smarcel#include <stdlib.h> 32132332Smarcel#include <string.h> 33132332Smarcel#include <unistd.h> 34132332Smarcel#include <pthread.h> 35132332Smarcel#include <sys/types.h> 36132332Smarcel#include <sys/kse.h> 37132332Smarcel#include <sys/ptrace.h> 38132332Smarcel#include <proc_service.h> 39132332Smarcel#include <thread_db.h> 40132332Smarcel 41132332Smarcel#include "libpthread_db.h" 42132332Smarcel 43132332Smarcel#define P2T(c) ps2td(c) 44132332Smarcel 45132332Smarcelstatic void pt_unmap_lwp(const td_thragent_t *ta, lwpid_t lwp); 46132332Smarcelstatic int pt_validate(const td_thrhandle_t *th); 47132332Smarcel 48132332Smarcelstatic int 49132332Smarcelps2td(int c) 50132332Smarcel{ 51132332Smarcel switch (c) { 52132332Smarcel case PS_OK: 53132332Smarcel return TD_OK; 54132332Smarcel case PS_ERR: 55132332Smarcel return TD_ERR; 56132332Smarcel case PS_BADPID: 57132332Smarcel return TD_BADPH; 58132332Smarcel case PS_BADLID: 59132332Smarcel return TD_NOLWP; 60132332Smarcel case PS_BADADDR: 61132332Smarcel return TD_ERR; 62132332Smarcel case PS_NOSYM: 63132332Smarcel return TD_NOLIBTHREAD; 64132332Smarcel case PS_NOFREGS: 65132332Smarcel return TD_NOFPREGS; 66132332Smarcel default: 67132332Smarcel return TD_ERR; 68132332Smarcel } 69132332Smarcel} 70132332Smarcel 71132332Smarcelstatic long 72132332Smarcelpt_map_thread(const td_thragent_t *const_ta, psaddr_t pt, int type) 73132332Smarcel{ 74132332Smarcel td_thragent_t *ta = __DECONST(td_thragent_t *, const_ta); 75132332Smarcel struct pt_map *new; 76132332Smarcel int i, first = -1; 77132332Smarcel 78132332Smarcel /* leave zero out */ 79132332Smarcel for (i = 1; i < ta->map_len; ++i) { 80132332Smarcel if (ta->map[i].type == PT_NONE) { 81132332Smarcel if (first == -1) 82132332Smarcel first = i; 83132332Smarcel } else if (ta->map[i].type == type && ta->map[i].thr == pt) { 84132332Smarcel return (i); 85132332Smarcel } 86132332Smarcel } 87132332Smarcel 88132332Smarcel if (first == -1) { 89132332Smarcel if (ta->map_len == 0) { 90132332Smarcel ta->map = calloc(20, sizeof(struct pt_map)); 91132332Smarcel if (ta->map == NULL) 92132332Smarcel return (-1); 93132332Smarcel ta->map_len = 20; 94132332Smarcel first = 1; 95132332Smarcel } else { 96132332Smarcel new = realloc(ta->map, 97132332Smarcel sizeof(struct pt_map) * ta->map_len * 2); 98132332Smarcel if (new == NULL) 99132332Smarcel return (-1); 100132332Smarcel memset(new + ta->map_len, '\0', sizeof(struct pt_map) * 101132332Smarcel ta->map_len); 102132332Smarcel first = ta->map_len; 103132332Smarcel ta->map = new; 104132332Smarcel ta->map_len *= 2; 105132332Smarcel } 106132332Smarcel } 107132332Smarcel 108132332Smarcel ta->map[first].type = type; 109132332Smarcel ta->map[first].thr = pt; 110132332Smarcel return (first); 111132332Smarcel} 112132332Smarcel 113132332Smarcelstatic td_err_e 114132332Smarcelpt_init(void) 115132332Smarcel{ 116132332Smarcel pt_md_init(); 117132332Smarcel return (0); 118132332Smarcel} 119132332Smarcel 120132332Smarcelstatic td_err_e 121132332Smarcelpt_ta_new(struct ps_prochandle *ph, td_thragent_t **pta) 122132332Smarcel{ 123132332Smarcel#define LOOKUP_SYM(proc, sym, addr) \ 124132332Smarcel ret = ps_pglobal_lookup(proc, NULL, sym, addr); \ 125132332Smarcel if (ret != 0) { \ 126132332Smarcel TDBG("can not find symbol: %s\n", sym); \ 127132332Smarcel ret = TD_NOLIBTHREAD; \ 128132332Smarcel goto error; \ 129132332Smarcel } 130132332Smarcel 131133802Sdavidxu#define LOOKUP_VAL(proc, sym, val) \ 132133802Sdavidxu ret = ps_pglobal_lookup(proc, NULL, sym, &vaddr);\ 133133802Sdavidxu if (ret != 0) { \ 134133802Sdavidxu TDBG("can not find symbol: %s\n", sym); \ 135133802Sdavidxu ret = TD_NOLIBTHREAD; \ 136133802Sdavidxu goto error; \ 137133802Sdavidxu } \ 138133802Sdavidxu ret = ps_pread(proc, vaddr, val, sizeof(int)); \ 139133802Sdavidxu if (ret != 0) { \ 140133802Sdavidxu TDBG("can not read value of %s\n", sym);\ 141133802Sdavidxu ret = TD_NOLIBTHREAD; \ 142133802Sdavidxu goto error; \ 143133802Sdavidxu } 144133802Sdavidxu 145132332Smarcel td_thragent_t *ta; 146133802Sdavidxu psaddr_t vaddr; 147132332Smarcel int dbg; 148132332Smarcel int ret; 149132332Smarcel 150132332Smarcel TDBG_FUNC(); 151132332Smarcel 152132332Smarcel ta = malloc(sizeof(td_thragent_t)); 153132332Smarcel if (ta == NULL) 154132332Smarcel return (TD_MALLOC); 155132332Smarcel 156132332Smarcel ta->ph = ph; 157132332Smarcel ta->thread_activated = 0; 158132332Smarcel ta->map = NULL; 159132332Smarcel ta->map_len = 0; 160132332Smarcel 161132332Smarcel LOOKUP_SYM(ph, "_libkse_debug", &ta->libkse_debug_addr); 162132332Smarcel LOOKUP_SYM(ph, "_thread_list", &ta->thread_list_addr); 163132332Smarcel LOOKUP_SYM(ph, "_thread_activated", &ta->thread_activated_addr); 164132332Smarcel LOOKUP_SYM(ph, "_thread_active_threads",&ta->thread_active_threads_addr); 165132332Smarcel LOOKUP_SYM(ph, "_thread_keytable", &ta->thread_keytable_addr); 166133802Sdavidxu LOOKUP_VAL(ph, "_thread_off_dtv", &ta->thread_off_dtv); 167133802Sdavidxu LOOKUP_VAL(ph, "_thread_off_kse_locklevel", &ta->thread_off_kse_locklevel); 168133802Sdavidxu LOOKUP_VAL(ph, "_thread_off_kse", &ta->thread_off_kse); 169133802Sdavidxu LOOKUP_VAL(ph, "_thread_off_tlsindex", &ta->thread_off_tlsindex); 170133802Sdavidxu LOOKUP_VAL(ph, "_thread_off_attr_flags", &ta->thread_off_attr_flags); 171133802Sdavidxu LOOKUP_VAL(ph, "_thread_size_key", &ta->thread_size_key); 172133802Sdavidxu LOOKUP_VAL(ph, "_thread_off_tcb", &ta->thread_off_tcb); 173133802Sdavidxu LOOKUP_VAL(ph, "_thread_off_linkmap", &ta->thread_off_linkmap); 174133802Sdavidxu LOOKUP_VAL(ph, "_thread_off_tmbx", &ta->thread_off_tmbx); 175133802Sdavidxu LOOKUP_VAL(ph, "_thread_off_thr_locklevel", &ta->thread_off_thr_locklevel); 176133802Sdavidxu LOOKUP_VAL(ph, "_thread_off_next", &ta->thread_off_next); 177133802Sdavidxu LOOKUP_VAL(ph, "_thread_off_state", &ta->thread_off_state); 178133802Sdavidxu LOOKUP_VAL(ph, "_thread_max_keys", &ta->thread_max_keys); 179133802Sdavidxu LOOKUP_VAL(ph, "_thread_off_key_allocated", &ta->thread_off_key_allocated); 180133802Sdavidxu LOOKUP_VAL(ph, "_thread_off_key_destructor", &ta->thread_off_key_destructor); 181133802Sdavidxu LOOKUP_VAL(ph, "_thread_state_running", &ta->thread_state_running); 182133802Sdavidxu LOOKUP_VAL(ph, "_thread_state_zoombie", &ta->thread_state_zoombie); 183132332Smarcel dbg = getpid(); 184132332Smarcel /* 185132332Smarcel * If this fails it probably means we're debugging a core file and 186132332Smarcel * can't write to it. 187132332Smarcel */ 188132332Smarcel ps_pwrite(ph, ta->libkse_debug_addr, &dbg, sizeof(int)); 189132332Smarcel *pta = ta; 190132332Smarcel return (0); 191132332Smarcel 192132332Smarcelerror: 193132332Smarcel free(ta); 194132332Smarcel return (ret); 195132332Smarcel} 196132332Smarcel 197132332Smarcelstatic td_err_e 198132332Smarcelpt_ta_delete(td_thragent_t *ta) 199132332Smarcel{ 200132332Smarcel int dbg; 201132332Smarcel 202132332Smarcel TDBG_FUNC(); 203132332Smarcel 204132332Smarcel dbg = 0; 205132332Smarcel /* 206132332Smarcel * Error returns from this write are not really a problem; 207132332Smarcel * the process doesn't exist any more. 208132332Smarcel */ 209132332Smarcel ps_pwrite(ta->ph, ta->libkse_debug_addr, &dbg, sizeof(int)); 210132332Smarcel if (ta->map) 211132332Smarcel free(ta->map); 212132332Smarcel free(ta); 213132332Smarcel return (TD_OK); 214132332Smarcel} 215132332Smarcel 216132332Smarcelstatic td_err_e 217132332Smarcelpt_ta_map_id2thr(const td_thragent_t *ta, thread_t id, td_thrhandle_t *th) 218132332Smarcel{ 219132332Smarcel prgregset_t gregs; 220132332Smarcel TAILQ_HEAD(, pthread) thread_list; 221132332Smarcel psaddr_t pt, tcb_addr; 222132332Smarcel lwpid_t lwp; 223132332Smarcel int ret; 224132332Smarcel 225132332Smarcel TDBG_FUNC(); 226132332Smarcel 227132332Smarcel if (id < 0 || id >= ta->map_len || ta->map[id].type == PT_NONE) 228132332Smarcel return (TD_NOTHR); 229132332Smarcel ret = ps_pread(ta->ph, ta->thread_list_addr, &thread_list, 230132332Smarcel sizeof(thread_list)); 231132332Smarcel if (ret != 0) 232132332Smarcel return (P2T(ret)); 233132332Smarcel pt = (psaddr_t)thread_list.tqh_first; 234132332Smarcel if (ta->map[id].type == PT_LWP) { 235132332Smarcel /* 236132332Smarcel * if we are referencing a lwp, make sure it was not already 237132332Smarcel * mapped to user thread. 238132332Smarcel */ 239132332Smarcel while (pt != 0) { 240132332Smarcel ret = ps_pread(ta->ph, 241133802Sdavidxu pt + ta->thread_off_tcb, 242132332Smarcel &tcb_addr, sizeof(tcb_addr)); 243132332Smarcel if (ret != 0) 244132332Smarcel return (P2T(ret)); 245132332Smarcel ret = ps_pread(ta->ph, 246133802Sdavidxu tcb_addr + ta->thread_off_tmbx + 247133802Sdavidxu offsetof(struct kse_thr_mailbox, tm_lwp), 248132332Smarcel &lwp, sizeof(lwp)); 249132332Smarcel if (ret != 0) 250132332Smarcel return (P2T(ret)); 251132332Smarcel /* 252132332Smarcel * If the lwp was already mapped to userland thread, 253132332Smarcel * we shouldn't reference it directly in future. 254132332Smarcel */ 255132332Smarcel if (lwp == ta->map[id].lwp) { 256132332Smarcel ta->map[id].type = PT_NONE; 257132332Smarcel return (TD_NOTHR); 258132332Smarcel } 259132332Smarcel /* get next thread */ 260132332Smarcel ret = ps_pread(ta->ph, 261133802Sdavidxu pt + ta->thread_off_next, 262132332Smarcel &pt, sizeof(pt)); 263132332Smarcel if (ret != 0) 264132332Smarcel return (P2T(ret)); 265132332Smarcel } 266132332Smarcel /* check lwp */ 267132332Smarcel ret = ptrace(PT_GETREGS, ta->map[id].lwp, (caddr_t)&gregs, 0); 268132332Smarcel if (ret != 0) { 269132332Smarcel /* no longer exists */ 270132332Smarcel ta->map[id].type = PT_NONE; 271132332Smarcel return (TD_NOTHR); 272132332Smarcel } 273132332Smarcel } else { 274132332Smarcel while (pt != 0 && ta->map[id].thr != pt) { 275132332Smarcel ret = ps_pread(ta->ph, 276133802Sdavidxu pt + ta->thread_off_tcb, 277132332Smarcel &tcb_addr, sizeof(tcb_addr)); 278132332Smarcel if (ret != 0) 279132332Smarcel return (P2T(ret)); 280132332Smarcel /* get next thread */ 281132332Smarcel ret = ps_pread(ta->ph, 282133802Sdavidxu pt + ta->thread_off_next, 283132332Smarcel &pt, sizeof(pt)); 284132332Smarcel if (ret != 0) 285132332Smarcel return (P2T(ret)); 286132332Smarcel } 287132332Smarcel 288132332Smarcel if (pt == 0) { 289132332Smarcel /* no longer exists */ 290132332Smarcel ta->map[id].type = PT_NONE; 291132332Smarcel return (TD_NOTHR); 292132332Smarcel } 293132332Smarcel } 294132332Smarcel th->th_ta = ta; 295132332Smarcel th->th_tid = id; 296132332Smarcel return (TD_OK); 297132332Smarcel} 298132332Smarcel 299132332Smarcelstatic td_err_e 300132332Smarcelpt_ta_map_lwp2thr(const td_thragent_t *ta, lwpid_t lwp, td_thrhandle_t *th) 301132332Smarcel{ 302132332Smarcel TAILQ_HEAD(, pthread) thread_list; 303132332Smarcel psaddr_t pt, ptr; 304132332Smarcel lwpid_t tmp_lwp; 305132332Smarcel int ret; 306132332Smarcel 307132332Smarcel TDBG_FUNC(); 308132332Smarcel 309132332Smarcel ret = ps_pread(ta->ph, ta->thread_list_addr, &thread_list, 310132332Smarcel sizeof(thread_list)); 311132332Smarcel if (ret != 0) 312132332Smarcel return (P2T(ret)); 313132332Smarcel pt = (psaddr_t)thread_list.tqh_first; 314132332Smarcel while (pt != 0) { 315133802Sdavidxu ret = ps_pread(ta->ph, pt + ta->thread_off_tcb, 316132332Smarcel &ptr, sizeof(ptr)); 317132332Smarcel if (ret != 0) 318132332Smarcel return (P2T(ret)); 319133802Sdavidxu ptr += ta->thread_off_tmbx + 320133802Sdavidxu offsetof(struct kse_thr_mailbox, tm_lwp); 321132332Smarcel ret = ps_pread(ta->ph, ptr, &tmp_lwp, sizeof(lwpid_t)); 322132332Smarcel if (ret != 0) 323132332Smarcel return (P2T(ret)); 324132332Smarcel if (tmp_lwp == lwp) { 325132332Smarcel th->th_ta = ta; 326132332Smarcel th->th_tid = pt_map_thread(ta, pt, PT_USER); 327132332Smarcel if (th->th_tid == -1) 328132332Smarcel return (TD_MALLOC); 329132332Smarcel pt_unmap_lwp(ta, lwp); 330132332Smarcel return (TD_OK); 331132332Smarcel } 332132332Smarcel 333132332Smarcel /* get next thread */ 334132332Smarcel ret = ps_pread(ta->ph, 335133802Sdavidxu pt + ta->thread_off_next, 336132332Smarcel &pt, sizeof(pt)); 337132332Smarcel if (ret != 0) 338132332Smarcel return (P2T(ret)); 339132332Smarcel } 340132332Smarcel 341132332Smarcel return (TD_NOTHR); 342132332Smarcel} 343132332Smarcel 344132332Smarcelstatic td_err_e 345132332Smarcelpt_ta_thr_iter(const td_thragent_t *ta, 346132332Smarcel td_thr_iter_f *callback, void *cbdata_p, 347132332Smarcel td_thr_state_e state, int ti_pri, 348132332Smarcel sigset_t *ti_sigmask_p, 349132332Smarcel unsigned int ti_user_flags) 350132332Smarcel{ 351132332Smarcel TAILQ_HEAD(, pthread) thread_list; 352132332Smarcel td_thrhandle_t th; 353132332Smarcel psaddr_t pt; 354132332Smarcel ps_err_e pserr; 355132332Smarcel int activated; 356132332Smarcel 357132332Smarcel TDBG_FUNC(); 358132332Smarcel 359132332Smarcel pserr = ps_pread(ta->ph, ta->thread_activated_addr, &activated, 360132332Smarcel sizeof(int)); 361132332Smarcel if (pserr != PS_OK) 362132332Smarcel return (P2T(pserr)); 363132332Smarcel if (!activated) 364132332Smarcel return (TD_OK); 365132332Smarcel 366132332Smarcel pserr = ps_pread(ta->ph, ta->thread_list_addr, &thread_list, 367132332Smarcel sizeof(thread_list)); 368132332Smarcel if (pserr != 0) 369132332Smarcel return (P2T(pserr)); 370132332Smarcel pt = (psaddr_t)thread_list.tqh_first; 371132332Smarcel while (pt != 0) { 372132332Smarcel th.th_ta = ta; 373132332Smarcel th.th_tid = pt_map_thread(ta, pt, PT_USER); 374132332Smarcel /* should we unmap lwp here ? */ 375132332Smarcel if (th.th_tid == -1) 376132332Smarcel return (TD_MALLOC); 377132332Smarcel if ((*callback)(&th, cbdata_p)) 378132332Smarcel return (TD_DBERR); 379132332Smarcel /* get next thread */ 380132332Smarcel pserr = ps_pread(ta->ph, 381133802Sdavidxu pt + ta->thread_off_next, &pt, 382132332Smarcel sizeof(pt)); 383132332Smarcel if (pserr != PS_OK) 384132332Smarcel return (P2T(pserr)); 385132332Smarcel } 386132332Smarcel return (TD_OK); 387132332Smarcel} 388132332Smarcel 389132332Smarcelstatic td_err_e 390132332Smarcelpt_ta_tsd_iter(const td_thragent_t *ta, td_key_iter_f *ki, void *arg) 391132332Smarcel{ 392133802Sdavidxu char *keytable; 393133802Sdavidxu void *destructor; 394133802Sdavidxu int i, ret, allocated; 395132332Smarcel 396132332Smarcel TDBG_FUNC(); 397132332Smarcel 398133802Sdavidxu keytable = malloc(ta->thread_max_keys * ta->thread_size_key); 399133802Sdavidxu if (keytable == NULL) 400133802Sdavidxu return (TD_MALLOC); 401132332Smarcel ret = ps_pread(ta->ph, (psaddr_t)ta->thread_keytable_addr, keytable, 402133802Sdavidxu ta->thread_max_keys * ta->thread_size_key); 403133805Sdavidxu if (ret != 0) { 404133805Sdavidxu free(keytable); 405132332Smarcel return (P2T(ret)); 406133805Sdavidxu } 407133802Sdavidxu for (i = 0; i < ta->thread_max_keys; i++) { 408133802Sdavidxu allocated = *(int *)(keytable + i * ta->thread_size_key + 409133802Sdavidxu ta->thread_off_key_allocated); 410133802Sdavidxu destructor = *(void **)(keytable + i * ta->thread_size_key + 411133802Sdavidxu ta->thread_off_key_destructor); 412133802Sdavidxu if (allocated) { 413133802Sdavidxu ret = (ki)(i, destructor, arg); 414133802Sdavidxu if (ret != 0) { 415133802Sdavidxu free(keytable); 416132332Smarcel return (TD_DBERR); 417133802Sdavidxu } 418132332Smarcel } 419132332Smarcel } 420133802Sdavidxu free(keytable); 421132332Smarcel return (TD_OK); 422132332Smarcel} 423132332Smarcel 424132332Smarcelstatic td_err_e 425132332Smarcelpt_ta_event_addr(const td_thragent_t *ta, td_event_e event, td_notify_t *ptr) 426132332Smarcel{ 427132332Smarcel TDBG_FUNC(); 428132332Smarcel return (TD_NOEVENT); 429132332Smarcel} 430132332Smarcel 431132332Smarcelstatic td_err_e 432132332Smarcelpt_ta_set_event(const td_thragent_t *ta, td_thr_events_t *events) 433132332Smarcel{ 434132332Smarcel TDBG_FUNC(); 435132332Smarcel return (TD_ERR); 436132332Smarcel} 437132332Smarcel 438132332Smarcelstatic td_err_e 439132332Smarcelpt_ta_clear_event(const td_thragent_t *ta, td_thr_events_t *events) 440132332Smarcel{ 441132332Smarcel TDBG_FUNC(); 442132332Smarcel return (TD_ERR); 443132332Smarcel} 444132332Smarcel 445132332Smarcelstatic td_err_e 446132332Smarcelpt_ta_event_getmsg(const td_thragent_t *ta, td_event_msg_t *msg) 447132332Smarcel{ 448132332Smarcel TDBG_FUNC(); 449132332Smarcel return (TD_NOMSG); 450132332Smarcel} 451132332Smarcel 452132332Smarcelstatic td_err_e 453132951Sdavidxupt_dbsuspend(const td_thrhandle_t *th, int suspend) 454132951Sdavidxu{ 455132951Sdavidxu td_thragent_t *ta = (td_thragent_t *)th->th_ta; 456132951Sdavidxu psaddr_t tcb_addr, tmbx_addr, ptr; 457132951Sdavidxu lwpid_t lwp; 458132951Sdavidxu uint32_t dflags; 459133342Sdavidxu int attrflags, locklevel, ret; 460132951Sdavidxu 461132951Sdavidxu TDBG_FUNC(); 462132951Sdavidxu 463132951Sdavidxu ret = pt_validate(th); 464132951Sdavidxu if (ret) 465132951Sdavidxu return (ret); 466132951Sdavidxu 467132951Sdavidxu if (ta->map[th->th_tid].type == PT_LWP) { 468132951Sdavidxu if (suspend) 469132951Sdavidxu ret = ps_lstop(ta->ph, ta->map[th->th_tid].lwp); 470132951Sdavidxu else 471132951Sdavidxu ret = ps_lcontinue(ta->ph, ta->map[th->th_tid].lwp); 472132951Sdavidxu return (P2T(ret)); 473132951Sdavidxu } 474132951Sdavidxu 475132951Sdavidxu ret = ps_pread(ta->ph, ta->map[th->th_tid].thr + 476133802Sdavidxu ta->thread_off_attr_flags, 477132951Sdavidxu &attrflags, sizeof(attrflags)); 478132951Sdavidxu if (ret != 0) 479132951Sdavidxu return (P2T(ret)); 480132951Sdavidxu ret = ps_pread(ta->ph, ta->map[th->th_tid].thr + 481133802Sdavidxu ta->thread_off_tcb, 482133802Sdavidxu &tcb_addr, sizeof(tcb_addr)); 483132951Sdavidxu if (ret != 0) 484132951Sdavidxu return (P2T(ret)); 485133802Sdavidxu tmbx_addr = tcb_addr + ta->thread_off_tmbx; 486132951Sdavidxu ptr = tmbx_addr + offsetof(struct kse_thr_mailbox, tm_lwp); 487132951Sdavidxu ret = ps_pread(ta->ph, ptr, &lwp, sizeof(lwpid_t)); 488132951Sdavidxu if (ret != 0) 489132951Sdavidxu return (P2T(ret)); 490133342Sdavidxu 491133342Sdavidxu if (lwp != 0) { 492133342Sdavidxu /* don't suspend signal thread */ 493133802Sdavidxu if (attrflags & 0x200) 494133342Sdavidxu return (0); 495133342Sdavidxu if (attrflags & PTHREAD_SCOPE_SYSTEM) { 496133342Sdavidxu /* 497133342Sdavidxu * don't suspend system scope thread if it is holding 498133342Sdavidxu * some low level locks 499133342Sdavidxu */ 500133802Sdavidxu ptr = ta->map[th->th_tid].thr + ta->thread_off_kse; 501133342Sdavidxu ret = ps_pread(ta->ph, ptr, &ptr, sizeof(ptr)); 502133342Sdavidxu if (ret != 0) 503133342Sdavidxu return (P2T(ret)); 504133802Sdavidxu ret = ps_pread(ta->ph, ptr + ta->thread_off_kse_locklevel, 505133802Sdavidxu &locklevel, sizeof(int)); 506133342Sdavidxu if (ret != 0) 507133342Sdavidxu return (P2T(ret)); 508133342Sdavidxu if (locklevel <= 0) { 509133342Sdavidxu ptr = ta->map[th->th_tid].thr + 510133802Sdavidxu ta->thread_off_thr_locklevel; 511133342Sdavidxu ret = ps_pread(ta->ph, ptr, &locklevel, 512133342Sdavidxu sizeof(int)); 513133342Sdavidxu if (ret != 0) 514133342Sdavidxu return (P2T(ret)); 515133342Sdavidxu } 516133342Sdavidxu if (suspend) { 517133342Sdavidxu if (locklevel <= 0) 518133342Sdavidxu ret = ps_lstop(ta->ph, lwp); 519133342Sdavidxu } else { 520132951Sdavidxu ret = ps_lcontinue(ta->ph, lwp); 521133342Sdavidxu } 522132951Sdavidxu if (ret != 0) 523132951Sdavidxu return (P2T(ret)); 524133342Sdavidxu /* FALLTHROUGH */ 525133342Sdavidxu } else { 526133342Sdavidxu struct ptrace_lwpinfo pl; 527133342Sdavidxu 528133342Sdavidxu if (ptrace(PT_LWPINFO, lwp, (caddr_t) &pl, sizeof(pl))) 529133342Sdavidxu return (TD_ERR); 530133342Sdavidxu if (suspend) { 531133342Sdavidxu if (!(pl.pl_flags & PL_FLAG_BOUND)) 532133342Sdavidxu ret = ps_lstop(ta->ph, lwp); 533133342Sdavidxu } else { 534133342Sdavidxu ret = ps_lcontinue(ta->ph, lwp); 535133342Sdavidxu } 536133342Sdavidxu if (ret != 0) 537133342Sdavidxu return (P2T(ret)); 538133342Sdavidxu /* FALLTHROUGH */ 539132951Sdavidxu } 540132951Sdavidxu } 541132951Sdavidxu /* read tm_dflags */ 542132951Sdavidxu ret = ps_pread(ta->ph, 543132951Sdavidxu tmbx_addr + offsetof(struct kse_thr_mailbox, tm_dflags), 544132951Sdavidxu &dflags, sizeof(dflags)); 545132951Sdavidxu if (ret != 0) 546132951Sdavidxu return (P2T(ret)); 547132951Sdavidxu if (suspend) 548133047Sdavidxu dflags |= TMDF_SUSPEND; 549132951Sdavidxu else 550133047Sdavidxu dflags &= ~TMDF_SUSPEND; 551132951Sdavidxu ret = ps_pwrite(ta->ph, 552132951Sdavidxu tmbx_addr + offsetof(struct kse_thr_mailbox, tm_dflags), 553132951Sdavidxu &dflags, sizeof(dflags)); 554132951Sdavidxu return (P2T(ret)); 555132951Sdavidxu} 556132951Sdavidxu 557132951Sdavidxustatic td_err_e 558132332Smarcelpt_thr_dbresume(const td_thrhandle_t *th) 559132332Smarcel{ 560132332Smarcel TDBG_FUNC(); 561132951Sdavidxu 562132951Sdavidxu return pt_dbsuspend(th, 0); 563132332Smarcel} 564132332Smarcel 565132332Smarcelstatic td_err_e 566132332Smarcelpt_thr_dbsuspend(const td_thrhandle_t *th) 567132332Smarcel{ 568132332Smarcel TDBG_FUNC(); 569132951Sdavidxu 570132951Sdavidxu return pt_dbsuspend(th, 1); 571132332Smarcel} 572132332Smarcel 573132332Smarcelstatic td_err_e 574132332Smarcelpt_thr_validate(const td_thrhandle_t *th) 575132332Smarcel{ 576132332Smarcel td_thrhandle_t temp; 577132332Smarcel int ret; 578132332Smarcel 579132332Smarcel TDBG_FUNC(); 580132332Smarcel 581132332Smarcel ret = pt_ta_map_id2thr(th->th_ta, th->th_tid, 582132332Smarcel &temp); 583132951Sdavidxu return (ret); 584132332Smarcel} 585132332Smarcel 586132332Smarcelstatic td_err_e 587132332Smarcelpt_thr_get_info(const td_thrhandle_t *th, td_thrinfo_t *info) 588132332Smarcel{ 589132332Smarcel const td_thragent_t *ta = th->th_ta; 590133802Sdavidxu psaddr_t tcb_addr; 591133802Sdavidxu uint32_t dflags; 592133802Sdavidxu int state; 593132332Smarcel int ret; 594132332Smarcel 595132332Smarcel TDBG_FUNC(); 596132332Smarcel 597132332Smarcel ret = pt_validate(th); 598132332Smarcel if (ret) 599132332Smarcel return (ret); 600132332Smarcel 601132332Smarcel memset(info, 0, sizeof(*info)); 602132332Smarcel if (ta->map[th->th_tid].type == PT_LWP) { 603132332Smarcel info->ti_type = TD_THR_SYSTEM; 604132332Smarcel info->ti_lid = ta->map[th->th_tid].lwp; 605132332Smarcel info->ti_tid = th->th_tid; 606132332Smarcel info->ti_state = TD_THR_RUN; 607132332Smarcel info->ti_type = TD_THR_SYSTEM; 608132332Smarcel return (TD_OK); 609132332Smarcel } 610133802Sdavidxu ret = ps_pread(ta->ph, ta->map[th->th_tid].thr + ta->thread_off_tcb, 611133802Sdavidxu &tcb_addr, sizeof(tcb_addr)); 612132332Smarcel if (ret != 0) 613132332Smarcel return (P2T(ret)); 614133802Sdavidxu ret = ps_pread(ta->ph, ta->map[th->th_tid].thr + ta->thread_off_state, 615133802Sdavidxu &state, sizeof(state)); 616132332Smarcel ret = ps_pread(ta->ph, 617133802Sdavidxu tcb_addr + ta->thread_off_tmbx + 618133802Sdavidxu offsetof(struct kse_thr_mailbox, tm_lwp), 619132332Smarcel &info->ti_lid, sizeof(lwpid_t)); 620132332Smarcel if (ret != 0) 621132332Smarcel return (P2T(ret)); 622132951Sdavidxu ret = ps_pread(ta->ph, 623133802Sdavidxu tcb_addr + ta->thread_off_tmbx + 624133802Sdavidxu offsetof(struct kse_thr_mailbox, tm_dflags), 625132951Sdavidxu &dflags, sizeof(dflags)); 626132951Sdavidxu if (ret != 0) 627132951Sdavidxu return (P2T(ret)); 628132332Smarcel info->ti_ta_p = th->th_ta; 629132332Smarcel info->ti_tid = th->th_tid; 630133802Sdavidxu if (state == ta->thread_state_running) 631132332Smarcel info->ti_state = TD_THR_RUN; 632133802Sdavidxu else if (state == ta->thread_state_zoombie) 633133802Sdavidxu info->ti_state = TD_THR_ZOMBIE; 634133802Sdavidxu else 635132332Smarcel info->ti_state = TD_THR_SLEEP; 636133047Sdavidxu info->ti_db_suspended = ((dflags & TMDF_SUSPEND) != 0); 637132332Smarcel info->ti_type = TD_THR_USER; 638132332Smarcel return (0); 639132332Smarcel} 640132332Smarcel 641132332Smarcelstatic td_err_e 642132332Smarcelpt_thr_getfpregs(const td_thrhandle_t *th, prfpregset_t *fpregs) 643132332Smarcel{ 644132332Smarcel const td_thragent_t *ta = th->th_ta; 645132332Smarcel struct kse_thr_mailbox tmbx; 646132332Smarcel psaddr_t tcb_addr, tmbx_addr, ptr; 647132332Smarcel lwpid_t lwp; 648132332Smarcel int ret; 649132332Smarcel 650132332Smarcel TDBG_FUNC(); 651132332Smarcel 652132332Smarcel ret = pt_validate(th); 653132332Smarcel if (ret) 654132332Smarcel return (ret); 655132332Smarcel 656132332Smarcel if (ta->map[th->th_tid].type == PT_LWP) { 657132332Smarcel ret = ps_lgetfpregs(ta->ph, ta->map[th->th_tid].lwp, fpregs); 658132332Smarcel return (P2T(ret)); 659132332Smarcel } 660132332Smarcel 661133802Sdavidxu ret = ps_pread(ta->ph, ta->map[th->th_tid].thr + ta->thread_off_tcb, 662132951Sdavidxu &tcb_addr, sizeof(tcb_addr)); 663132332Smarcel if (ret != 0) 664132332Smarcel return (P2T(ret)); 665133802Sdavidxu tmbx_addr = tcb_addr + ta->thread_off_tmbx; 666132332Smarcel ptr = tmbx_addr + offsetof(struct kse_thr_mailbox, tm_lwp); 667132332Smarcel ret = ps_pread(ta->ph, ptr, &lwp, sizeof(lwpid_t)); 668132332Smarcel if (ret != 0) 669132332Smarcel return (P2T(ret)); 670132332Smarcel if (lwp != 0) { 671132332Smarcel ret = ps_lgetfpregs(ta->ph, lwp, fpregs); 672132332Smarcel return (P2T(ret)); 673132332Smarcel } 674132332Smarcel 675132332Smarcel ret = ps_pread(ta->ph, tmbx_addr, &tmbx, sizeof(tmbx)); 676132332Smarcel if (ret != 0) 677132332Smarcel return (P2T(ret)); 678132332Smarcel pt_ucontext_to_fpreg(&tmbx.tm_context, fpregs); 679132332Smarcel return (0); 680132332Smarcel} 681132332Smarcel 682132332Smarcelstatic td_err_e 683132332Smarcelpt_thr_getgregs(const td_thrhandle_t *th, prgregset_t gregs) 684132332Smarcel{ 685132332Smarcel const td_thragent_t *ta = th->th_ta; 686132332Smarcel struct kse_thr_mailbox tmbx; 687132332Smarcel psaddr_t tcb_addr, tmbx_addr, ptr; 688132332Smarcel lwpid_t lwp; 689132332Smarcel int ret; 690132332Smarcel 691132332Smarcel TDBG_FUNC(); 692132332Smarcel 693132332Smarcel ret = pt_validate(th); 694132332Smarcel if (ret) 695132332Smarcel return (ret); 696132332Smarcel 697132332Smarcel if (ta->map[th->th_tid].type == PT_LWP) { 698132332Smarcel ret = ps_lgetregs(ta->ph, 699132332Smarcel ta->map[th->th_tid].lwp, gregs); 700132332Smarcel return (P2T(ret)); 701132332Smarcel } 702132332Smarcel 703133802Sdavidxu ret = ps_pread(ta->ph, ta->map[th->th_tid].thr + ta->thread_off_tcb, 704132332Smarcel &tcb_addr, sizeof(tcb_addr)); 705132332Smarcel if (ret != 0) 706132332Smarcel return (P2T(ret)); 707133802Sdavidxu tmbx_addr = tcb_addr + ta->thread_off_tmbx; 708132332Smarcel ptr = tmbx_addr + offsetof(struct kse_thr_mailbox, tm_lwp); 709132332Smarcel ret = ps_pread(ta->ph, ptr, &lwp, sizeof(lwpid_t)); 710132332Smarcel if (ret != 0) 711132332Smarcel return (P2T(ret)); 712132332Smarcel if (lwp != 0) { 713132332Smarcel ret = ps_lgetregs(ta->ph, lwp, gregs); 714132332Smarcel return (P2T(ret)); 715132332Smarcel } 716132332Smarcel ret = ps_pread(ta->ph, tmbx_addr, &tmbx, sizeof(tmbx)); 717132332Smarcel if (ret != 0) 718132332Smarcel return (P2T(ret)); 719132332Smarcel pt_ucontext_to_reg(&tmbx.tm_context, gregs); 720132332Smarcel return (0); 721132332Smarcel} 722132332Smarcel 723132332Smarcelstatic td_err_e 724132332Smarcelpt_thr_setfpregs(const td_thrhandle_t *th, const prfpregset_t *fpregs) 725132332Smarcel{ 726132332Smarcel const td_thragent_t *ta = th->th_ta; 727132332Smarcel struct kse_thr_mailbox tmbx; 728132332Smarcel psaddr_t tcb_addr, tmbx_addr, ptr; 729132332Smarcel lwpid_t lwp; 730132332Smarcel int ret; 731132332Smarcel 732132332Smarcel TDBG_FUNC(); 733132332Smarcel 734132332Smarcel ret = pt_validate(th); 735132332Smarcel if (ret) 736132332Smarcel return (ret); 737132332Smarcel 738132332Smarcel if (ta->map[th->th_tid].type == PT_LWP) { 739132332Smarcel ret = ps_lsetfpregs(ta->ph, ta->map[th->th_tid].lwp, fpregs); 740132332Smarcel return (P2T(ret)); 741132332Smarcel } 742132332Smarcel 743132332Smarcel ret = ps_pread(ta->ph, ta->map[th->th_tid].thr + 744133802Sdavidxu ta->thread_off_tcb, 745132332Smarcel &tcb_addr, sizeof(tcb_addr)); 746132332Smarcel if (ret != 0) 747132332Smarcel return (P2T(ret)); 748133802Sdavidxu tmbx_addr = tcb_addr + ta->thread_off_tmbx; 749132332Smarcel ptr = tmbx_addr + offsetof(struct kse_thr_mailbox, tm_lwp); 750132332Smarcel ret = ps_pread(ta->ph, ptr, &lwp, sizeof(lwpid_t)); 751132332Smarcel if (ret != 0) 752132332Smarcel return (P2T(ret)); 753132332Smarcel if (lwp != 0) { 754132332Smarcel ret = ps_lsetfpregs(ta->ph, lwp, fpregs); 755132332Smarcel return (P2T(ret)); 756132332Smarcel } 757132332Smarcel /* 758132332Smarcel * Read a copy of context, this makes sure that registers 759132332Smarcel * not covered by structure reg won't be clobbered 760132332Smarcel */ 761132332Smarcel ret = ps_pread(ta->ph, tmbx_addr, &tmbx, sizeof(tmbx)); 762132332Smarcel if (ret != 0) 763132332Smarcel return (P2T(ret)); 764132332Smarcel 765132332Smarcel pt_fpreg_to_ucontext(fpregs, &tmbx.tm_context); 766132332Smarcel ret = ps_pwrite(ta->ph, tmbx_addr, &tmbx, sizeof(tmbx)); 767132332Smarcel return (P2T(ret)); 768132332Smarcel} 769132332Smarcel 770132332Smarcelstatic td_err_e 771132332Smarcelpt_thr_setgregs(const td_thrhandle_t *th, const prgregset_t gregs) 772132332Smarcel{ 773132332Smarcel const td_thragent_t *ta = th->th_ta; 774132332Smarcel struct kse_thr_mailbox tmbx; 775132332Smarcel psaddr_t tcb_addr, tmbx_addr, ptr; 776132332Smarcel lwpid_t lwp; 777132332Smarcel int ret; 778132332Smarcel 779132332Smarcel TDBG_FUNC(); 780132332Smarcel 781132332Smarcel ret = pt_validate(th); 782132332Smarcel if (ret) 783132332Smarcel return (ret); 784132332Smarcel 785132332Smarcel if (ta->map[th->th_tid].type == PT_LWP) { 786132332Smarcel ret = ps_lsetregs(ta->ph, ta->map[th->th_tid].lwp, gregs); 787132332Smarcel return (P2T(ret)); 788132332Smarcel } 789132332Smarcel 790132332Smarcel ret = ps_pread(ta->ph, ta->map[th->th_tid].thr + 791133802Sdavidxu ta->thread_off_tcb, 792132332Smarcel &tcb_addr, sizeof(tcb_addr)); 793132332Smarcel if (ret != 0) 794132332Smarcel return (P2T(ret)); 795133802Sdavidxu tmbx_addr = tcb_addr + ta->thread_off_tmbx; 796132332Smarcel ptr = tmbx_addr + offsetof(struct kse_thr_mailbox, tm_lwp); 797132332Smarcel ret = ps_pread(ta->ph, ptr, &lwp, sizeof(lwpid_t)); 798132332Smarcel if (ret != 0) 799132332Smarcel return (P2T(ret)); 800132332Smarcel if (lwp != 0) { 801132332Smarcel ret = ps_lsetregs(ta->ph, lwp, gregs); 802132332Smarcel return (P2T(ret)); 803132332Smarcel } 804132332Smarcel 805132332Smarcel /* 806132332Smarcel * Read a copy of context, make sure that registers 807132332Smarcel * not covered by structure reg won't be clobbered 808132332Smarcel */ 809132332Smarcel ret = ps_pread(ta->ph, tmbx_addr, &tmbx, sizeof(tmbx)); 810132332Smarcel if (ret != 0) 811132332Smarcel return (P2T(ret)); 812132332Smarcel pt_reg_to_ucontext(gregs, &tmbx.tm_context); 813132332Smarcel ret = ps_pwrite(ta->ph, tmbx_addr, &tmbx, sizeof(tmbx)); 814132332Smarcel return (P2T(ret)); 815132332Smarcel} 816132332Smarcel 817132332Smarcelstatic td_err_e 818132332Smarcelpt_thr_event_enable(const td_thrhandle_t *th, int en) 819132332Smarcel{ 820132332Smarcel TDBG_FUNC(); 821132332Smarcel return (TD_ERR); 822132332Smarcel} 823132332Smarcel 824132332Smarcelstatic td_err_e 825132332Smarcelpt_thr_set_event(const td_thrhandle_t *th, td_thr_events_t *setp) 826132332Smarcel{ 827132332Smarcel TDBG_FUNC(); 828132332Smarcel return (TD_ERR); 829132332Smarcel} 830132332Smarcel 831132332Smarcelstatic td_err_e 832132332Smarcelpt_thr_clear_event(const td_thrhandle_t *th, td_thr_events_t *setp) 833132332Smarcel{ 834132332Smarcel TDBG_FUNC(); 835132332Smarcel return (TD_ERR); 836132332Smarcel} 837132332Smarcel 838132332Smarcelstatic td_err_e 839132332Smarcelpt_thr_event_getmsg(const td_thrhandle_t *th, td_event_msg_t *msg) 840132332Smarcel{ 841132332Smarcel TDBG_FUNC(); 842132332Smarcel return (TD_NOMSG); 843132332Smarcel} 844132332Smarcel 845132332Smarcelstatic td_err_e 846132332Smarcelpt_thr_sstep(const td_thrhandle_t *th, int step) 847132332Smarcel{ 848132332Smarcel const td_thragent_t *ta = th->th_ta; 849132332Smarcel struct kse_thr_mailbox tmbx; 850132332Smarcel struct reg regs; 851132332Smarcel psaddr_t tcb_addr, tmbx_addr; 852132951Sdavidxu uint32_t dflags; 853132332Smarcel lwpid_t lwp; 854132332Smarcel int ret; 855132332Smarcel 856132332Smarcel TDBG_FUNC(); 857132332Smarcel 858132332Smarcel ret = pt_validate(th); 859132332Smarcel if (ret) 860132332Smarcel return (ret); 861132332Smarcel 862132332Smarcel if (ta->map[th->th_tid].type == PT_LWP) 863132332Smarcel return (TD_BADTH); 864132332Smarcel 865132332Smarcel ret = ps_pread(ta->ph, ta->map[th->th_tid].thr + 866133802Sdavidxu ta->thread_off_tcb, 867132332Smarcel &tcb_addr, sizeof(tcb_addr)); 868132332Smarcel if (ret != 0) 869132332Smarcel return (P2T(ret)); 870132332Smarcel 871132332Smarcel /* Clear or set single step flag in thread mailbox */ 872133802Sdavidxu ret = ps_pread(ta->ph, 873133802Sdavidxu tcb_addr + ta->thread_off_tmbx + 874133802Sdavidxu offsetof(struct kse_thr_mailbox, tm_dflags), 875133802Sdavidxu &dflags, sizeof(uint32_t)); 876132951Sdavidxu if (ret != 0) 877132951Sdavidxu return (P2T(ret)); 878132951Sdavidxu if (step != 0) 879132951Sdavidxu dflags |= TMDF_SSTEP; 880132951Sdavidxu else 881132951Sdavidxu dflags &= ~TMDF_SSTEP; 882133802Sdavidxu ret = ps_pwrite(ta->ph, 883133802Sdavidxu tcb_addr + ta->thread_off_tmbx + 884133802Sdavidxu offsetof(struct kse_thr_mailbox, tm_dflags), 885133802Sdavidxu &dflags, sizeof(uint32_t)); 886132332Smarcel if (ret != 0) 887132332Smarcel return (P2T(ret)); 888132332Smarcel /* Get lwp */ 889133802Sdavidxu ret = ps_pread(ta->ph, 890133802Sdavidxu tcb_addr + ta->thread_off_tmbx + 891133802Sdavidxu offsetof(struct kse_thr_mailbox, tm_lwp), 892133802Sdavidxu &lwp, sizeof(lwpid_t)); 893132332Smarcel if (ret != 0) 894132332Smarcel return (P2T(ret)); 895132332Smarcel if (lwp != 0) 896132951Sdavidxu return (0); 897132332Smarcel 898133802Sdavidxu tmbx_addr = tcb_addr + ta->thread_off_tmbx; 899132332Smarcel /* 900132332Smarcel * context is in userland, some architectures store 901132332Smarcel * single step status in registers, we should change 902132332Smarcel * these registers. 903132332Smarcel */ 904132332Smarcel ret = ps_pread(ta->ph, tmbx_addr, &tmbx, sizeof(tmbx)); 905132332Smarcel if (ret == 0) { 906132332Smarcel pt_ucontext_to_reg(&tmbx.tm_context, ®s); 907132332Smarcel /* only write out if it is really changed. */ 908132332Smarcel if (pt_reg_sstep(®s, step) != 0) { 909132332Smarcel pt_reg_to_ucontext(®s, &tmbx.tm_context); 910132332Smarcel ret = ps_pwrite(ta->ph, tmbx_addr, &tmbx, 911132332Smarcel sizeof(tmbx)); 912132332Smarcel } 913132332Smarcel } 914132332Smarcel return (P2T(ret)); 915132332Smarcel} 916132332Smarcel 917132332Smarcelstatic void 918132332Smarcelpt_unmap_lwp(const td_thragent_t *ta, lwpid_t lwp) 919132332Smarcel{ 920132332Smarcel int i; 921132332Smarcel 922132332Smarcel for (i = 0; i < ta->map_len; ++i) { 923132332Smarcel if (ta->map[i].type == PT_LWP && ta->map[i].lwp == lwp) { 924132332Smarcel ta->map[i].type = PT_NONE; 925132332Smarcel return; 926132332Smarcel } 927132332Smarcel } 928132332Smarcel} 929132332Smarcel 930132332Smarcelstatic int 931132332Smarcelpt_validate(const td_thrhandle_t *th) 932132332Smarcel{ 933132332Smarcel 934132332Smarcel if (th->th_tid < 0 || th->th_tid >= th->th_ta->map_len || 935132332Smarcel th->th_ta->map[th->th_tid].type == PT_NONE) 936132332Smarcel return (TD_NOTHR); 937132332Smarcel return (TD_OK); 938132332Smarcel} 939132332Smarcel 940133342Sdavidxutd_err_e 941133342Sdavidxupt_thr_tls_get_addr(const td_thrhandle_t *th, void *_linkmap, size_t offset, 942133342Sdavidxu void **address) 943133342Sdavidxu{ 944133802Sdavidxu char *obj_entry; 945133342Sdavidxu const td_thragent_t *ta = th->th_ta; 946133342Sdavidxu psaddr_t tcb_addr, *dtv_addr, tcb_tp; 947133342Sdavidxu int tls_index, ret; 948133342Sdavidxu 949133342Sdavidxu /* linkmap is a member of Obj_Entry */ 950133802Sdavidxu obj_entry = (char *)_linkmap - ta->thread_off_linkmap; 951133342Sdavidxu 952133342Sdavidxu /* get tlsindex of the object file */ 953133342Sdavidxu ret = ps_pread(ta->ph, 954133802Sdavidxu obj_entry + ta->thread_off_tlsindex, 955133342Sdavidxu &tls_index, sizeof(tls_index)); 956133342Sdavidxu if (ret != 0) 957133342Sdavidxu return (P2T(ret)); 958133342Sdavidxu 959133342Sdavidxu /* get thread tcb */ 960133342Sdavidxu ret = ps_pread(ta->ph, ta->map[th->th_tid].thr + 961133802Sdavidxu ta->thread_off_tcb, 962133342Sdavidxu &tcb_addr, sizeof(tcb_addr)); 963133342Sdavidxu if (ret != 0) 964133342Sdavidxu return (P2T(ret)); 965133342Sdavidxu 966133342Sdavidxu /* get dtv array address */ 967133802Sdavidxu ret = ps_pread(ta->ph, tcb_addr + ta->thread_off_dtv, 968133342Sdavidxu &dtv_addr, sizeof(dtv_addr)); 969133342Sdavidxu if (ret != 0) 970133342Sdavidxu return (P2T(ret)); 971133342Sdavidxu /* now get the object's tls block base address */ 972133342Sdavidxu ret = ps_pread(ta->ph, &dtv_addr[tls_index+1], address, 973133342Sdavidxu sizeof(*address)); 974133342Sdavidxu if (ret != 0) 975133342Sdavidxu return (P2T(ret)); 976133342Sdavidxu 977133342Sdavidxu *address += offset; 978133342Sdavidxu return (TD_OK); 979133342Sdavidxu} 980133342Sdavidxu 981132332Smarcelstruct ta_ops libpthread_db_ops = { 982132332Smarcel .to_init = pt_init, 983132332Smarcel .to_ta_clear_event = pt_ta_clear_event, 984132332Smarcel .to_ta_delete = pt_ta_delete, 985132332Smarcel .to_ta_event_addr = pt_ta_event_addr, 986132332Smarcel .to_ta_event_getmsg = pt_ta_event_getmsg, 987132332Smarcel .to_ta_map_id2thr = pt_ta_map_id2thr, 988132332Smarcel .to_ta_map_lwp2thr = pt_ta_map_lwp2thr, 989132332Smarcel .to_ta_new = pt_ta_new, 990132332Smarcel .to_ta_set_event = pt_ta_set_event, 991132332Smarcel .to_ta_thr_iter = pt_ta_thr_iter, 992132332Smarcel .to_ta_tsd_iter = pt_ta_tsd_iter, 993132332Smarcel .to_thr_clear_event = pt_thr_clear_event, 994132332Smarcel .to_thr_dbresume = pt_thr_dbresume, 995132332Smarcel .to_thr_dbsuspend = pt_thr_dbsuspend, 996132332Smarcel .to_thr_event_enable = pt_thr_event_enable, 997132332Smarcel .to_thr_event_getmsg = pt_thr_event_getmsg, 998132332Smarcel .to_thr_get_info = pt_thr_get_info, 999132332Smarcel .to_thr_getfpregs = pt_thr_getfpregs, 1000132332Smarcel .to_thr_getgregs = pt_thr_getgregs, 1001132332Smarcel .to_thr_set_event = pt_thr_set_event, 1002132332Smarcel .to_thr_setfpregs = pt_thr_setfpregs, 1003132332Smarcel .to_thr_setgregs = pt_thr_setgregs, 1004132332Smarcel .to_thr_validate = pt_thr_validate, 1005133342Sdavidxu .to_thr_tls_get_addr = pt_thr_tls_get_addr, 1006132332Smarcel 1007132332Smarcel /* FreeBSD specific extensions. */ 1008132332Smarcel .to_thr_sstep = pt_thr_sstep, 1009132332Smarcel}; 1010