libpthread_db.c revision 146447
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 146447 2005-05-20 13:09:49Z charnier $"); 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; 296144663Sdavidxu th->th_thread = pt; 297132332Smarcel return (TD_OK); 298132332Smarcel} 299132332Smarcel 300132332Smarcelstatic td_err_e 301132332Smarcelpt_ta_map_lwp2thr(const td_thragent_t *ta, lwpid_t lwp, td_thrhandle_t *th) 302132332Smarcel{ 303132332Smarcel TAILQ_HEAD(, pthread) thread_list; 304132332Smarcel psaddr_t pt, ptr; 305132332Smarcel lwpid_t tmp_lwp; 306132332Smarcel int ret; 307132332Smarcel 308132332Smarcel TDBG_FUNC(); 309132332Smarcel 310132332Smarcel ret = ps_pread(ta->ph, ta->thread_list_addr, &thread_list, 311132332Smarcel sizeof(thread_list)); 312132332Smarcel if (ret != 0) 313132332Smarcel return (P2T(ret)); 314132332Smarcel pt = (psaddr_t)thread_list.tqh_first; 315132332Smarcel while (pt != 0) { 316133802Sdavidxu ret = ps_pread(ta->ph, pt + ta->thread_off_tcb, 317132332Smarcel &ptr, sizeof(ptr)); 318132332Smarcel if (ret != 0) 319132332Smarcel return (P2T(ret)); 320133802Sdavidxu ptr += ta->thread_off_tmbx + 321133802Sdavidxu offsetof(struct kse_thr_mailbox, tm_lwp); 322132332Smarcel ret = ps_pread(ta->ph, ptr, &tmp_lwp, sizeof(lwpid_t)); 323132332Smarcel if (ret != 0) 324132332Smarcel return (P2T(ret)); 325132332Smarcel if (tmp_lwp == lwp) { 326132332Smarcel th->th_ta = ta; 327132332Smarcel th->th_tid = pt_map_thread(ta, pt, PT_USER); 328132332Smarcel if (th->th_tid == -1) 329132332Smarcel return (TD_MALLOC); 330132332Smarcel pt_unmap_lwp(ta, lwp); 331144663Sdavidxu th->th_thread = pt; 332132332Smarcel return (TD_OK); 333132332Smarcel } 334132332Smarcel 335132332Smarcel /* get next thread */ 336132332Smarcel ret = ps_pread(ta->ph, 337133802Sdavidxu pt + ta->thread_off_next, 338132332Smarcel &pt, sizeof(pt)); 339132332Smarcel if (ret != 0) 340132332Smarcel return (P2T(ret)); 341132332Smarcel } 342132332Smarcel 343132332Smarcel return (TD_NOTHR); 344132332Smarcel} 345132332Smarcel 346132332Smarcelstatic td_err_e 347132332Smarcelpt_ta_thr_iter(const td_thragent_t *ta, 348132332Smarcel td_thr_iter_f *callback, void *cbdata_p, 349132332Smarcel td_thr_state_e state, int ti_pri, 350132332Smarcel sigset_t *ti_sigmask_p, 351132332Smarcel unsigned int ti_user_flags) 352132332Smarcel{ 353132332Smarcel TAILQ_HEAD(, pthread) thread_list; 354132332Smarcel td_thrhandle_t th; 355132332Smarcel psaddr_t pt; 356132332Smarcel ps_err_e pserr; 357132332Smarcel int activated; 358132332Smarcel 359132332Smarcel TDBG_FUNC(); 360132332Smarcel 361132332Smarcel pserr = ps_pread(ta->ph, ta->thread_activated_addr, &activated, 362132332Smarcel sizeof(int)); 363132332Smarcel if (pserr != PS_OK) 364132332Smarcel return (P2T(pserr)); 365132332Smarcel if (!activated) 366132332Smarcel return (TD_OK); 367132332Smarcel 368132332Smarcel pserr = ps_pread(ta->ph, ta->thread_list_addr, &thread_list, 369132332Smarcel sizeof(thread_list)); 370132332Smarcel if (pserr != 0) 371132332Smarcel return (P2T(pserr)); 372132332Smarcel pt = (psaddr_t)thread_list.tqh_first; 373132332Smarcel while (pt != 0) { 374132332Smarcel th.th_ta = ta; 375132332Smarcel th.th_tid = pt_map_thread(ta, pt, PT_USER); 376144663Sdavidxu th.th_thread = pt; 377132332Smarcel /* should we unmap lwp here ? */ 378132332Smarcel if (th.th_tid == -1) 379132332Smarcel return (TD_MALLOC); 380132332Smarcel if ((*callback)(&th, cbdata_p)) 381132332Smarcel return (TD_DBERR); 382132332Smarcel /* get next thread */ 383132332Smarcel pserr = ps_pread(ta->ph, 384133802Sdavidxu pt + ta->thread_off_next, &pt, 385132332Smarcel sizeof(pt)); 386132332Smarcel if (pserr != PS_OK) 387132332Smarcel return (P2T(pserr)); 388132332Smarcel } 389132332Smarcel return (TD_OK); 390132332Smarcel} 391132332Smarcel 392132332Smarcelstatic td_err_e 393132332Smarcelpt_ta_tsd_iter(const td_thragent_t *ta, td_key_iter_f *ki, void *arg) 394132332Smarcel{ 395133802Sdavidxu char *keytable; 396133802Sdavidxu void *destructor; 397133802Sdavidxu int i, ret, allocated; 398132332Smarcel 399132332Smarcel TDBG_FUNC(); 400132332Smarcel 401133802Sdavidxu keytable = malloc(ta->thread_max_keys * ta->thread_size_key); 402133802Sdavidxu if (keytable == NULL) 403133802Sdavidxu return (TD_MALLOC); 404132332Smarcel ret = ps_pread(ta->ph, (psaddr_t)ta->thread_keytable_addr, keytable, 405133802Sdavidxu ta->thread_max_keys * ta->thread_size_key); 406133805Sdavidxu if (ret != 0) { 407133805Sdavidxu free(keytable); 408132332Smarcel return (P2T(ret)); 409133805Sdavidxu } 410133802Sdavidxu for (i = 0; i < ta->thread_max_keys; i++) { 411133802Sdavidxu allocated = *(int *)(keytable + i * ta->thread_size_key + 412133802Sdavidxu ta->thread_off_key_allocated); 413133802Sdavidxu destructor = *(void **)(keytable + i * ta->thread_size_key + 414133802Sdavidxu ta->thread_off_key_destructor); 415133802Sdavidxu if (allocated) { 416133802Sdavidxu ret = (ki)(i, destructor, arg); 417133802Sdavidxu if (ret != 0) { 418133802Sdavidxu free(keytable); 419132332Smarcel return (TD_DBERR); 420133802Sdavidxu } 421132332Smarcel } 422132332Smarcel } 423133802Sdavidxu free(keytable); 424132332Smarcel return (TD_OK); 425132332Smarcel} 426132332Smarcel 427132332Smarcelstatic td_err_e 428132332Smarcelpt_ta_event_addr(const td_thragent_t *ta, td_event_e event, td_notify_t *ptr) 429132332Smarcel{ 430132332Smarcel TDBG_FUNC(); 431144922Sdavidxu return (TD_ERR); 432132332Smarcel} 433132332Smarcel 434132332Smarcelstatic td_err_e 435132332Smarcelpt_ta_set_event(const td_thragent_t *ta, td_thr_events_t *events) 436132332Smarcel{ 437132332Smarcel TDBG_FUNC(); 438144922Sdavidxu return (0); 439132332Smarcel} 440132332Smarcel 441132332Smarcelstatic td_err_e 442132332Smarcelpt_ta_clear_event(const td_thragent_t *ta, td_thr_events_t *events) 443132332Smarcel{ 444132332Smarcel TDBG_FUNC(); 445144922Sdavidxu return (0); 446132332Smarcel} 447132332Smarcel 448132332Smarcelstatic td_err_e 449132332Smarcelpt_ta_event_getmsg(const td_thragent_t *ta, td_event_msg_t *msg) 450132332Smarcel{ 451132332Smarcel TDBG_FUNC(); 452132332Smarcel return (TD_NOMSG); 453132332Smarcel} 454132332Smarcel 455132332Smarcelstatic td_err_e 456132951Sdavidxupt_dbsuspend(const td_thrhandle_t *th, int suspend) 457132951Sdavidxu{ 458132951Sdavidxu td_thragent_t *ta = (td_thragent_t *)th->th_ta; 459132951Sdavidxu psaddr_t tcb_addr, tmbx_addr, ptr; 460132951Sdavidxu lwpid_t lwp; 461132951Sdavidxu uint32_t dflags; 462133342Sdavidxu int attrflags, locklevel, ret; 463132951Sdavidxu 464132951Sdavidxu TDBG_FUNC(); 465132951Sdavidxu 466132951Sdavidxu ret = pt_validate(th); 467132951Sdavidxu if (ret) 468132951Sdavidxu return (ret); 469132951Sdavidxu 470132951Sdavidxu if (ta->map[th->th_tid].type == PT_LWP) { 471132951Sdavidxu if (suspend) 472132951Sdavidxu ret = ps_lstop(ta->ph, ta->map[th->th_tid].lwp); 473132951Sdavidxu else 474132951Sdavidxu ret = ps_lcontinue(ta->ph, ta->map[th->th_tid].lwp); 475132951Sdavidxu return (P2T(ret)); 476132951Sdavidxu } 477132951Sdavidxu 478132951Sdavidxu ret = ps_pread(ta->ph, ta->map[th->th_tid].thr + 479133802Sdavidxu ta->thread_off_attr_flags, 480132951Sdavidxu &attrflags, sizeof(attrflags)); 481132951Sdavidxu if (ret != 0) 482132951Sdavidxu return (P2T(ret)); 483132951Sdavidxu ret = ps_pread(ta->ph, ta->map[th->th_tid].thr + 484133802Sdavidxu ta->thread_off_tcb, 485133802Sdavidxu &tcb_addr, sizeof(tcb_addr)); 486132951Sdavidxu if (ret != 0) 487132951Sdavidxu return (P2T(ret)); 488133802Sdavidxu tmbx_addr = tcb_addr + ta->thread_off_tmbx; 489132951Sdavidxu ptr = tmbx_addr + offsetof(struct kse_thr_mailbox, tm_lwp); 490132951Sdavidxu ret = ps_pread(ta->ph, ptr, &lwp, sizeof(lwpid_t)); 491132951Sdavidxu if (ret != 0) 492132951Sdavidxu return (P2T(ret)); 493133342Sdavidxu 494133342Sdavidxu if (lwp != 0) { 495133342Sdavidxu /* don't suspend signal thread */ 496133802Sdavidxu if (attrflags & 0x200) 497133342Sdavidxu return (0); 498133342Sdavidxu if (attrflags & PTHREAD_SCOPE_SYSTEM) { 499133342Sdavidxu /* 500133342Sdavidxu * don't suspend system scope thread if it is holding 501133342Sdavidxu * some low level locks 502133342Sdavidxu */ 503133802Sdavidxu ptr = ta->map[th->th_tid].thr + ta->thread_off_kse; 504133342Sdavidxu ret = ps_pread(ta->ph, ptr, &ptr, sizeof(ptr)); 505133342Sdavidxu if (ret != 0) 506133342Sdavidxu return (P2T(ret)); 507133802Sdavidxu ret = ps_pread(ta->ph, ptr + ta->thread_off_kse_locklevel, 508133802Sdavidxu &locklevel, sizeof(int)); 509133342Sdavidxu if (ret != 0) 510133342Sdavidxu return (P2T(ret)); 511133342Sdavidxu if (locklevel <= 0) { 512133342Sdavidxu ptr = ta->map[th->th_tid].thr + 513133802Sdavidxu ta->thread_off_thr_locklevel; 514133342Sdavidxu ret = ps_pread(ta->ph, ptr, &locklevel, 515133342Sdavidxu sizeof(int)); 516133342Sdavidxu if (ret != 0) 517133342Sdavidxu return (P2T(ret)); 518133342Sdavidxu } 519133342Sdavidxu if (suspend) { 520133342Sdavidxu if (locklevel <= 0) 521133342Sdavidxu ret = ps_lstop(ta->ph, lwp); 522133342Sdavidxu } else { 523132951Sdavidxu ret = ps_lcontinue(ta->ph, lwp); 524133342Sdavidxu } 525132951Sdavidxu if (ret != 0) 526132951Sdavidxu return (P2T(ret)); 527133342Sdavidxu /* FALLTHROUGH */ 528133342Sdavidxu } else { 529133342Sdavidxu struct ptrace_lwpinfo pl; 530133342Sdavidxu 531133342Sdavidxu if (ptrace(PT_LWPINFO, lwp, (caddr_t) &pl, sizeof(pl))) 532133342Sdavidxu return (TD_ERR); 533133342Sdavidxu if (suspend) { 534133342Sdavidxu if (!(pl.pl_flags & PL_FLAG_BOUND)) 535133342Sdavidxu ret = ps_lstop(ta->ph, lwp); 536133342Sdavidxu } else { 537133342Sdavidxu ret = ps_lcontinue(ta->ph, lwp); 538133342Sdavidxu } 539133342Sdavidxu if (ret != 0) 540133342Sdavidxu return (P2T(ret)); 541133342Sdavidxu /* FALLTHROUGH */ 542132951Sdavidxu } 543132951Sdavidxu } 544132951Sdavidxu /* read tm_dflags */ 545132951Sdavidxu ret = ps_pread(ta->ph, 546132951Sdavidxu tmbx_addr + offsetof(struct kse_thr_mailbox, tm_dflags), 547132951Sdavidxu &dflags, sizeof(dflags)); 548132951Sdavidxu if (ret != 0) 549132951Sdavidxu return (P2T(ret)); 550132951Sdavidxu if (suspend) 551133047Sdavidxu dflags |= TMDF_SUSPEND; 552132951Sdavidxu else 553133047Sdavidxu dflags &= ~TMDF_SUSPEND; 554132951Sdavidxu ret = ps_pwrite(ta->ph, 555132951Sdavidxu tmbx_addr + offsetof(struct kse_thr_mailbox, tm_dflags), 556132951Sdavidxu &dflags, sizeof(dflags)); 557132951Sdavidxu return (P2T(ret)); 558132951Sdavidxu} 559132951Sdavidxu 560132951Sdavidxustatic td_err_e 561132332Smarcelpt_thr_dbresume(const td_thrhandle_t *th) 562132332Smarcel{ 563132332Smarcel TDBG_FUNC(); 564132951Sdavidxu 565132951Sdavidxu return pt_dbsuspend(th, 0); 566132332Smarcel} 567132332Smarcel 568132332Smarcelstatic td_err_e 569132332Smarcelpt_thr_dbsuspend(const td_thrhandle_t *th) 570132332Smarcel{ 571132332Smarcel TDBG_FUNC(); 572132951Sdavidxu 573132951Sdavidxu return pt_dbsuspend(th, 1); 574132332Smarcel} 575132332Smarcel 576132332Smarcelstatic td_err_e 577132332Smarcelpt_thr_validate(const td_thrhandle_t *th) 578132332Smarcel{ 579132332Smarcel td_thrhandle_t temp; 580132332Smarcel int ret; 581132332Smarcel 582132332Smarcel TDBG_FUNC(); 583132332Smarcel 584132332Smarcel ret = pt_ta_map_id2thr(th->th_ta, th->th_tid, 585132332Smarcel &temp); 586132951Sdavidxu return (ret); 587132332Smarcel} 588132332Smarcel 589132332Smarcelstatic td_err_e 590132332Smarcelpt_thr_get_info(const td_thrhandle_t *th, td_thrinfo_t *info) 591132332Smarcel{ 592132332Smarcel const td_thragent_t *ta = th->th_ta; 593133802Sdavidxu psaddr_t tcb_addr; 594133802Sdavidxu uint32_t dflags; 595133802Sdavidxu int state; 596132332Smarcel int ret; 597132332Smarcel 598132332Smarcel TDBG_FUNC(); 599132332Smarcel 600132332Smarcel ret = pt_validate(th); 601132332Smarcel if (ret) 602132332Smarcel return (ret); 603132332Smarcel 604132332Smarcel memset(info, 0, sizeof(*info)); 605132332Smarcel if (ta->map[th->th_tid].type == PT_LWP) { 606132332Smarcel info->ti_type = TD_THR_SYSTEM; 607132332Smarcel info->ti_lid = ta->map[th->th_tid].lwp; 608132332Smarcel info->ti_tid = th->th_tid; 609132332Smarcel info->ti_state = TD_THR_RUN; 610132332Smarcel info->ti_type = TD_THR_SYSTEM; 611132332Smarcel return (TD_OK); 612132332Smarcel } 613133802Sdavidxu ret = ps_pread(ta->ph, ta->map[th->th_tid].thr + ta->thread_off_tcb, 614133802Sdavidxu &tcb_addr, sizeof(tcb_addr)); 615132332Smarcel if (ret != 0) 616132332Smarcel return (P2T(ret)); 617133802Sdavidxu ret = ps_pread(ta->ph, ta->map[th->th_tid].thr + ta->thread_off_state, 618133802Sdavidxu &state, sizeof(state)); 619132332Smarcel ret = ps_pread(ta->ph, 620133802Sdavidxu tcb_addr + ta->thread_off_tmbx + 621133802Sdavidxu offsetof(struct kse_thr_mailbox, tm_lwp), 622132332Smarcel &info->ti_lid, sizeof(lwpid_t)); 623132332Smarcel if (ret != 0) 624132332Smarcel return (P2T(ret)); 625132951Sdavidxu ret = ps_pread(ta->ph, 626133802Sdavidxu tcb_addr + ta->thread_off_tmbx + 627133802Sdavidxu offsetof(struct kse_thr_mailbox, tm_dflags), 628132951Sdavidxu &dflags, sizeof(dflags)); 629132951Sdavidxu if (ret != 0) 630132951Sdavidxu return (P2T(ret)); 631132332Smarcel info->ti_ta_p = th->th_ta; 632132332Smarcel info->ti_tid = th->th_tid; 633133802Sdavidxu if (state == ta->thread_state_running) 634132332Smarcel info->ti_state = TD_THR_RUN; 635133802Sdavidxu else if (state == ta->thread_state_zoombie) 636133802Sdavidxu info->ti_state = TD_THR_ZOMBIE; 637133802Sdavidxu else 638132332Smarcel info->ti_state = TD_THR_SLEEP; 639133047Sdavidxu info->ti_db_suspended = ((dflags & TMDF_SUSPEND) != 0); 640132332Smarcel info->ti_type = TD_THR_USER; 641132332Smarcel return (0); 642132332Smarcel} 643132332Smarcel 644132332Smarcelstatic td_err_e 645132332Smarcelpt_thr_getfpregs(const td_thrhandle_t *th, prfpregset_t *fpregs) 646132332Smarcel{ 647132332Smarcel const td_thragent_t *ta = th->th_ta; 648132332Smarcel struct kse_thr_mailbox tmbx; 649132332Smarcel psaddr_t tcb_addr, tmbx_addr, ptr; 650132332Smarcel lwpid_t lwp; 651132332Smarcel int ret; 652132332Smarcel 653132332Smarcel TDBG_FUNC(); 654132332Smarcel 655132332Smarcel ret = pt_validate(th); 656132332Smarcel if (ret) 657132332Smarcel return (ret); 658132332Smarcel 659132332Smarcel if (ta->map[th->th_tid].type == PT_LWP) { 660132332Smarcel ret = ps_lgetfpregs(ta->ph, ta->map[th->th_tid].lwp, fpregs); 661132332Smarcel return (P2T(ret)); 662132332Smarcel } 663132332Smarcel 664133802Sdavidxu ret = ps_pread(ta->ph, ta->map[th->th_tid].thr + ta->thread_off_tcb, 665132951Sdavidxu &tcb_addr, sizeof(tcb_addr)); 666132332Smarcel if (ret != 0) 667132332Smarcel return (P2T(ret)); 668133802Sdavidxu tmbx_addr = tcb_addr + ta->thread_off_tmbx; 669132332Smarcel ptr = tmbx_addr + offsetof(struct kse_thr_mailbox, tm_lwp); 670132332Smarcel ret = ps_pread(ta->ph, ptr, &lwp, sizeof(lwpid_t)); 671132332Smarcel if (ret != 0) 672132332Smarcel return (P2T(ret)); 673132332Smarcel if (lwp != 0) { 674132332Smarcel ret = ps_lgetfpregs(ta->ph, lwp, fpregs); 675132332Smarcel return (P2T(ret)); 676132332Smarcel } 677132332Smarcel 678132332Smarcel ret = ps_pread(ta->ph, tmbx_addr, &tmbx, sizeof(tmbx)); 679132332Smarcel if (ret != 0) 680132332Smarcel return (P2T(ret)); 681132332Smarcel pt_ucontext_to_fpreg(&tmbx.tm_context, fpregs); 682132332Smarcel return (0); 683132332Smarcel} 684132332Smarcel 685132332Smarcelstatic td_err_e 686132332Smarcelpt_thr_getgregs(const td_thrhandle_t *th, prgregset_t gregs) 687132332Smarcel{ 688132332Smarcel const td_thragent_t *ta = th->th_ta; 689132332Smarcel struct kse_thr_mailbox tmbx; 690132332Smarcel psaddr_t tcb_addr, tmbx_addr, ptr; 691132332Smarcel lwpid_t lwp; 692132332Smarcel int ret; 693132332Smarcel 694132332Smarcel TDBG_FUNC(); 695132332Smarcel 696132332Smarcel ret = pt_validate(th); 697132332Smarcel if (ret) 698132332Smarcel return (ret); 699132332Smarcel 700132332Smarcel if (ta->map[th->th_tid].type == PT_LWP) { 701132332Smarcel ret = ps_lgetregs(ta->ph, 702132332Smarcel ta->map[th->th_tid].lwp, gregs); 703132332Smarcel return (P2T(ret)); 704132332Smarcel } 705132332Smarcel 706133802Sdavidxu ret = ps_pread(ta->ph, ta->map[th->th_tid].thr + ta->thread_off_tcb, 707132332Smarcel &tcb_addr, sizeof(tcb_addr)); 708132332Smarcel if (ret != 0) 709132332Smarcel return (P2T(ret)); 710133802Sdavidxu tmbx_addr = tcb_addr + ta->thread_off_tmbx; 711132332Smarcel ptr = tmbx_addr + offsetof(struct kse_thr_mailbox, tm_lwp); 712132332Smarcel ret = ps_pread(ta->ph, ptr, &lwp, sizeof(lwpid_t)); 713132332Smarcel if (ret != 0) 714132332Smarcel return (P2T(ret)); 715132332Smarcel if (lwp != 0) { 716132332Smarcel ret = ps_lgetregs(ta->ph, lwp, gregs); 717132332Smarcel return (P2T(ret)); 718132332Smarcel } 719132332Smarcel ret = ps_pread(ta->ph, tmbx_addr, &tmbx, sizeof(tmbx)); 720132332Smarcel if (ret != 0) 721132332Smarcel return (P2T(ret)); 722132332Smarcel pt_ucontext_to_reg(&tmbx.tm_context, gregs); 723132332Smarcel return (0); 724132332Smarcel} 725132332Smarcel 726132332Smarcelstatic td_err_e 727132332Smarcelpt_thr_setfpregs(const td_thrhandle_t *th, const prfpregset_t *fpregs) 728132332Smarcel{ 729132332Smarcel const td_thragent_t *ta = th->th_ta; 730132332Smarcel struct kse_thr_mailbox tmbx; 731132332Smarcel psaddr_t tcb_addr, tmbx_addr, ptr; 732132332Smarcel lwpid_t lwp; 733132332Smarcel int ret; 734132332Smarcel 735132332Smarcel TDBG_FUNC(); 736132332Smarcel 737132332Smarcel ret = pt_validate(th); 738132332Smarcel if (ret) 739132332Smarcel return (ret); 740132332Smarcel 741132332Smarcel if (ta->map[th->th_tid].type == PT_LWP) { 742132332Smarcel ret = ps_lsetfpregs(ta->ph, ta->map[th->th_tid].lwp, fpregs); 743132332Smarcel return (P2T(ret)); 744132332Smarcel } 745132332Smarcel 746132332Smarcel ret = ps_pread(ta->ph, ta->map[th->th_tid].thr + 747133802Sdavidxu ta->thread_off_tcb, 748132332Smarcel &tcb_addr, sizeof(tcb_addr)); 749132332Smarcel if (ret != 0) 750132332Smarcel return (P2T(ret)); 751133802Sdavidxu tmbx_addr = tcb_addr + ta->thread_off_tmbx; 752132332Smarcel ptr = tmbx_addr + offsetof(struct kse_thr_mailbox, tm_lwp); 753132332Smarcel ret = ps_pread(ta->ph, ptr, &lwp, sizeof(lwpid_t)); 754132332Smarcel if (ret != 0) 755132332Smarcel return (P2T(ret)); 756132332Smarcel if (lwp != 0) { 757132332Smarcel ret = ps_lsetfpregs(ta->ph, lwp, fpregs); 758132332Smarcel return (P2T(ret)); 759132332Smarcel } 760132332Smarcel /* 761132332Smarcel * Read a copy of context, this makes sure that registers 762132332Smarcel * not covered by structure reg won't be clobbered 763132332Smarcel */ 764132332Smarcel ret = ps_pread(ta->ph, tmbx_addr, &tmbx, sizeof(tmbx)); 765132332Smarcel if (ret != 0) 766132332Smarcel return (P2T(ret)); 767132332Smarcel 768132332Smarcel pt_fpreg_to_ucontext(fpregs, &tmbx.tm_context); 769132332Smarcel ret = ps_pwrite(ta->ph, tmbx_addr, &tmbx, sizeof(tmbx)); 770132332Smarcel return (P2T(ret)); 771132332Smarcel} 772132332Smarcel 773132332Smarcelstatic td_err_e 774132332Smarcelpt_thr_setgregs(const td_thrhandle_t *th, const prgregset_t gregs) 775132332Smarcel{ 776132332Smarcel const td_thragent_t *ta = th->th_ta; 777132332Smarcel struct kse_thr_mailbox tmbx; 778132332Smarcel psaddr_t tcb_addr, tmbx_addr, ptr; 779132332Smarcel lwpid_t lwp; 780132332Smarcel int ret; 781132332Smarcel 782132332Smarcel TDBG_FUNC(); 783132332Smarcel 784132332Smarcel ret = pt_validate(th); 785132332Smarcel if (ret) 786132332Smarcel return (ret); 787132332Smarcel 788132332Smarcel if (ta->map[th->th_tid].type == PT_LWP) { 789132332Smarcel ret = ps_lsetregs(ta->ph, ta->map[th->th_tid].lwp, gregs); 790132332Smarcel return (P2T(ret)); 791132332Smarcel } 792132332Smarcel 793132332Smarcel ret = ps_pread(ta->ph, ta->map[th->th_tid].thr + 794133802Sdavidxu ta->thread_off_tcb, 795132332Smarcel &tcb_addr, sizeof(tcb_addr)); 796132332Smarcel if (ret != 0) 797132332Smarcel return (P2T(ret)); 798133802Sdavidxu tmbx_addr = tcb_addr + ta->thread_off_tmbx; 799132332Smarcel ptr = tmbx_addr + offsetof(struct kse_thr_mailbox, tm_lwp); 800132332Smarcel ret = ps_pread(ta->ph, ptr, &lwp, sizeof(lwpid_t)); 801132332Smarcel if (ret != 0) 802132332Smarcel return (P2T(ret)); 803132332Smarcel if (lwp != 0) { 804132332Smarcel ret = ps_lsetregs(ta->ph, lwp, gregs); 805132332Smarcel return (P2T(ret)); 806132332Smarcel } 807132332Smarcel 808132332Smarcel /* 809132332Smarcel * Read a copy of context, make sure that registers 810132332Smarcel * not covered by structure reg won't be clobbered 811132332Smarcel */ 812132332Smarcel ret = ps_pread(ta->ph, tmbx_addr, &tmbx, sizeof(tmbx)); 813132332Smarcel if (ret != 0) 814132332Smarcel return (P2T(ret)); 815132332Smarcel pt_reg_to_ucontext(gregs, &tmbx.tm_context); 816132332Smarcel ret = ps_pwrite(ta->ph, tmbx_addr, &tmbx, sizeof(tmbx)); 817132332Smarcel return (P2T(ret)); 818132332Smarcel} 819132332Smarcel 820132332Smarcelstatic td_err_e 821132332Smarcelpt_thr_event_enable(const td_thrhandle_t *th, int en) 822132332Smarcel{ 823132332Smarcel TDBG_FUNC(); 824144922Sdavidxu return (0); 825132332Smarcel} 826132332Smarcel 827132332Smarcelstatic td_err_e 828132332Smarcelpt_thr_set_event(const td_thrhandle_t *th, td_thr_events_t *setp) 829132332Smarcel{ 830132332Smarcel TDBG_FUNC(); 831144922Sdavidxu return (0); 832132332Smarcel} 833132332Smarcel 834132332Smarcelstatic td_err_e 835132332Smarcelpt_thr_clear_event(const td_thrhandle_t *th, td_thr_events_t *setp) 836132332Smarcel{ 837132332Smarcel TDBG_FUNC(); 838144922Sdavidxu return (0); 839132332Smarcel} 840132332Smarcel 841132332Smarcelstatic td_err_e 842132332Smarcelpt_thr_event_getmsg(const td_thrhandle_t *th, td_event_msg_t *msg) 843132332Smarcel{ 844132332Smarcel TDBG_FUNC(); 845132332Smarcel return (TD_NOMSG); 846132332Smarcel} 847132332Smarcel 848132332Smarcelstatic td_err_e 849132332Smarcelpt_thr_sstep(const td_thrhandle_t *th, int step) 850132332Smarcel{ 851132332Smarcel const td_thragent_t *ta = th->th_ta; 852132332Smarcel struct kse_thr_mailbox tmbx; 853132332Smarcel struct reg regs; 854132332Smarcel psaddr_t tcb_addr, tmbx_addr; 855132951Sdavidxu uint32_t dflags; 856132332Smarcel lwpid_t lwp; 857132332Smarcel int ret; 858132332Smarcel 859132332Smarcel TDBG_FUNC(); 860132332Smarcel 861132332Smarcel ret = pt_validate(th); 862132332Smarcel if (ret) 863132332Smarcel return (ret); 864132332Smarcel 865132332Smarcel if (ta->map[th->th_tid].type == PT_LWP) 866132332Smarcel return (TD_BADTH); 867132332Smarcel 868132332Smarcel ret = ps_pread(ta->ph, ta->map[th->th_tid].thr + 869133802Sdavidxu ta->thread_off_tcb, 870132332Smarcel &tcb_addr, sizeof(tcb_addr)); 871132332Smarcel if (ret != 0) 872132332Smarcel return (P2T(ret)); 873132332Smarcel 874132332Smarcel /* Clear or set single step flag in thread mailbox */ 875133802Sdavidxu ret = ps_pread(ta->ph, 876133802Sdavidxu tcb_addr + ta->thread_off_tmbx + 877133802Sdavidxu offsetof(struct kse_thr_mailbox, tm_dflags), 878133802Sdavidxu &dflags, sizeof(uint32_t)); 879132951Sdavidxu if (ret != 0) 880132951Sdavidxu return (P2T(ret)); 881132951Sdavidxu if (step != 0) 882132951Sdavidxu dflags |= TMDF_SSTEP; 883132951Sdavidxu else 884132951Sdavidxu dflags &= ~TMDF_SSTEP; 885133802Sdavidxu ret = ps_pwrite(ta->ph, 886133802Sdavidxu tcb_addr + ta->thread_off_tmbx + 887133802Sdavidxu offsetof(struct kse_thr_mailbox, tm_dflags), 888133802Sdavidxu &dflags, sizeof(uint32_t)); 889132332Smarcel if (ret != 0) 890132332Smarcel return (P2T(ret)); 891132332Smarcel /* Get lwp */ 892133802Sdavidxu ret = ps_pread(ta->ph, 893133802Sdavidxu tcb_addr + ta->thread_off_tmbx + 894133802Sdavidxu offsetof(struct kse_thr_mailbox, tm_lwp), 895133802Sdavidxu &lwp, sizeof(lwpid_t)); 896132332Smarcel if (ret != 0) 897132332Smarcel return (P2T(ret)); 898132332Smarcel if (lwp != 0) 899132951Sdavidxu return (0); 900132332Smarcel 901133802Sdavidxu tmbx_addr = tcb_addr + ta->thread_off_tmbx; 902132332Smarcel /* 903132332Smarcel * context is in userland, some architectures store 904132332Smarcel * single step status in registers, we should change 905132332Smarcel * these registers. 906132332Smarcel */ 907132332Smarcel ret = ps_pread(ta->ph, tmbx_addr, &tmbx, sizeof(tmbx)); 908132332Smarcel if (ret == 0) { 909132332Smarcel pt_ucontext_to_reg(&tmbx.tm_context, ®s); 910132332Smarcel /* only write out if it is really changed. */ 911132332Smarcel if (pt_reg_sstep(®s, step) != 0) { 912132332Smarcel pt_reg_to_ucontext(®s, &tmbx.tm_context); 913132332Smarcel ret = ps_pwrite(ta->ph, tmbx_addr, &tmbx, 914132332Smarcel sizeof(tmbx)); 915132332Smarcel } 916132332Smarcel } 917132332Smarcel return (P2T(ret)); 918132332Smarcel} 919132332Smarcel 920132332Smarcelstatic void 921132332Smarcelpt_unmap_lwp(const td_thragent_t *ta, lwpid_t lwp) 922132332Smarcel{ 923132332Smarcel int i; 924132332Smarcel 925132332Smarcel for (i = 0; i < ta->map_len; ++i) { 926132332Smarcel if (ta->map[i].type == PT_LWP && ta->map[i].lwp == lwp) { 927132332Smarcel ta->map[i].type = PT_NONE; 928132332Smarcel return; 929132332Smarcel } 930132332Smarcel } 931132332Smarcel} 932132332Smarcel 933132332Smarcelstatic int 934132332Smarcelpt_validate(const td_thrhandle_t *th) 935132332Smarcel{ 936132332Smarcel 937132332Smarcel if (th->th_tid < 0 || th->th_tid >= th->th_ta->map_len || 938132332Smarcel th->th_ta->map[th->th_tid].type == PT_NONE) 939132332Smarcel return (TD_NOTHR); 940132332Smarcel return (TD_OK); 941132332Smarcel} 942132332Smarcel 943133342Sdavidxutd_err_e 944133342Sdavidxupt_thr_tls_get_addr(const td_thrhandle_t *th, void *_linkmap, size_t offset, 945133342Sdavidxu void **address) 946133342Sdavidxu{ 947133802Sdavidxu char *obj_entry; 948133342Sdavidxu const td_thragent_t *ta = th->th_ta; 949146447Scharnier psaddr_t tcb_addr, *dtv_addr; 950133342Sdavidxu int tls_index, ret; 951133342Sdavidxu 952133342Sdavidxu /* linkmap is a member of Obj_Entry */ 953133802Sdavidxu obj_entry = (char *)_linkmap - ta->thread_off_linkmap; 954133342Sdavidxu 955133342Sdavidxu /* get tlsindex of the object file */ 956133342Sdavidxu ret = ps_pread(ta->ph, 957133802Sdavidxu obj_entry + ta->thread_off_tlsindex, 958133342Sdavidxu &tls_index, sizeof(tls_index)); 959133342Sdavidxu if (ret != 0) 960133342Sdavidxu return (P2T(ret)); 961133342Sdavidxu 962133342Sdavidxu /* get thread tcb */ 963133342Sdavidxu ret = ps_pread(ta->ph, ta->map[th->th_tid].thr + 964133802Sdavidxu ta->thread_off_tcb, 965133342Sdavidxu &tcb_addr, sizeof(tcb_addr)); 966133342Sdavidxu if (ret != 0) 967133342Sdavidxu return (P2T(ret)); 968133342Sdavidxu 969133342Sdavidxu /* get dtv array address */ 970133802Sdavidxu ret = ps_pread(ta->ph, tcb_addr + ta->thread_off_dtv, 971133342Sdavidxu &dtv_addr, sizeof(dtv_addr)); 972133342Sdavidxu if (ret != 0) 973133342Sdavidxu return (P2T(ret)); 974133342Sdavidxu /* now get the object's tls block base address */ 975133342Sdavidxu ret = ps_pread(ta->ph, &dtv_addr[tls_index+1], address, 976133342Sdavidxu sizeof(*address)); 977133342Sdavidxu if (ret != 0) 978133342Sdavidxu return (P2T(ret)); 979133342Sdavidxu 980133342Sdavidxu *address += offset; 981133342Sdavidxu return (TD_OK); 982133342Sdavidxu} 983133342Sdavidxu 984132332Smarcelstruct ta_ops libpthread_db_ops = { 985132332Smarcel .to_init = pt_init, 986132332Smarcel .to_ta_clear_event = pt_ta_clear_event, 987132332Smarcel .to_ta_delete = pt_ta_delete, 988132332Smarcel .to_ta_event_addr = pt_ta_event_addr, 989132332Smarcel .to_ta_event_getmsg = pt_ta_event_getmsg, 990132332Smarcel .to_ta_map_id2thr = pt_ta_map_id2thr, 991132332Smarcel .to_ta_map_lwp2thr = pt_ta_map_lwp2thr, 992132332Smarcel .to_ta_new = pt_ta_new, 993132332Smarcel .to_ta_set_event = pt_ta_set_event, 994132332Smarcel .to_ta_thr_iter = pt_ta_thr_iter, 995132332Smarcel .to_ta_tsd_iter = pt_ta_tsd_iter, 996132332Smarcel .to_thr_clear_event = pt_thr_clear_event, 997132332Smarcel .to_thr_dbresume = pt_thr_dbresume, 998132332Smarcel .to_thr_dbsuspend = pt_thr_dbsuspend, 999132332Smarcel .to_thr_event_enable = pt_thr_event_enable, 1000132332Smarcel .to_thr_event_getmsg = pt_thr_event_getmsg, 1001132332Smarcel .to_thr_get_info = pt_thr_get_info, 1002132332Smarcel .to_thr_getfpregs = pt_thr_getfpregs, 1003132332Smarcel .to_thr_getgregs = pt_thr_getgregs, 1004132332Smarcel .to_thr_set_event = pt_thr_set_event, 1005132332Smarcel .to_thr_setfpregs = pt_thr_setfpregs, 1006132332Smarcel .to_thr_setgregs = pt_thr_setgregs, 1007132332Smarcel .to_thr_validate = pt_thr_validate, 1008133342Sdavidxu .to_thr_tls_get_addr = pt_thr_tls_get_addr, 1009132332Smarcel 1010132332Smarcel /* FreeBSD specific extensions. */ 1011132332Smarcel .to_thr_sstep = pt_thr_sstep, 1012132332Smarcel}; 1013