libpthread_db.c revision 146818
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 146818 2005-05-31 09:43:04Z dfr $"); 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 644146818Sdfr#ifdef __i386__ 645132332Smarcelstatic td_err_e 646146818Sdfrpt_thr_getxmmregs(const td_thrhandle_t *th, char *fxsave) 647146818Sdfr{ 648146818Sdfr const td_thragent_t *ta = th->th_ta; 649146818Sdfr struct kse_thr_mailbox tmbx; 650146818Sdfr psaddr_t tcb_addr, tmbx_addr, ptr; 651146818Sdfr lwpid_t lwp; 652146818Sdfr int ret; 653146818Sdfr 654146818Sdfr return TD_ERR; 655146818Sdfr 656146818Sdfr TDBG_FUNC(); 657146818Sdfr 658146818Sdfr ret = pt_validate(th); 659146818Sdfr if (ret) 660146818Sdfr return (ret); 661146818Sdfr 662146818Sdfr if (ta->map[th->th_tid].type == PT_LWP) { 663146818Sdfr ret = ps_lgetxmmregs(ta->ph, ta->map[th->th_tid].lwp, fxsave); 664146818Sdfr return (P2T(ret)); 665146818Sdfr } 666146818Sdfr 667146818Sdfr ret = ps_pread(ta->ph, ta->map[th->th_tid].thr + ta->thread_off_tcb, 668146818Sdfr &tcb_addr, sizeof(tcb_addr)); 669146818Sdfr if (ret != 0) 670146818Sdfr return (P2T(ret)); 671146818Sdfr tmbx_addr = tcb_addr + ta->thread_off_tmbx; 672146818Sdfr ptr = tmbx_addr + offsetof(struct kse_thr_mailbox, tm_lwp); 673146818Sdfr ret = ps_pread(ta->ph, ptr, &lwp, sizeof(lwpid_t)); 674146818Sdfr if (ret != 0) 675146818Sdfr return (P2T(ret)); 676146818Sdfr if (lwp != 0) { 677146818Sdfr ret = ps_lgetxmmregs(ta->ph, lwp, fxsave); 678146818Sdfr return (P2T(ret)); 679146818Sdfr } 680146818Sdfr 681146818Sdfr ret = ps_pread(ta->ph, tmbx_addr, &tmbx, sizeof(tmbx)); 682146818Sdfr if (ret != 0) 683146818Sdfr return (P2T(ret)); 684146818Sdfr pt_ucontext_to_fxsave(&tmbx.tm_context, fxsave); 685146818Sdfr return (0); 686146818Sdfr} 687146818Sdfr#endif 688146818Sdfr 689146818Sdfrstatic td_err_e 690132332Smarcelpt_thr_getfpregs(const td_thrhandle_t *th, prfpregset_t *fpregs) 691132332Smarcel{ 692132332Smarcel const td_thragent_t *ta = th->th_ta; 693132332Smarcel struct kse_thr_mailbox tmbx; 694132332Smarcel psaddr_t tcb_addr, tmbx_addr, ptr; 695132332Smarcel lwpid_t lwp; 696132332Smarcel int ret; 697132332Smarcel 698132332Smarcel TDBG_FUNC(); 699132332Smarcel 700132332Smarcel ret = pt_validate(th); 701132332Smarcel if (ret) 702132332Smarcel return (ret); 703132332Smarcel 704132332Smarcel if (ta->map[th->th_tid].type == PT_LWP) { 705132332Smarcel ret = ps_lgetfpregs(ta->ph, ta->map[th->th_tid].lwp, fpregs); 706132332Smarcel return (P2T(ret)); 707132332Smarcel } 708132332Smarcel 709133802Sdavidxu ret = ps_pread(ta->ph, ta->map[th->th_tid].thr + ta->thread_off_tcb, 710132951Sdavidxu &tcb_addr, sizeof(tcb_addr)); 711132332Smarcel if (ret != 0) 712132332Smarcel return (P2T(ret)); 713133802Sdavidxu tmbx_addr = tcb_addr + ta->thread_off_tmbx; 714132332Smarcel ptr = tmbx_addr + offsetof(struct kse_thr_mailbox, tm_lwp); 715132332Smarcel ret = ps_pread(ta->ph, ptr, &lwp, sizeof(lwpid_t)); 716132332Smarcel if (ret != 0) 717132332Smarcel return (P2T(ret)); 718132332Smarcel if (lwp != 0) { 719132332Smarcel ret = ps_lgetfpregs(ta->ph, lwp, fpregs); 720132332Smarcel return (P2T(ret)); 721132332Smarcel } 722132332Smarcel 723132332Smarcel ret = ps_pread(ta->ph, tmbx_addr, &tmbx, sizeof(tmbx)); 724132332Smarcel if (ret != 0) 725132332Smarcel return (P2T(ret)); 726132332Smarcel pt_ucontext_to_fpreg(&tmbx.tm_context, fpregs); 727132332Smarcel return (0); 728132332Smarcel} 729132332Smarcel 730132332Smarcelstatic td_err_e 731132332Smarcelpt_thr_getgregs(const td_thrhandle_t *th, prgregset_t gregs) 732132332Smarcel{ 733132332Smarcel const td_thragent_t *ta = th->th_ta; 734132332Smarcel struct kse_thr_mailbox tmbx; 735132332Smarcel psaddr_t tcb_addr, tmbx_addr, ptr; 736132332Smarcel lwpid_t lwp; 737132332Smarcel int ret; 738132332Smarcel 739132332Smarcel TDBG_FUNC(); 740132332Smarcel 741132332Smarcel ret = pt_validate(th); 742132332Smarcel if (ret) 743132332Smarcel return (ret); 744132332Smarcel 745132332Smarcel if (ta->map[th->th_tid].type == PT_LWP) { 746132332Smarcel ret = ps_lgetregs(ta->ph, 747132332Smarcel ta->map[th->th_tid].lwp, gregs); 748132332Smarcel return (P2T(ret)); 749132332Smarcel } 750132332Smarcel 751133802Sdavidxu ret = ps_pread(ta->ph, ta->map[th->th_tid].thr + ta->thread_off_tcb, 752132332Smarcel &tcb_addr, sizeof(tcb_addr)); 753132332Smarcel if (ret != 0) 754132332Smarcel return (P2T(ret)); 755133802Sdavidxu tmbx_addr = tcb_addr + ta->thread_off_tmbx; 756132332Smarcel ptr = tmbx_addr + offsetof(struct kse_thr_mailbox, tm_lwp); 757132332Smarcel ret = ps_pread(ta->ph, ptr, &lwp, sizeof(lwpid_t)); 758132332Smarcel if (ret != 0) 759132332Smarcel return (P2T(ret)); 760132332Smarcel if (lwp != 0) { 761132332Smarcel ret = ps_lgetregs(ta->ph, lwp, gregs); 762132332Smarcel return (P2T(ret)); 763132332Smarcel } 764132332Smarcel ret = ps_pread(ta->ph, tmbx_addr, &tmbx, sizeof(tmbx)); 765132332Smarcel if (ret != 0) 766132332Smarcel return (P2T(ret)); 767132332Smarcel pt_ucontext_to_reg(&tmbx.tm_context, gregs); 768132332Smarcel return (0); 769132332Smarcel} 770132332Smarcel 771146818Sdfr#ifdef __i386__ 772132332Smarcelstatic td_err_e 773146818Sdfrpt_thr_setxmmregs(const td_thrhandle_t *th, const char *fxsave) 774146818Sdfr{ 775146818Sdfr const td_thragent_t *ta = th->th_ta; 776146818Sdfr struct kse_thr_mailbox tmbx; 777146818Sdfr psaddr_t tcb_addr, tmbx_addr, ptr; 778146818Sdfr lwpid_t lwp; 779146818Sdfr int ret; 780146818Sdfr 781146818Sdfr return TD_ERR; 782146818Sdfr 783146818Sdfr TDBG_FUNC(); 784146818Sdfr 785146818Sdfr ret = pt_validate(th); 786146818Sdfr if (ret) 787146818Sdfr return (ret); 788146818Sdfr 789146818Sdfr if (ta->map[th->th_tid].type == PT_LWP) { 790146818Sdfr ret = ps_lsetxmmregs(ta->ph, ta->map[th->th_tid].lwp, fxsave); 791146818Sdfr return (P2T(ret)); 792146818Sdfr } 793146818Sdfr 794146818Sdfr ret = ps_pread(ta->ph, ta->map[th->th_tid].thr + 795146818Sdfr ta->thread_off_tcb, 796146818Sdfr &tcb_addr, sizeof(tcb_addr)); 797146818Sdfr if (ret != 0) 798146818Sdfr return (P2T(ret)); 799146818Sdfr tmbx_addr = tcb_addr + ta->thread_off_tmbx; 800146818Sdfr ptr = tmbx_addr + offsetof(struct kse_thr_mailbox, tm_lwp); 801146818Sdfr ret = ps_pread(ta->ph, ptr, &lwp, sizeof(lwpid_t)); 802146818Sdfr if (ret != 0) 803146818Sdfr return (P2T(ret)); 804146818Sdfr if (lwp != 0) { 805146818Sdfr ret = ps_lsetxmmregs(ta->ph, lwp, fxsave); 806146818Sdfr return (P2T(ret)); 807146818Sdfr } 808146818Sdfr /* 809146818Sdfr * Read a copy of context, this makes sure that registers 810146818Sdfr * not covered by structure reg won't be clobbered 811146818Sdfr */ 812146818Sdfr ret = ps_pread(ta->ph, tmbx_addr, &tmbx, sizeof(tmbx)); 813146818Sdfr if (ret != 0) 814146818Sdfr return (P2T(ret)); 815146818Sdfr 816146818Sdfr pt_fxsave_to_ucontext(fxsave, &tmbx.tm_context); 817146818Sdfr ret = ps_pwrite(ta->ph, tmbx_addr, &tmbx, sizeof(tmbx)); 818146818Sdfr return (P2T(ret)); 819146818Sdfr} 820146818Sdfr#endif 821146818Sdfr 822146818Sdfrstatic td_err_e 823132332Smarcelpt_thr_setfpregs(const td_thrhandle_t *th, const prfpregset_t *fpregs) 824132332Smarcel{ 825132332Smarcel const td_thragent_t *ta = th->th_ta; 826132332Smarcel struct kse_thr_mailbox tmbx; 827132332Smarcel psaddr_t tcb_addr, tmbx_addr, ptr; 828132332Smarcel lwpid_t lwp; 829132332Smarcel int ret; 830132332Smarcel 831132332Smarcel TDBG_FUNC(); 832132332Smarcel 833132332Smarcel ret = pt_validate(th); 834132332Smarcel if (ret) 835132332Smarcel return (ret); 836132332Smarcel 837132332Smarcel if (ta->map[th->th_tid].type == PT_LWP) { 838132332Smarcel ret = ps_lsetfpregs(ta->ph, ta->map[th->th_tid].lwp, fpregs); 839132332Smarcel return (P2T(ret)); 840132332Smarcel } 841132332Smarcel 842132332Smarcel ret = ps_pread(ta->ph, ta->map[th->th_tid].thr + 843133802Sdavidxu ta->thread_off_tcb, 844132332Smarcel &tcb_addr, sizeof(tcb_addr)); 845132332Smarcel if (ret != 0) 846132332Smarcel return (P2T(ret)); 847133802Sdavidxu tmbx_addr = tcb_addr + ta->thread_off_tmbx; 848132332Smarcel ptr = tmbx_addr + offsetof(struct kse_thr_mailbox, tm_lwp); 849132332Smarcel ret = ps_pread(ta->ph, ptr, &lwp, sizeof(lwpid_t)); 850132332Smarcel if (ret != 0) 851132332Smarcel return (P2T(ret)); 852132332Smarcel if (lwp != 0) { 853132332Smarcel ret = ps_lsetfpregs(ta->ph, lwp, fpregs); 854132332Smarcel return (P2T(ret)); 855132332Smarcel } 856132332Smarcel /* 857132332Smarcel * Read a copy of context, this makes sure that registers 858132332Smarcel * not covered by structure reg won't be clobbered 859132332Smarcel */ 860132332Smarcel ret = ps_pread(ta->ph, tmbx_addr, &tmbx, sizeof(tmbx)); 861132332Smarcel if (ret != 0) 862132332Smarcel return (P2T(ret)); 863132332Smarcel 864132332Smarcel pt_fpreg_to_ucontext(fpregs, &tmbx.tm_context); 865132332Smarcel ret = ps_pwrite(ta->ph, tmbx_addr, &tmbx, sizeof(tmbx)); 866132332Smarcel return (P2T(ret)); 867132332Smarcel} 868132332Smarcel 869132332Smarcelstatic td_err_e 870132332Smarcelpt_thr_setgregs(const td_thrhandle_t *th, const prgregset_t gregs) 871132332Smarcel{ 872132332Smarcel const td_thragent_t *ta = th->th_ta; 873132332Smarcel struct kse_thr_mailbox tmbx; 874132332Smarcel psaddr_t tcb_addr, tmbx_addr, ptr; 875132332Smarcel lwpid_t lwp; 876132332Smarcel int ret; 877132332Smarcel 878132332Smarcel TDBG_FUNC(); 879132332Smarcel 880132332Smarcel ret = pt_validate(th); 881132332Smarcel if (ret) 882132332Smarcel return (ret); 883132332Smarcel 884132332Smarcel if (ta->map[th->th_tid].type == PT_LWP) { 885132332Smarcel ret = ps_lsetregs(ta->ph, ta->map[th->th_tid].lwp, gregs); 886132332Smarcel return (P2T(ret)); 887132332Smarcel } 888132332Smarcel 889132332Smarcel ret = ps_pread(ta->ph, ta->map[th->th_tid].thr + 890133802Sdavidxu ta->thread_off_tcb, 891132332Smarcel &tcb_addr, sizeof(tcb_addr)); 892132332Smarcel if (ret != 0) 893132332Smarcel return (P2T(ret)); 894133802Sdavidxu tmbx_addr = tcb_addr + ta->thread_off_tmbx; 895132332Smarcel ptr = tmbx_addr + offsetof(struct kse_thr_mailbox, tm_lwp); 896132332Smarcel ret = ps_pread(ta->ph, ptr, &lwp, sizeof(lwpid_t)); 897132332Smarcel if (ret != 0) 898132332Smarcel return (P2T(ret)); 899132332Smarcel if (lwp != 0) { 900132332Smarcel ret = ps_lsetregs(ta->ph, lwp, gregs); 901132332Smarcel return (P2T(ret)); 902132332Smarcel } 903132332Smarcel 904132332Smarcel /* 905132332Smarcel * Read a copy of context, make sure that registers 906132332Smarcel * not covered by structure reg won't be clobbered 907132332Smarcel */ 908132332Smarcel ret = ps_pread(ta->ph, tmbx_addr, &tmbx, sizeof(tmbx)); 909132332Smarcel if (ret != 0) 910132332Smarcel return (P2T(ret)); 911132332Smarcel pt_reg_to_ucontext(gregs, &tmbx.tm_context); 912132332Smarcel ret = ps_pwrite(ta->ph, tmbx_addr, &tmbx, sizeof(tmbx)); 913132332Smarcel return (P2T(ret)); 914132332Smarcel} 915132332Smarcel 916132332Smarcelstatic td_err_e 917132332Smarcelpt_thr_event_enable(const td_thrhandle_t *th, int en) 918132332Smarcel{ 919132332Smarcel TDBG_FUNC(); 920144922Sdavidxu return (0); 921132332Smarcel} 922132332Smarcel 923132332Smarcelstatic td_err_e 924132332Smarcelpt_thr_set_event(const td_thrhandle_t *th, td_thr_events_t *setp) 925132332Smarcel{ 926132332Smarcel TDBG_FUNC(); 927144922Sdavidxu return (0); 928132332Smarcel} 929132332Smarcel 930132332Smarcelstatic td_err_e 931132332Smarcelpt_thr_clear_event(const td_thrhandle_t *th, td_thr_events_t *setp) 932132332Smarcel{ 933132332Smarcel TDBG_FUNC(); 934144922Sdavidxu return (0); 935132332Smarcel} 936132332Smarcel 937132332Smarcelstatic td_err_e 938132332Smarcelpt_thr_event_getmsg(const td_thrhandle_t *th, td_event_msg_t *msg) 939132332Smarcel{ 940132332Smarcel TDBG_FUNC(); 941132332Smarcel return (TD_NOMSG); 942132332Smarcel} 943132332Smarcel 944132332Smarcelstatic td_err_e 945132332Smarcelpt_thr_sstep(const td_thrhandle_t *th, int step) 946132332Smarcel{ 947132332Smarcel const td_thragent_t *ta = th->th_ta; 948132332Smarcel struct kse_thr_mailbox tmbx; 949132332Smarcel struct reg regs; 950132332Smarcel psaddr_t tcb_addr, tmbx_addr; 951132951Sdavidxu uint32_t dflags; 952132332Smarcel lwpid_t lwp; 953132332Smarcel int ret; 954132332Smarcel 955132332Smarcel TDBG_FUNC(); 956132332Smarcel 957132332Smarcel ret = pt_validate(th); 958132332Smarcel if (ret) 959132332Smarcel return (ret); 960132332Smarcel 961132332Smarcel if (ta->map[th->th_tid].type == PT_LWP) 962132332Smarcel return (TD_BADTH); 963132332Smarcel 964132332Smarcel ret = ps_pread(ta->ph, ta->map[th->th_tid].thr + 965133802Sdavidxu ta->thread_off_tcb, 966132332Smarcel &tcb_addr, sizeof(tcb_addr)); 967132332Smarcel if (ret != 0) 968132332Smarcel return (P2T(ret)); 969132332Smarcel 970132332Smarcel /* Clear or set single step flag in thread mailbox */ 971133802Sdavidxu ret = ps_pread(ta->ph, 972133802Sdavidxu tcb_addr + ta->thread_off_tmbx + 973133802Sdavidxu offsetof(struct kse_thr_mailbox, tm_dflags), 974133802Sdavidxu &dflags, sizeof(uint32_t)); 975132951Sdavidxu if (ret != 0) 976132951Sdavidxu return (P2T(ret)); 977132951Sdavidxu if (step != 0) 978132951Sdavidxu dflags |= TMDF_SSTEP; 979132951Sdavidxu else 980132951Sdavidxu dflags &= ~TMDF_SSTEP; 981133802Sdavidxu ret = ps_pwrite(ta->ph, 982133802Sdavidxu tcb_addr + ta->thread_off_tmbx + 983133802Sdavidxu offsetof(struct kse_thr_mailbox, tm_dflags), 984133802Sdavidxu &dflags, sizeof(uint32_t)); 985132332Smarcel if (ret != 0) 986132332Smarcel return (P2T(ret)); 987132332Smarcel /* Get lwp */ 988133802Sdavidxu ret = ps_pread(ta->ph, 989133802Sdavidxu tcb_addr + ta->thread_off_tmbx + 990133802Sdavidxu offsetof(struct kse_thr_mailbox, tm_lwp), 991133802Sdavidxu &lwp, sizeof(lwpid_t)); 992132332Smarcel if (ret != 0) 993132332Smarcel return (P2T(ret)); 994132332Smarcel if (lwp != 0) 995132951Sdavidxu return (0); 996132332Smarcel 997133802Sdavidxu tmbx_addr = tcb_addr + ta->thread_off_tmbx; 998132332Smarcel /* 999132332Smarcel * context is in userland, some architectures store 1000132332Smarcel * single step status in registers, we should change 1001132332Smarcel * these registers. 1002132332Smarcel */ 1003132332Smarcel ret = ps_pread(ta->ph, tmbx_addr, &tmbx, sizeof(tmbx)); 1004132332Smarcel if (ret == 0) { 1005132332Smarcel pt_ucontext_to_reg(&tmbx.tm_context, ®s); 1006132332Smarcel /* only write out if it is really changed. */ 1007132332Smarcel if (pt_reg_sstep(®s, step) != 0) { 1008132332Smarcel pt_reg_to_ucontext(®s, &tmbx.tm_context); 1009132332Smarcel ret = ps_pwrite(ta->ph, tmbx_addr, &tmbx, 1010132332Smarcel sizeof(tmbx)); 1011132332Smarcel } 1012132332Smarcel } 1013132332Smarcel return (P2T(ret)); 1014132332Smarcel} 1015132332Smarcel 1016132332Smarcelstatic void 1017132332Smarcelpt_unmap_lwp(const td_thragent_t *ta, lwpid_t lwp) 1018132332Smarcel{ 1019132332Smarcel int i; 1020132332Smarcel 1021132332Smarcel for (i = 0; i < ta->map_len; ++i) { 1022132332Smarcel if (ta->map[i].type == PT_LWP && ta->map[i].lwp == lwp) { 1023132332Smarcel ta->map[i].type = PT_NONE; 1024132332Smarcel return; 1025132332Smarcel } 1026132332Smarcel } 1027132332Smarcel} 1028132332Smarcel 1029132332Smarcelstatic int 1030132332Smarcelpt_validate(const td_thrhandle_t *th) 1031132332Smarcel{ 1032132332Smarcel 1033132332Smarcel if (th->th_tid < 0 || th->th_tid >= th->th_ta->map_len || 1034132332Smarcel th->th_ta->map[th->th_tid].type == PT_NONE) 1035132332Smarcel return (TD_NOTHR); 1036132332Smarcel return (TD_OK); 1037132332Smarcel} 1038132332Smarcel 1039133342Sdavidxutd_err_e 1040133342Sdavidxupt_thr_tls_get_addr(const td_thrhandle_t *th, void *_linkmap, size_t offset, 1041133342Sdavidxu void **address) 1042133342Sdavidxu{ 1043133802Sdavidxu char *obj_entry; 1044133342Sdavidxu const td_thragent_t *ta = th->th_ta; 1045146447Scharnier psaddr_t tcb_addr, *dtv_addr; 1046133342Sdavidxu int tls_index, ret; 1047133342Sdavidxu 1048133342Sdavidxu /* linkmap is a member of Obj_Entry */ 1049133802Sdavidxu obj_entry = (char *)_linkmap - ta->thread_off_linkmap; 1050133342Sdavidxu 1051133342Sdavidxu /* get tlsindex of the object file */ 1052133342Sdavidxu ret = ps_pread(ta->ph, 1053133802Sdavidxu obj_entry + ta->thread_off_tlsindex, 1054133342Sdavidxu &tls_index, sizeof(tls_index)); 1055133342Sdavidxu if (ret != 0) 1056133342Sdavidxu return (P2T(ret)); 1057133342Sdavidxu 1058133342Sdavidxu /* get thread tcb */ 1059133342Sdavidxu ret = ps_pread(ta->ph, ta->map[th->th_tid].thr + 1060133802Sdavidxu ta->thread_off_tcb, 1061133342Sdavidxu &tcb_addr, sizeof(tcb_addr)); 1062133342Sdavidxu if (ret != 0) 1063133342Sdavidxu return (P2T(ret)); 1064133342Sdavidxu 1065133342Sdavidxu /* get dtv array address */ 1066133802Sdavidxu ret = ps_pread(ta->ph, tcb_addr + ta->thread_off_dtv, 1067133342Sdavidxu &dtv_addr, sizeof(dtv_addr)); 1068133342Sdavidxu if (ret != 0) 1069133342Sdavidxu return (P2T(ret)); 1070133342Sdavidxu /* now get the object's tls block base address */ 1071133342Sdavidxu ret = ps_pread(ta->ph, &dtv_addr[tls_index+1], address, 1072133342Sdavidxu sizeof(*address)); 1073133342Sdavidxu if (ret != 0) 1074133342Sdavidxu return (P2T(ret)); 1075133342Sdavidxu 1076133342Sdavidxu *address += offset; 1077133342Sdavidxu return (TD_OK); 1078133342Sdavidxu} 1079133342Sdavidxu 1080132332Smarcelstruct ta_ops libpthread_db_ops = { 1081132332Smarcel .to_init = pt_init, 1082132332Smarcel .to_ta_clear_event = pt_ta_clear_event, 1083132332Smarcel .to_ta_delete = pt_ta_delete, 1084132332Smarcel .to_ta_event_addr = pt_ta_event_addr, 1085132332Smarcel .to_ta_event_getmsg = pt_ta_event_getmsg, 1086132332Smarcel .to_ta_map_id2thr = pt_ta_map_id2thr, 1087132332Smarcel .to_ta_map_lwp2thr = pt_ta_map_lwp2thr, 1088132332Smarcel .to_ta_new = pt_ta_new, 1089132332Smarcel .to_ta_set_event = pt_ta_set_event, 1090132332Smarcel .to_ta_thr_iter = pt_ta_thr_iter, 1091132332Smarcel .to_ta_tsd_iter = pt_ta_tsd_iter, 1092132332Smarcel .to_thr_clear_event = pt_thr_clear_event, 1093132332Smarcel .to_thr_dbresume = pt_thr_dbresume, 1094132332Smarcel .to_thr_dbsuspend = pt_thr_dbsuspend, 1095132332Smarcel .to_thr_event_enable = pt_thr_event_enable, 1096132332Smarcel .to_thr_event_getmsg = pt_thr_event_getmsg, 1097132332Smarcel .to_thr_get_info = pt_thr_get_info, 1098132332Smarcel .to_thr_getfpregs = pt_thr_getfpregs, 1099132332Smarcel .to_thr_getgregs = pt_thr_getgregs, 1100132332Smarcel .to_thr_set_event = pt_thr_set_event, 1101132332Smarcel .to_thr_setfpregs = pt_thr_setfpregs, 1102132332Smarcel .to_thr_setgregs = pt_thr_setgregs, 1103132332Smarcel .to_thr_validate = pt_thr_validate, 1104133342Sdavidxu .to_thr_tls_get_addr = pt_thr_tls_get_addr, 1105132332Smarcel 1106132332Smarcel /* FreeBSD specific extensions. */ 1107132332Smarcel .to_thr_sstep = pt_thr_sstep, 1108146818Sdfr#ifdef __i386__ 1109146818Sdfr .to_thr_getxmmregs = pt_thr_getxmmregs, 1110146818Sdfr .to_thr_setxmmregs = pt_thr_setxmmregs, 1111146818Sdfr#endif 1112132332Smarcel}; 1113