libpthread_db.c revision 181059
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 181059 2008-07-31 16:26:58Z marcel $"); 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> 36177490Sdavidxu#include <sys/linker_set.h> 37132332Smarcel#include <sys/ptrace.h> 38132332Smarcel#include <proc_service.h> 39132332Smarcel#include <thread_db.h> 40132332Smarcel 41132332Smarcel#include "libpthread_db.h" 42177526Sjeff#include "kse.h" 43132332Smarcel 44132332Smarcel#define P2T(c) ps2td(c) 45132332Smarcel 46132332Smarcelstatic void pt_unmap_lwp(const td_thragent_t *ta, lwpid_t lwp); 47132332Smarcelstatic int pt_validate(const td_thrhandle_t *th); 48132332Smarcel 49132332Smarcelstatic int 50132332Smarcelps2td(int c) 51132332Smarcel{ 52132332Smarcel switch (c) { 53132332Smarcel case PS_OK: 54132332Smarcel return TD_OK; 55132332Smarcel case PS_ERR: 56132332Smarcel return TD_ERR; 57132332Smarcel case PS_BADPID: 58132332Smarcel return TD_BADPH; 59132332Smarcel case PS_BADLID: 60132332Smarcel return TD_NOLWP; 61132332Smarcel case PS_BADADDR: 62132332Smarcel return TD_ERR; 63132332Smarcel case PS_NOSYM: 64132332Smarcel return TD_NOLIBTHREAD; 65132332Smarcel case PS_NOFREGS: 66132332Smarcel return TD_NOFPREGS; 67132332Smarcel default: 68132332Smarcel return TD_ERR; 69132332Smarcel } 70132332Smarcel} 71132332Smarcel 72132332Smarcelstatic long 73181059Smarcelpt_map_thread(const td_thragent_t *const_ta, psaddr_t pt, enum pt_type type) 74132332Smarcel{ 75132332Smarcel td_thragent_t *ta = __DECONST(td_thragent_t *, const_ta); 76132332Smarcel struct pt_map *new; 77132332Smarcel int i, first = -1; 78132332Smarcel 79132332Smarcel /* leave zero out */ 80132332Smarcel for (i = 1; i < ta->map_len; ++i) { 81132332Smarcel if (ta->map[i].type == PT_NONE) { 82132332Smarcel if (first == -1) 83132332Smarcel first = i; 84132332Smarcel } else if (ta->map[i].type == type && ta->map[i].thr == pt) { 85132332Smarcel return (i); 86132332Smarcel } 87132332Smarcel } 88132332Smarcel 89132332Smarcel if (first == -1) { 90132332Smarcel if (ta->map_len == 0) { 91132332Smarcel ta->map = calloc(20, sizeof(struct pt_map)); 92132332Smarcel if (ta->map == NULL) 93132332Smarcel return (-1); 94132332Smarcel ta->map_len = 20; 95132332Smarcel first = 1; 96132332Smarcel } else { 97132332Smarcel new = realloc(ta->map, 98132332Smarcel sizeof(struct pt_map) * ta->map_len * 2); 99132332Smarcel if (new == NULL) 100132332Smarcel return (-1); 101132332Smarcel memset(new + ta->map_len, '\0', sizeof(struct pt_map) * 102132332Smarcel ta->map_len); 103132332Smarcel first = ta->map_len; 104132332Smarcel ta->map = new; 105132332Smarcel ta->map_len *= 2; 106132332Smarcel } 107132332Smarcel } 108132332Smarcel 109132332Smarcel ta->map[first].type = type; 110132332Smarcel ta->map[first].thr = pt; 111132332Smarcel return (first); 112132332Smarcel} 113132332Smarcel 114132332Smarcelstatic td_err_e 115132332Smarcelpt_init(void) 116132332Smarcel{ 117132332Smarcel pt_md_init(); 118132332Smarcel return (0); 119132332Smarcel} 120132332Smarcel 121132332Smarcelstatic td_err_e 122132332Smarcelpt_ta_new(struct ps_prochandle *ph, td_thragent_t **pta) 123132332Smarcel{ 124132332Smarcel#define LOOKUP_SYM(proc, sym, addr) \ 125132332Smarcel ret = ps_pglobal_lookup(proc, NULL, sym, addr); \ 126132332Smarcel if (ret != 0) { \ 127132332Smarcel TDBG("can not find symbol: %s\n", sym); \ 128132332Smarcel ret = TD_NOLIBTHREAD; \ 129132332Smarcel goto error; \ 130132332Smarcel } 131132332Smarcel 132133802Sdavidxu#define LOOKUP_VAL(proc, sym, val) \ 133133802Sdavidxu ret = ps_pglobal_lookup(proc, NULL, sym, &vaddr);\ 134133802Sdavidxu if (ret != 0) { \ 135133802Sdavidxu TDBG("can not find symbol: %s\n", sym); \ 136133802Sdavidxu ret = TD_NOLIBTHREAD; \ 137133802Sdavidxu goto error; \ 138133802Sdavidxu } \ 139133802Sdavidxu ret = ps_pread(proc, vaddr, val, sizeof(int)); \ 140133802Sdavidxu if (ret != 0) { \ 141133802Sdavidxu TDBG("can not read value of %s\n", sym);\ 142133802Sdavidxu ret = TD_NOLIBTHREAD; \ 143133802Sdavidxu goto error; \ 144133802Sdavidxu } 145133802Sdavidxu 146132332Smarcel td_thragent_t *ta; 147133802Sdavidxu psaddr_t vaddr; 148132332Smarcel int dbg; 149132332Smarcel int ret; 150132332Smarcel 151132332Smarcel TDBG_FUNC(); 152132332Smarcel 153132332Smarcel ta = malloc(sizeof(td_thragent_t)); 154132332Smarcel if (ta == NULL) 155132332Smarcel return (TD_MALLOC); 156132332Smarcel 157132332Smarcel ta->ph = ph; 158132332Smarcel ta->thread_activated = 0; 159132332Smarcel ta->map = NULL; 160132332Smarcel ta->map_len = 0; 161132332Smarcel 162132332Smarcel LOOKUP_SYM(ph, "_libkse_debug", &ta->libkse_debug_addr); 163132332Smarcel LOOKUP_SYM(ph, "_thread_list", &ta->thread_list_addr); 164132332Smarcel LOOKUP_SYM(ph, "_thread_activated", &ta->thread_activated_addr); 165132332Smarcel LOOKUP_SYM(ph, "_thread_active_threads",&ta->thread_active_threads_addr); 166132332Smarcel LOOKUP_SYM(ph, "_thread_keytable", &ta->thread_keytable_addr); 167133802Sdavidxu LOOKUP_VAL(ph, "_thread_off_dtv", &ta->thread_off_dtv); 168133802Sdavidxu LOOKUP_VAL(ph, "_thread_off_kse_locklevel", &ta->thread_off_kse_locklevel); 169133802Sdavidxu LOOKUP_VAL(ph, "_thread_off_kse", &ta->thread_off_kse); 170133802Sdavidxu LOOKUP_VAL(ph, "_thread_off_tlsindex", &ta->thread_off_tlsindex); 171133802Sdavidxu LOOKUP_VAL(ph, "_thread_off_attr_flags", &ta->thread_off_attr_flags); 172133802Sdavidxu LOOKUP_VAL(ph, "_thread_size_key", &ta->thread_size_key); 173133802Sdavidxu LOOKUP_VAL(ph, "_thread_off_tcb", &ta->thread_off_tcb); 174133802Sdavidxu LOOKUP_VAL(ph, "_thread_off_linkmap", &ta->thread_off_linkmap); 175133802Sdavidxu LOOKUP_VAL(ph, "_thread_off_tmbx", &ta->thread_off_tmbx); 176133802Sdavidxu LOOKUP_VAL(ph, "_thread_off_thr_locklevel", &ta->thread_off_thr_locklevel); 177133802Sdavidxu LOOKUP_VAL(ph, "_thread_off_next", &ta->thread_off_next); 178133802Sdavidxu LOOKUP_VAL(ph, "_thread_off_state", &ta->thread_off_state); 179133802Sdavidxu LOOKUP_VAL(ph, "_thread_max_keys", &ta->thread_max_keys); 180133802Sdavidxu LOOKUP_VAL(ph, "_thread_off_key_allocated", &ta->thread_off_key_allocated); 181133802Sdavidxu LOOKUP_VAL(ph, "_thread_off_key_destructor", &ta->thread_off_key_destructor); 182133802Sdavidxu LOOKUP_VAL(ph, "_thread_state_running", &ta->thread_state_running); 183133802Sdavidxu LOOKUP_VAL(ph, "_thread_state_zoombie", &ta->thread_state_zoombie); 184158680Sdavidxu LOOKUP_VAL(ph, "_thread_off_sigmask", &ta->thread_off_sigmask); 185158680Sdavidxu LOOKUP_VAL(ph, "_thread_off_sigpend", &ta->thread_off_sigpend); 186132332Smarcel dbg = getpid(); 187132332Smarcel /* 188132332Smarcel * If this fails it probably means we're debugging a core file and 189132332Smarcel * can't write to it. 190132332Smarcel */ 191132332Smarcel ps_pwrite(ph, ta->libkse_debug_addr, &dbg, sizeof(int)); 192132332Smarcel *pta = ta; 193132332Smarcel return (0); 194132332Smarcel 195132332Smarcelerror: 196132332Smarcel free(ta); 197132332Smarcel return (ret); 198132332Smarcel} 199132332Smarcel 200132332Smarcelstatic td_err_e 201132332Smarcelpt_ta_delete(td_thragent_t *ta) 202132332Smarcel{ 203132332Smarcel int dbg; 204132332Smarcel 205132332Smarcel TDBG_FUNC(); 206132332Smarcel 207132332Smarcel dbg = 0; 208132332Smarcel /* 209132332Smarcel * Error returns from this write are not really a problem; 210132332Smarcel * the process doesn't exist any more. 211132332Smarcel */ 212132332Smarcel ps_pwrite(ta->ph, ta->libkse_debug_addr, &dbg, sizeof(int)); 213132332Smarcel if (ta->map) 214132332Smarcel free(ta->map); 215132332Smarcel free(ta); 216132332Smarcel return (TD_OK); 217132332Smarcel} 218132332Smarcel 219132332Smarcelstatic td_err_e 220132332Smarcelpt_ta_map_id2thr(const td_thragent_t *ta, thread_t id, td_thrhandle_t *th) 221132332Smarcel{ 222132332Smarcel prgregset_t gregs; 223132332Smarcel TAILQ_HEAD(, pthread) thread_list; 224132332Smarcel psaddr_t pt, tcb_addr; 225132332Smarcel lwpid_t lwp; 226132332Smarcel int ret; 227132332Smarcel 228132332Smarcel TDBG_FUNC(); 229132332Smarcel 230132332Smarcel if (id < 0 || id >= ta->map_len || ta->map[id].type == PT_NONE) 231132332Smarcel return (TD_NOTHR); 232132332Smarcel ret = ps_pread(ta->ph, ta->thread_list_addr, &thread_list, 233132332Smarcel sizeof(thread_list)); 234132332Smarcel if (ret != 0) 235132332Smarcel return (P2T(ret)); 236132332Smarcel pt = (psaddr_t)thread_list.tqh_first; 237132332Smarcel if (ta->map[id].type == PT_LWP) { 238132332Smarcel /* 239132332Smarcel * if we are referencing a lwp, make sure it was not already 240132332Smarcel * mapped to user thread. 241132332Smarcel */ 242132332Smarcel while (pt != 0) { 243180982Smarcel ret = ps_pread(ta->ph, pt + ta->thread_off_tcb, 244132332Smarcel &tcb_addr, sizeof(tcb_addr)); 245132332Smarcel if (ret != 0) 246132332Smarcel return (P2T(ret)); 247132332Smarcel ret = ps_pread(ta->ph, 248133802Sdavidxu tcb_addr + ta->thread_off_tmbx + 249133802Sdavidxu offsetof(struct kse_thr_mailbox, tm_lwp), 250132332Smarcel &lwp, sizeof(lwp)); 251132332Smarcel if (ret != 0) 252132332Smarcel return (P2T(ret)); 253132332Smarcel /* 254132332Smarcel * If the lwp was already mapped to userland thread, 255132332Smarcel * we shouldn't reference it directly in future. 256132332Smarcel */ 257132332Smarcel if (lwp == ta->map[id].lwp) { 258132332Smarcel ta->map[id].type = PT_NONE; 259132332Smarcel return (TD_NOTHR); 260132332Smarcel } 261132332Smarcel /* get next thread */ 262132332Smarcel ret = ps_pread(ta->ph, 263133802Sdavidxu pt + ta->thread_off_next, 264132332Smarcel &pt, sizeof(pt)); 265132332Smarcel if (ret != 0) 266132332Smarcel return (P2T(ret)); 267132332Smarcel } 268132332Smarcel /* check lwp */ 269155411Sdavidxu ret = ps_lgetregs(ta->ph, ta->map[id].lwp, gregs); 270155411Sdavidxu if (ret != PS_OK) { 271132332Smarcel /* no longer exists */ 272132332Smarcel ta->map[id].type = PT_NONE; 273132332Smarcel return (TD_NOTHR); 274132332Smarcel } 275132332Smarcel } else { 276132332Smarcel while (pt != 0 && ta->map[id].thr != pt) { 277132332Smarcel ret = ps_pread(ta->ph, 278133802Sdavidxu pt + ta->thread_off_tcb, 279132332Smarcel &tcb_addr, sizeof(tcb_addr)); 280132332Smarcel if (ret != 0) 281132332Smarcel return (P2T(ret)); 282132332Smarcel /* get next thread */ 283132332Smarcel ret = ps_pread(ta->ph, 284133802Sdavidxu pt + ta->thread_off_next, 285132332Smarcel &pt, sizeof(pt)); 286132332Smarcel if (ret != 0) 287132332Smarcel return (P2T(ret)); 288132332Smarcel } 289132332Smarcel 290132332Smarcel if (pt == 0) { 291132332Smarcel /* no longer exists */ 292132332Smarcel ta->map[id].type = PT_NONE; 293132332Smarcel return (TD_NOTHR); 294132332Smarcel } 295132332Smarcel } 296132332Smarcel th->th_ta = ta; 297132332Smarcel th->th_tid = id; 298144663Sdavidxu th->th_thread = pt; 299132332Smarcel return (TD_OK); 300132332Smarcel} 301132332Smarcel 302132332Smarcelstatic td_err_e 303132332Smarcelpt_ta_map_lwp2thr(const td_thragent_t *ta, lwpid_t lwp, td_thrhandle_t *th) 304132332Smarcel{ 305132332Smarcel TAILQ_HEAD(, pthread) thread_list; 306132332Smarcel psaddr_t pt, ptr; 307132332Smarcel lwpid_t tmp_lwp; 308132332Smarcel int ret; 309132332Smarcel 310132332Smarcel TDBG_FUNC(); 311132332Smarcel 312132332Smarcel ret = ps_pread(ta->ph, ta->thread_list_addr, &thread_list, 313132332Smarcel sizeof(thread_list)); 314132332Smarcel if (ret != 0) 315132332Smarcel return (P2T(ret)); 316132332Smarcel pt = (psaddr_t)thread_list.tqh_first; 317132332Smarcel while (pt != 0) { 318133802Sdavidxu ret = ps_pread(ta->ph, pt + ta->thread_off_tcb, 319132332Smarcel &ptr, sizeof(ptr)); 320132332Smarcel if (ret != 0) 321132332Smarcel return (P2T(ret)); 322133802Sdavidxu ptr += ta->thread_off_tmbx + 323133802Sdavidxu offsetof(struct kse_thr_mailbox, tm_lwp); 324132332Smarcel ret = ps_pread(ta->ph, ptr, &tmp_lwp, sizeof(lwpid_t)); 325132332Smarcel if (ret != 0) 326132332Smarcel return (P2T(ret)); 327132332Smarcel if (tmp_lwp == lwp) { 328132332Smarcel th->th_ta = ta; 329132332Smarcel th->th_tid = pt_map_thread(ta, pt, PT_USER); 330132332Smarcel if (th->th_tid == -1) 331132332Smarcel return (TD_MALLOC); 332132332Smarcel pt_unmap_lwp(ta, lwp); 333144663Sdavidxu th->th_thread = pt; 334132332Smarcel return (TD_OK); 335132332Smarcel } 336132332Smarcel 337132332Smarcel /* get next thread */ 338132332Smarcel ret = ps_pread(ta->ph, 339133802Sdavidxu pt + ta->thread_off_next, 340132332Smarcel &pt, sizeof(pt)); 341132332Smarcel if (ret != 0) 342132332Smarcel return (P2T(ret)); 343132332Smarcel } 344132332Smarcel 345132332Smarcel return (TD_NOTHR); 346132332Smarcel} 347132332Smarcel 348132332Smarcelstatic td_err_e 349132332Smarcelpt_ta_thr_iter(const td_thragent_t *ta, 350132332Smarcel td_thr_iter_f *callback, void *cbdata_p, 351132332Smarcel td_thr_state_e state, int ti_pri, 352132332Smarcel sigset_t *ti_sigmask_p, 353132332Smarcel unsigned int ti_user_flags) 354132332Smarcel{ 355132332Smarcel TAILQ_HEAD(, pthread) thread_list; 356132332Smarcel td_thrhandle_t th; 357132332Smarcel psaddr_t pt; 358132332Smarcel ps_err_e pserr; 359132332Smarcel int activated; 360132332Smarcel 361132332Smarcel TDBG_FUNC(); 362132332Smarcel 363132332Smarcel pserr = ps_pread(ta->ph, ta->thread_activated_addr, &activated, 364132332Smarcel sizeof(int)); 365132332Smarcel if (pserr != PS_OK) 366132332Smarcel return (P2T(pserr)); 367132332Smarcel if (!activated) 368132332Smarcel return (TD_OK); 369132332Smarcel 370132332Smarcel pserr = ps_pread(ta->ph, ta->thread_list_addr, &thread_list, 371132332Smarcel sizeof(thread_list)); 372132332Smarcel if (pserr != 0) 373132332Smarcel return (P2T(pserr)); 374132332Smarcel pt = (psaddr_t)thread_list.tqh_first; 375132332Smarcel while (pt != 0) { 376132332Smarcel th.th_ta = ta; 377132332Smarcel th.th_tid = pt_map_thread(ta, pt, PT_USER); 378144663Sdavidxu th.th_thread = pt; 379132332Smarcel /* should we unmap lwp here ? */ 380132332Smarcel if (th.th_tid == -1) 381132332Smarcel return (TD_MALLOC); 382132332Smarcel if ((*callback)(&th, cbdata_p)) 383132332Smarcel return (TD_DBERR); 384132332Smarcel /* get next thread */ 385132332Smarcel pserr = ps_pread(ta->ph, 386133802Sdavidxu pt + ta->thread_off_next, &pt, 387132332Smarcel sizeof(pt)); 388132332Smarcel if (pserr != PS_OK) 389132332Smarcel return (P2T(pserr)); 390132332Smarcel } 391132332Smarcel return (TD_OK); 392132332Smarcel} 393132332Smarcel 394132332Smarcelstatic td_err_e 395132332Smarcelpt_ta_tsd_iter(const td_thragent_t *ta, td_key_iter_f *ki, void *arg) 396132332Smarcel{ 397133802Sdavidxu char *keytable; 398133802Sdavidxu void *destructor; 399133802Sdavidxu int i, ret, allocated; 400132332Smarcel 401132332Smarcel TDBG_FUNC(); 402132332Smarcel 403133802Sdavidxu keytable = malloc(ta->thread_max_keys * ta->thread_size_key); 404133802Sdavidxu if (keytable == NULL) 405133802Sdavidxu return (TD_MALLOC); 406132332Smarcel ret = ps_pread(ta->ph, (psaddr_t)ta->thread_keytable_addr, keytable, 407133802Sdavidxu ta->thread_max_keys * ta->thread_size_key); 408133805Sdavidxu if (ret != 0) { 409133805Sdavidxu free(keytable); 410132332Smarcel return (P2T(ret)); 411133805Sdavidxu } 412133802Sdavidxu for (i = 0; i < ta->thread_max_keys; i++) { 413133802Sdavidxu allocated = *(int *)(keytable + i * ta->thread_size_key + 414133802Sdavidxu ta->thread_off_key_allocated); 415133802Sdavidxu destructor = *(void **)(keytable + i * ta->thread_size_key + 416133802Sdavidxu ta->thread_off_key_destructor); 417133802Sdavidxu if (allocated) { 418133802Sdavidxu ret = (ki)(i, destructor, arg); 419133802Sdavidxu if (ret != 0) { 420133802Sdavidxu free(keytable); 421132332Smarcel return (TD_DBERR); 422133802Sdavidxu } 423132332Smarcel } 424132332Smarcel } 425133802Sdavidxu free(keytable); 426132332Smarcel return (TD_OK); 427132332Smarcel} 428132332Smarcel 429132332Smarcelstatic td_err_e 430132332Smarcelpt_ta_event_addr(const td_thragent_t *ta, td_event_e event, td_notify_t *ptr) 431132332Smarcel{ 432132332Smarcel TDBG_FUNC(); 433144922Sdavidxu return (TD_ERR); 434132332Smarcel} 435132332Smarcel 436132332Smarcelstatic td_err_e 437132332Smarcelpt_ta_set_event(const td_thragent_t *ta, td_thr_events_t *events) 438132332Smarcel{ 439132332Smarcel TDBG_FUNC(); 440144922Sdavidxu return (0); 441132332Smarcel} 442132332Smarcel 443132332Smarcelstatic td_err_e 444132332Smarcelpt_ta_clear_event(const td_thragent_t *ta, td_thr_events_t *events) 445132332Smarcel{ 446132332Smarcel TDBG_FUNC(); 447144922Sdavidxu return (0); 448132332Smarcel} 449132332Smarcel 450132332Smarcelstatic td_err_e 451132332Smarcelpt_ta_event_getmsg(const td_thragent_t *ta, td_event_msg_t *msg) 452132332Smarcel{ 453132332Smarcel TDBG_FUNC(); 454132332Smarcel return (TD_NOMSG); 455132332Smarcel} 456132332Smarcel 457132332Smarcelstatic td_err_e 458132951Sdavidxupt_dbsuspend(const td_thrhandle_t *th, int suspend) 459132951Sdavidxu{ 460132951Sdavidxu td_thragent_t *ta = (td_thragent_t *)th->th_ta; 461132951Sdavidxu psaddr_t tcb_addr, tmbx_addr, ptr; 462132951Sdavidxu lwpid_t lwp; 463132951Sdavidxu uint32_t dflags; 464133342Sdavidxu int attrflags, locklevel, ret; 465132951Sdavidxu 466132951Sdavidxu TDBG_FUNC(); 467132951Sdavidxu 468132951Sdavidxu ret = pt_validate(th); 469132951Sdavidxu if (ret) 470132951Sdavidxu return (ret); 471132951Sdavidxu 472132951Sdavidxu if (ta->map[th->th_tid].type == PT_LWP) { 473132951Sdavidxu if (suspend) 474132951Sdavidxu ret = ps_lstop(ta->ph, ta->map[th->th_tid].lwp); 475132951Sdavidxu else 476132951Sdavidxu ret = ps_lcontinue(ta->ph, ta->map[th->th_tid].lwp); 477132951Sdavidxu return (P2T(ret)); 478132951Sdavidxu } 479132951Sdavidxu 480132951Sdavidxu ret = ps_pread(ta->ph, ta->map[th->th_tid].thr + 481133802Sdavidxu ta->thread_off_attr_flags, 482132951Sdavidxu &attrflags, sizeof(attrflags)); 483132951Sdavidxu if (ret != 0) 484132951Sdavidxu return (P2T(ret)); 485132951Sdavidxu ret = ps_pread(ta->ph, ta->map[th->th_tid].thr + 486133802Sdavidxu ta->thread_off_tcb, 487133802Sdavidxu &tcb_addr, sizeof(tcb_addr)); 488132951Sdavidxu if (ret != 0) 489132951Sdavidxu return (P2T(ret)); 490133802Sdavidxu tmbx_addr = tcb_addr + ta->thread_off_tmbx; 491132951Sdavidxu ptr = tmbx_addr + offsetof(struct kse_thr_mailbox, tm_lwp); 492132951Sdavidxu ret = ps_pread(ta->ph, ptr, &lwp, sizeof(lwpid_t)); 493132951Sdavidxu if (ret != 0) 494132951Sdavidxu return (P2T(ret)); 495133342Sdavidxu 496133342Sdavidxu if (lwp != 0) { 497133342Sdavidxu /* don't suspend signal thread */ 498133802Sdavidxu if (attrflags & 0x200) 499133342Sdavidxu return (0); 500133342Sdavidxu if (attrflags & PTHREAD_SCOPE_SYSTEM) { 501133342Sdavidxu /* 502133342Sdavidxu * don't suspend system scope thread if it is holding 503133342Sdavidxu * some low level locks 504133342Sdavidxu */ 505133802Sdavidxu ptr = ta->map[th->th_tid].thr + ta->thread_off_kse; 506133342Sdavidxu ret = ps_pread(ta->ph, ptr, &ptr, sizeof(ptr)); 507133342Sdavidxu if (ret != 0) 508133342Sdavidxu return (P2T(ret)); 509133802Sdavidxu ret = ps_pread(ta->ph, ptr + ta->thread_off_kse_locklevel, 510133802Sdavidxu &locklevel, sizeof(int)); 511133342Sdavidxu if (ret != 0) 512133342Sdavidxu return (P2T(ret)); 513133342Sdavidxu if (locklevel <= 0) { 514133342Sdavidxu ptr = ta->map[th->th_tid].thr + 515133802Sdavidxu ta->thread_off_thr_locklevel; 516133342Sdavidxu ret = ps_pread(ta->ph, ptr, &locklevel, 517133342Sdavidxu sizeof(int)); 518133342Sdavidxu if (ret != 0) 519133342Sdavidxu return (P2T(ret)); 520133342Sdavidxu } 521133342Sdavidxu if (suspend) { 522133342Sdavidxu if (locklevel <= 0) 523133342Sdavidxu ret = ps_lstop(ta->ph, lwp); 524133342Sdavidxu } else { 525132951Sdavidxu ret = ps_lcontinue(ta->ph, lwp); 526133342Sdavidxu } 527132951Sdavidxu if (ret != 0) 528132951Sdavidxu return (P2T(ret)); 529133342Sdavidxu /* FALLTHROUGH */ 530133342Sdavidxu } else { 531133342Sdavidxu struct ptrace_lwpinfo pl; 532133342Sdavidxu 533155413Sdavidxu if (ps_linfo(ta->ph, lwp, (caddr_t)&pl)) 534133342Sdavidxu return (TD_ERR); 535133342Sdavidxu if (suspend) { 536133342Sdavidxu if (!(pl.pl_flags & PL_FLAG_BOUND)) 537133342Sdavidxu ret = ps_lstop(ta->ph, lwp); 538133342Sdavidxu } else { 539133342Sdavidxu ret = ps_lcontinue(ta->ph, lwp); 540133342Sdavidxu } 541133342Sdavidxu if (ret != 0) 542133342Sdavidxu return (P2T(ret)); 543133342Sdavidxu /* FALLTHROUGH */ 544132951Sdavidxu } 545132951Sdavidxu } 546132951Sdavidxu /* read tm_dflags */ 547132951Sdavidxu ret = ps_pread(ta->ph, 548132951Sdavidxu tmbx_addr + offsetof(struct kse_thr_mailbox, tm_dflags), 549132951Sdavidxu &dflags, sizeof(dflags)); 550132951Sdavidxu if (ret != 0) 551132951Sdavidxu return (P2T(ret)); 552132951Sdavidxu if (suspend) 553133047Sdavidxu dflags |= TMDF_SUSPEND; 554132951Sdavidxu else 555133047Sdavidxu dflags &= ~TMDF_SUSPEND; 556132951Sdavidxu ret = ps_pwrite(ta->ph, 557132951Sdavidxu tmbx_addr + offsetof(struct kse_thr_mailbox, tm_dflags), 558132951Sdavidxu &dflags, sizeof(dflags)); 559132951Sdavidxu return (P2T(ret)); 560132951Sdavidxu} 561132951Sdavidxu 562132951Sdavidxustatic td_err_e 563132332Smarcelpt_thr_dbresume(const td_thrhandle_t *th) 564132332Smarcel{ 565132332Smarcel TDBG_FUNC(); 566132951Sdavidxu 567132951Sdavidxu return pt_dbsuspend(th, 0); 568132332Smarcel} 569132332Smarcel 570132332Smarcelstatic td_err_e 571132332Smarcelpt_thr_dbsuspend(const td_thrhandle_t *th) 572132332Smarcel{ 573132332Smarcel TDBG_FUNC(); 574132951Sdavidxu 575132951Sdavidxu return pt_dbsuspend(th, 1); 576132332Smarcel} 577132332Smarcel 578132332Smarcelstatic td_err_e 579132332Smarcelpt_thr_validate(const td_thrhandle_t *th) 580132332Smarcel{ 581132332Smarcel td_thrhandle_t temp; 582132332Smarcel int ret; 583132332Smarcel 584132332Smarcel TDBG_FUNC(); 585132332Smarcel 586132332Smarcel ret = pt_ta_map_id2thr(th->th_ta, th->th_tid, 587132332Smarcel &temp); 588132951Sdavidxu return (ret); 589132332Smarcel} 590132332Smarcel 591132332Smarcelstatic td_err_e 592132332Smarcelpt_thr_get_info(const td_thrhandle_t *th, td_thrinfo_t *info) 593132332Smarcel{ 594132332Smarcel const td_thragent_t *ta = th->th_ta; 595158680Sdavidxu struct ptrace_lwpinfo linfo; 596133802Sdavidxu psaddr_t tcb_addr; 597133802Sdavidxu uint32_t dflags; 598158680Sdavidxu lwpid_t lwp; 599133802Sdavidxu int state; 600132332Smarcel int ret; 601158680Sdavidxu int attrflags; 602132332Smarcel 603132332Smarcel TDBG_FUNC(); 604132332Smarcel 605155387Sdavidxu bzero(info, sizeof(*info)); 606132332Smarcel ret = pt_validate(th); 607132332Smarcel if (ret) 608132332Smarcel return (ret); 609132332Smarcel 610132332Smarcel memset(info, 0, sizeof(*info)); 611132332Smarcel if (ta->map[th->th_tid].type == PT_LWP) { 612132332Smarcel info->ti_type = TD_THR_SYSTEM; 613132332Smarcel info->ti_lid = ta->map[th->th_tid].lwp; 614132332Smarcel info->ti_tid = th->th_tid; 615132332Smarcel info->ti_state = TD_THR_RUN; 616132332Smarcel info->ti_type = TD_THR_SYSTEM; 617132332Smarcel return (TD_OK); 618132332Smarcel } 619158680Sdavidxu 620158680Sdavidxu ret = ps_pread(ta->ph, ta->map[th->th_tid].thr + 621158680Sdavidxu ta->thread_off_attr_flags, 622158680Sdavidxu &attrflags, sizeof(attrflags)); 623158680Sdavidxu if (ret != 0) 624158680Sdavidxu return (P2T(ret)); 625133802Sdavidxu ret = ps_pread(ta->ph, ta->map[th->th_tid].thr + ta->thread_off_tcb, 626133802Sdavidxu &tcb_addr, sizeof(tcb_addr)); 627132332Smarcel if (ret != 0) 628132332Smarcel return (P2T(ret)); 629133802Sdavidxu ret = ps_pread(ta->ph, ta->map[th->th_tid].thr + ta->thread_off_state, 630133802Sdavidxu &state, sizeof(state)); 631132332Smarcel ret = ps_pread(ta->ph, 632133802Sdavidxu tcb_addr + ta->thread_off_tmbx + 633133802Sdavidxu offsetof(struct kse_thr_mailbox, tm_lwp), 634132332Smarcel &info->ti_lid, sizeof(lwpid_t)); 635132332Smarcel if (ret != 0) 636132332Smarcel return (P2T(ret)); 637132951Sdavidxu ret = ps_pread(ta->ph, 638133802Sdavidxu tcb_addr + ta->thread_off_tmbx + 639133802Sdavidxu offsetof(struct kse_thr_mailbox, tm_dflags), 640132951Sdavidxu &dflags, sizeof(dflags)); 641132951Sdavidxu if (ret != 0) 642132951Sdavidxu return (P2T(ret)); 643158680Sdavidxu ret = ps_pread(ta->ph, tcb_addr + ta->thread_off_tmbx + 644158680Sdavidxu offsetof(struct kse_thr_mailbox, tm_lwp), &lwp, sizeof(lwpid_t)); 645158680Sdavidxu if (ret != 0) 646158680Sdavidxu return (P2T(ret)); 647132332Smarcel info->ti_ta_p = th->th_ta; 648132332Smarcel info->ti_tid = th->th_tid; 649158680Sdavidxu 650158680Sdavidxu if (attrflags & PTHREAD_SCOPE_SYSTEM) { 651158680Sdavidxu ret = ps_linfo(ta->ph, lwp, &linfo); 652158680Sdavidxu if (ret == PS_OK) { 653158680Sdavidxu info->ti_sigmask = linfo.pl_sigmask; 654158680Sdavidxu info->ti_pending = linfo.pl_siglist; 655158680Sdavidxu } else 656158680Sdavidxu return (ret); 657158680Sdavidxu } else { 658158680Sdavidxu ret = ps_pread(ta->ph, 659158680Sdavidxu ta->map[th->th_tid].thr + ta->thread_off_sigmask, 660158680Sdavidxu &info->ti_sigmask, sizeof(sigset_t)); 661158680Sdavidxu if (ret) 662158680Sdavidxu return (ret); 663158680Sdavidxu ret = ps_pread(ta->ph, 664158680Sdavidxu ta->map[th->th_tid].thr + ta->thread_off_sigpend, 665158680Sdavidxu &info->ti_pending, sizeof(sigset_t)); 666158680Sdavidxu if (ret) 667158680Sdavidxu return (ret); 668158680Sdavidxu } 669158680Sdavidxu 670133802Sdavidxu if (state == ta->thread_state_running) 671132332Smarcel info->ti_state = TD_THR_RUN; 672133802Sdavidxu else if (state == ta->thread_state_zoombie) 673133802Sdavidxu info->ti_state = TD_THR_ZOMBIE; 674133802Sdavidxu else 675132332Smarcel info->ti_state = TD_THR_SLEEP; 676133047Sdavidxu info->ti_db_suspended = ((dflags & TMDF_SUSPEND) != 0); 677132332Smarcel info->ti_type = TD_THR_USER; 678132332Smarcel return (0); 679132332Smarcel} 680132332Smarcel 681146818Sdfr#ifdef __i386__ 682132332Smarcelstatic td_err_e 683146818Sdfrpt_thr_getxmmregs(const td_thrhandle_t *th, char *fxsave) 684146818Sdfr{ 685146818Sdfr const td_thragent_t *ta = th->th_ta; 686146818Sdfr struct kse_thr_mailbox tmbx; 687146818Sdfr psaddr_t tcb_addr, tmbx_addr, ptr; 688146818Sdfr lwpid_t lwp; 689146818Sdfr int ret; 690146818Sdfr 691146818Sdfr return TD_ERR; 692146818Sdfr 693146818Sdfr TDBG_FUNC(); 694146818Sdfr 695146818Sdfr ret = pt_validate(th); 696146818Sdfr if (ret) 697146818Sdfr return (ret); 698146818Sdfr 699146818Sdfr if (ta->map[th->th_tid].type == PT_LWP) { 700146818Sdfr ret = ps_lgetxmmregs(ta->ph, ta->map[th->th_tid].lwp, fxsave); 701146818Sdfr return (P2T(ret)); 702146818Sdfr } 703146818Sdfr 704146818Sdfr ret = ps_pread(ta->ph, ta->map[th->th_tid].thr + ta->thread_off_tcb, 705146818Sdfr &tcb_addr, sizeof(tcb_addr)); 706146818Sdfr if (ret != 0) 707146818Sdfr return (P2T(ret)); 708146818Sdfr tmbx_addr = tcb_addr + ta->thread_off_tmbx; 709146818Sdfr ptr = tmbx_addr + offsetof(struct kse_thr_mailbox, tm_lwp); 710146818Sdfr ret = ps_pread(ta->ph, ptr, &lwp, sizeof(lwpid_t)); 711146818Sdfr if (ret != 0) 712146818Sdfr return (P2T(ret)); 713146818Sdfr if (lwp != 0) { 714146818Sdfr ret = ps_lgetxmmregs(ta->ph, lwp, fxsave); 715146818Sdfr return (P2T(ret)); 716146818Sdfr } 717146818Sdfr 718146818Sdfr ret = ps_pread(ta->ph, tmbx_addr, &tmbx, sizeof(tmbx)); 719146818Sdfr if (ret != 0) 720146818Sdfr return (P2T(ret)); 721146818Sdfr pt_ucontext_to_fxsave(&tmbx.tm_context, fxsave); 722146818Sdfr return (0); 723146818Sdfr} 724146818Sdfr#endif 725146818Sdfr 726146818Sdfrstatic td_err_e 727132332Smarcelpt_thr_getfpregs(const td_thrhandle_t *th, 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_lgetfpregs(ta->ph, ta->map[th->th_tid].lwp, fpregs); 743132332Smarcel return (P2T(ret)); 744132332Smarcel } 745132332Smarcel 746133802Sdavidxu ret = ps_pread(ta->ph, ta->map[th->th_tid].thr + ta->thread_off_tcb, 747132951Sdavidxu &tcb_addr, sizeof(tcb_addr)); 748132332Smarcel if (ret != 0) 749132332Smarcel return (P2T(ret)); 750133802Sdavidxu tmbx_addr = tcb_addr + ta->thread_off_tmbx; 751132332Smarcel ptr = tmbx_addr + offsetof(struct kse_thr_mailbox, tm_lwp); 752132332Smarcel ret = ps_pread(ta->ph, ptr, &lwp, sizeof(lwpid_t)); 753132332Smarcel if (ret != 0) 754132332Smarcel return (P2T(ret)); 755132332Smarcel if (lwp != 0) { 756132332Smarcel ret = ps_lgetfpregs(ta->ph, lwp, fpregs); 757132332Smarcel return (P2T(ret)); 758132332Smarcel } 759132332Smarcel 760132332Smarcel ret = ps_pread(ta->ph, tmbx_addr, &tmbx, sizeof(tmbx)); 761132332Smarcel if (ret != 0) 762132332Smarcel return (P2T(ret)); 763132332Smarcel pt_ucontext_to_fpreg(&tmbx.tm_context, fpregs); 764132332Smarcel return (0); 765132332Smarcel} 766132332Smarcel 767132332Smarcelstatic td_err_e 768132332Smarcelpt_thr_getgregs(const td_thrhandle_t *th, prgregset_t gregs) 769132332Smarcel{ 770132332Smarcel const td_thragent_t *ta = th->th_ta; 771132332Smarcel struct kse_thr_mailbox tmbx; 772132332Smarcel psaddr_t tcb_addr, tmbx_addr, ptr; 773132332Smarcel lwpid_t lwp; 774132332Smarcel int ret; 775132332Smarcel 776132332Smarcel TDBG_FUNC(); 777132332Smarcel 778132332Smarcel ret = pt_validate(th); 779132332Smarcel if (ret) 780132332Smarcel return (ret); 781132332Smarcel 782132332Smarcel if (ta->map[th->th_tid].type == PT_LWP) { 783132332Smarcel ret = ps_lgetregs(ta->ph, 784132332Smarcel ta->map[th->th_tid].lwp, gregs); 785132332Smarcel return (P2T(ret)); 786132332Smarcel } 787132332Smarcel 788133802Sdavidxu ret = ps_pread(ta->ph, ta->map[th->th_tid].thr + ta->thread_off_tcb, 789132332Smarcel &tcb_addr, sizeof(tcb_addr)); 790132332Smarcel if (ret != 0) 791132332Smarcel return (P2T(ret)); 792133802Sdavidxu tmbx_addr = tcb_addr + ta->thread_off_tmbx; 793132332Smarcel ptr = tmbx_addr + offsetof(struct kse_thr_mailbox, tm_lwp); 794132332Smarcel ret = ps_pread(ta->ph, ptr, &lwp, sizeof(lwpid_t)); 795132332Smarcel if (ret != 0) 796132332Smarcel return (P2T(ret)); 797132332Smarcel if (lwp != 0) { 798132332Smarcel ret = ps_lgetregs(ta->ph, lwp, gregs); 799132332Smarcel return (P2T(ret)); 800132332Smarcel } 801132332Smarcel ret = ps_pread(ta->ph, tmbx_addr, &tmbx, sizeof(tmbx)); 802132332Smarcel if (ret != 0) 803132332Smarcel return (P2T(ret)); 804132332Smarcel pt_ucontext_to_reg(&tmbx.tm_context, gregs); 805132332Smarcel return (0); 806132332Smarcel} 807132332Smarcel 808146818Sdfr#ifdef __i386__ 809132332Smarcelstatic td_err_e 810146818Sdfrpt_thr_setxmmregs(const td_thrhandle_t *th, const char *fxsave) 811146818Sdfr{ 812146818Sdfr const td_thragent_t *ta = th->th_ta; 813146818Sdfr struct kse_thr_mailbox tmbx; 814146818Sdfr psaddr_t tcb_addr, tmbx_addr, ptr; 815146818Sdfr lwpid_t lwp; 816146818Sdfr int ret; 817146818Sdfr 818146818Sdfr return TD_ERR; 819146818Sdfr 820146818Sdfr TDBG_FUNC(); 821146818Sdfr 822146818Sdfr ret = pt_validate(th); 823146818Sdfr if (ret) 824146818Sdfr return (ret); 825146818Sdfr 826146818Sdfr if (ta->map[th->th_tid].type == PT_LWP) { 827146818Sdfr ret = ps_lsetxmmregs(ta->ph, ta->map[th->th_tid].lwp, fxsave); 828146818Sdfr return (P2T(ret)); 829146818Sdfr } 830146818Sdfr 831146818Sdfr ret = ps_pread(ta->ph, ta->map[th->th_tid].thr + 832146818Sdfr ta->thread_off_tcb, 833146818Sdfr &tcb_addr, sizeof(tcb_addr)); 834146818Sdfr if (ret != 0) 835146818Sdfr return (P2T(ret)); 836146818Sdfr tmbx_addr = tcb_addr + ta->thread_off_tmbx; 837146818Sdfr ptr = tmbx_addr + offsetof(struct kse_thr_mailbox, tm_lwp); 838146818Sdfr ret = ps_pread(ta->ph, ptr, &lwp, sizeof(lwpid_t)); 839146818Sdfr if (ret != 0) 840146818Sdfr return (P2T(ret)); 841146818Sdfr if (lwp != 0) { 842146818Sdfr ret = ps_lsetxmmregs(ta->ph, lwp, fxsave); 843146818Sdfr return (P2T(ret)); 844146818Sdfr } 845146818Sdfr /* 846146818Sdfr * Read a copy of context, this makes sure that registers 847146818Sdfr * not covered by structure reg won't be clobbered 848146818Sdfr */ 849146818Sdfr ret = ps_pread(ta->ph, tmbx_addr, &tmbx, sizeof(tmbx)); 850146818Sdfr if (ret != 0) 851146818Sdfr return (P2T(ret)); 852146818Sdfr 853146818Sdfr pt_fxsave_to_ucontext(fxsave, &tmbx.tm_context); 854146818Sdfr ret = ps_pwrite(ta->ph, tmbx_addr, &tmbx, sizeof(tmbx)); 855146818Sdfr return (P2T(ret)); 856146818Sdfr} 857146818Sdfr#endif 858146818Sdfr 859146818Sdfrstatic td_err_e 860132332Smarcelpt_thr_setfpregs(const td_thrhandle_t *th, const prfpregset_t *fpregs) 861132332Smarcel{ 862132332Smarcel const td_thragent_t *ta = th->th_ta; 863132332Smarcel struct kse_thr_mailbox tmbx; 864132332Smarcel psaddr_t tcb_addr, tmbx_addr, ptr; 865132332Smarcel lwpid_t lwp; 866132332Smarcel int ret; 867132332Smarcel 868132332Smarcel TDBG_FUNC(); 869132332Smarcel 870132332Smarcel ret = pt_validate(th); 871132332Smarcel if (ret) 872132332Smarcel return (ret); 873132332Smarcel 874132332Smarcel if (ta->map[th->th_tid].type == PT_LWP) { 875132332Smarcel ret = ps_lsetfpregs(ta->ph, ta->map[th->th_tid].lwp, fpregs); 876132332Smarcel return (P2T(ret)); 877132332Smarcel } 878132332Smarcel 879132332Smarcel ret = ps_pread(ta->ph, ta->map[th->th_tid].thr + 880133802Sdavidxu ta->thread_off_tcb, 881132332Smarcel &tcb_addr, sizeof(tcb_addr)); 882132332Smarcel if (ret != 0) 883132332Smarcel return (P2T(ret)); 884133802Sdavidxu tmbx_addr = tcb_addr + ta->thread_off_tmbx; 885132332Smarcel ptr = tmbx_addr + offsetof(struct kse_thr_mailbox, tm_lwp); 886132332Smarcel ret = ps_pread(ta->ph, ptr, &lwp, sizeof(lwpid_t)); 887132332Smarcel if (ret != 0) 888132332Smarcel return (P2T(ret)); 889132332Smarcel if (lwp != 0) { 890132332Smarcel ret = ps_lsetfpregs(ta->ph, lwp, fpregs); 891132332Smarcel return (P2T(ret)); 892132332Smarcel } 893132332Smarcel /* 894132332Smarcel * Read a copy of context, this makes sure that registers 895132332Smarcel * not covered by structure reg won't be clobbered 896132332Smarcel */ 897132332Smarcel ret = ps_pread(ta->ph, tmbx_addr, &tmbx, sizeof(tmbx)); 898132332Smarcel if (ret != 0) 899132332Smarcel return (P2T(ret)); 900132332Smarcel 901132332Smarcel pt_fpreg_to_ucontext(fpregs, &tmbx.tm_context); 902132332Smarcel ret = ps_pwrite(ta->ph, tmbx_addr, &tmbx, sizeof(tmbx)); 903132332Smarcel return (P2T(ret)); 904132332Smarcel} 905132332Smarcel 906132332Smarcelstatic td_err_e 907132332Smarcelpt_thr_setgregs(const td_thrhandle_t *th, const prgregset_t gregs) 908132332Smarcel{ 909132332Smarcel const td_thragent_t *ta = th->th_ta; 910132332Smarcel struct kse_thr_mailbox tmbx; 911132332Smarcel psaddr_t tcb_addr, tmbx_addr, ptr; 912132332Smarcel lwpid_t lwp; 913132332Smarcel int ret; 914132332Smarcel 915132332Smarcel TDBG_FUNC(); 916132332Smarcel 917132332Smarcel ret = pt_validate(th); 918132332Smarcel if (ret) 919132332Smarcel return (ret); 920132332Smarcel 921132332Smarcel if (ta->map[th->th_tid].type == PT_LWP) { 922132332Smarcel ret = ps_lsetregs(ta->ph, ta->map[th->th_tid].lwp, gregs); 923132332Smarcel return (P2T(ret)); 924132332Smarcel } 925132332Smarcel 926132332Smarcel ret = ps_pread(ta->ph, ta->map[th->th_tid].thr + 927133802Sdavidxu ta->thread_off_tcb, 928132332Smarcel &tcb_addr, sizeof(tcb_addr)); 929132332Smarcel if (ret != 0) 930132332Smarcel return (P2T(ret)); 931133802Sdavidxu tmbx_addr = tcb_addr + ta->thread_off_tmbx; 932132332Smarcel ptr = tmbx_addr + offsetof(struct kse_thr_mailbox, tm_lwp); 933132332Smarcel ret = ps_pread(ta->ph, ptr, &lwp, sizeof(lwpid_t)); 934132332Smarcel if (ret != 0) 935132332Smarcel return (P2T(ret)); 936132332Smarcel if (lwp != 0) { 937132332Smarcel ret = ps_lsetregs(ta->ph, lwp, gregs); 938132332Smarcel return (P2T(ret)); 939132332Smarcel } 940132332Smarcel 941132332Smarcel /* 942132332Smarcel * Read a copy of context, make sure that registers 943132332Smarcel * not covered by structure reg won't be clobbered 944132332Smarcel */ 945132332Smarcel ret = ps_pread(ta->ph, tmbx_addr, &tmbx, sizeof(tmbx)); 946132332Smarcel if (ret != 0) 947132332Smarcel return (P2T(ret)); 948132332Smarcel pt_reg_to_ucontext(gregs, &tmbx.tm_context); 949132332Smarcel ret = ps_pwrite(ta->ph, tmbx_addr, &tmbx, sizeof(tmbx)); 950132332Smarcel return (P2T(ret)); 951132332Smarcel} 952132332Smarcel 953132332Smarcelstatic td_err_e 954132332Smarcelpt_thr_event_enable(const td_thrhandle_t *th, int en) 955132332Smarcel{ 956132332Smarcel TDBG_FUNC(); 957144922Sdavidxu return (0); 958132332Smarcel} 959132332Smarcel 960132332Smarcelstatic td_err_e 961132332Smarcelpt_thr_set_event(const td_thrhandle_t *th, td_thr_events_t *setp) 962132332Smarcel{ 963132332Smarcel TDBG_FUNC(); 964144922Sdavidxu return (0); 965132332Smarcel} 966132332Smarcel 967132332Smarcelstatic td_err_e 968132332Smarcelpt_thr_clear_event(const td_thrhandle_t *th, td_thr_events_t *setp) 969132332Smarcel{ 970132332Smarcel TDBG_FUNC(); 971144922Sdavidxu return (0); 972132332Smarcel} 973132332Smarcel 974132332Smarcelstatic td_err_e 975132332Smarcelpt_thr_event_getmsg(const td_thrhandle_t *th, td_event_msg_t *msg) 976132332Smarcel{ 977132332Smarcel TDBG_FUNC(); 978132332Smarcel return (TD_NOMSG); 979132332Smarcel} 980132332Smarcel 981132332Smarcelstatic td_err_e 982132332Smarcelpt_thr_sstep(const td_thrhandle_t *th, int step) 983132332Smarcel{ 984132332Smarcel const td_thragent_t *ta = th->th_ta; 985132332Smarcel struct kse_thr_mailbox tmbx; 986132332Smarcel struct reg regs; 987132332Smarcel psaddr_t tcb_addr, tmbx_addr; 988132951Sdavidxu uint32_t dflags; 989132332Smarcel lwpid_t lwp; 990132332Smarcel int ret; 991132332Smarcel 992132332Smarcel TDBG_FUNC(); 993132332Smarcel 994132332Smarcel ret = pt_validate(th); 995132332Smarcel if (ret) 996132332Smarcel return (ret); 997132332Smarcel 998132332Smarcel if (ta->map[th->th_tid].type == PT_LWP) 999132332Smarcel return (TD_BADTH); 1000132332Smarcel 1001132332Smarcel ret = ps_pread(ta->ph, ta->map[th->th_tid].thr + 1002133802Sdavidxu ta->thread_off_tcb, 1003132332Smarcel &tcb_addr, sizeof(tcb_addr)); 1004132332Smarcel if (ret != 0) 1005132332Smarcel return (P2T(ret)); 1006132332Smarcel 1007132332Smarcel /* Clear or set single step flag in thread mailbox */ 1008133802Sdavidxu ret = ps_pread(ta->ph, 1009133802Sdavidxu tcb_addr + ta->thread_off_tmbx + 1010133802Sdavidxu offsetof(struct kse_thr_mailbox, tm_dflags), 1011133802Sdavidxu &dflags, sizeof(uint32_t)); 1012132951Sdavidxu if (ret != 0) 1013132951Sdavidxu return (P2T(ret)); 1014132951Sdavidxu if (step != 0) 1015132951Sdavidxu dflags |= TMDF_SSTEP; 1016132951Sdavidxu else 1017132951Sdavidxu dflags &= ~TMDF_SSTEP; 1018133802Sdavidxu ret = ps_pwrite(ta->ph, 1019133802Sdavidxu tcb_addr + ta->thread_off_tmbx + 1020133802Sdavidxu offsetof(struct kse_thr_mailbox, tm_dflags), 1021133802Sdavidxu &dflags, sizeof(uint32_t)); 1022132332Smarcel if (ret != 0) 1023132332Smarcel return (P2T(ret)); 1024132332Smarcel /* Get lwp */ 1025133802Sdavidxu ret = ps_pread(ta->ph, 1026133802Sdavidxu tcb_addr + ta->thread_off_tmbx + 1027133802Sdavidxu offsetof(struct kse_thr_mailbox, tm_lwp), 1028133802Sdavidxu &lwp, sizeof(lwpid_t)); 1029132332Smarcel if (ret != 0) 1030132332Smarcel return (P2T(ret)); 1031132332Smarcel if (lwp != 0) 1032132951Sdavidxu return (0); 1033132332Smarcel 1034133802Sdavidxu tmbx_addr = tcb_addr + ta->thread_off_tmbx; 1035132332Smarcel /* 1036132332Smarcel * context is in userland, some architectures store 1037132332Smarcel * single step status in registers, we should change 1038132332Smarcel * these registers. 1039132332Smarcel */ 1040132332Smarcel ret = ps_pread(ta->ph, tmbx_addr, &tmbx, sizeof(tmbx)); 1041132332Smarcel if (ret == 0) { 1042132332Smarcel pt_ucontext_to_reg(&tmbx.tm_context, ®s); 1043132332Smarcel /* only write out if it is really changed. */ 1044132332Smarcel if (pt_reg_sstep(®s, step) != 0) { 1045132332Smarcel pt_reg_to_ucontext(®s, &tmbx.tm_context); 1046132332Smarcel ret = ps_pwrite(ta->ph, tmbx_addr, &tmbx, 1047132332Smarcel sizeof(tmbx)); 1048132332Smarcel } 1049132332Smarcel } 1050132332Smarcel return (P2T(ret)); 1051132332Smarcel} 1052132332Smarcel 1053132332Smarcelstatic void 1054132332Smarcelpt_unmap_lwp(const td_thragent_t *ta, lwpid_t lwp) 1055132332Smarcel{ 1056132332Smarcel int i; 1057132332Smarcel 1058132332Smarcel for (i = 0; i < ta->map_len; ++i) { 1059132332Smarcel if (ta->map[i].type == PT_LWP && ta->map[i].lwp == lwp) { 1060132332Smarcel ta->map[i].type = PT_NONE; 1061132332Smarcel return; 1062132332Smarcel } 1063132332Smarcel } 1064132332Smarcel} 1065132332Smarcel 1066132332Smarcelstatic int 1067132332Smarcelpt_validate(const td_thrhandle_t *th) 1068132332Smarcel{ 1069132332Smarcel 1070132332Smarcel if (th->th_tid < 0 || th->th_tid >= th->th_ta->map_len || 1071132332Smarcel th->th_ta->map[th->th_tid].type == PT_NONE) 1072132332Smarcel return (TD_NOTHR); 1073132332Smarcel return (TD_OK); 1074132332Smarcel} 1075132332Smarcel 1076181059Smarcelstatic td_err_e 1077180982Smarcelpt_thr_tls_get_addr(const td_thrhandle_t *th, psaddr_t _linkmap, size_t offset, 1078180982Smarcel psaddr_t *address) 1079133342Sdavidxu{ 1080133342Sdavidxu const td_thragent_t *ta = th->th_ta; 1081180982Smarcel psaddr_t dtv_addr, obj_entry, tcb_addr; 1082133342Sdavidxu int tls_index, ret; 1083133342Sdavidxu 1084133342Sdavidxu /* linkmap is a member of Obj_Entry */ 1085180982Smarcel obj_entry = _linkmap - ta->thread_off_linkmap; 1086133342Sdavidxu 1087133342Sdavidxu /* get tlsindex of the object file */ 1088133342Sdavidxu ret = ps_pread(ta->ph, 1089133802Sdavidxu obj_entry + ta->thread_off_tlsindex, 1090133342Sdavidxu &tls_index, sizeof(tls_index)); 1091133342Sdavidxu if (ret != 0) 1092133342Sdavidxu return (P2T(ret)); 1093133342Sdavidxu 1094133342Sdavidxu /* get thread tcb */ 1095133342Sdavidxu ret = ps_pread(ta->ph, ta->map[th->th_tid].thr + 1096133802Sdavidxu ta->thread_off_tcb, 1097133342Sdavidxu &tcb_addr, sizeof(tcb_addr)); 1098133342Sdavidxu if (ret != 0) 1099133342Sdavidxu return (P2T(ret)); 1100133342Sdavidxu 1101133342Sdavidxu /* get dtv array address */ 1102133802Sdavidxu ret = ps_pread(ta->ph, tcb_addr + ta->thread_off_dtv, 1103133342Sdavidxu &dtv_addr, sizeof(dtv_addr)); 1104133342Sdavidxu if (ret != 0) 1105133342Sdavidxu return (P2T(ret)); 1106133342Sdavidxu /* now get the object's tls block base address */ 1107180982Smarcel ret = ps_pread(ta->ph, dtv_addr + sizeof(void *) * (tls_index + 1), 1108180982Smarcel address, sizeof(*address)); 1109133342Sdavidxu if (ret != 0) 1110133342Sdavidxu return (P2T(ret)); 1111133342Sdavidxu 1112133342Sdavidxu *address += offset; 1113133342Sdavidxu return (TD_OK); 1114133342Sdavidxu} 1115133342Sdavidxu 1116132332Smarcelstruct ta_ops libpthread_db_ops = { 1117132332Smarcel .to_init = pt_init, 1118132332Smarcel .to_ta_clear_event = pt_ta_clear_event, 1119132332Smarcel .to_ta_delete = pt_ta_delete, 1120132332Smarcel .to_ta_event_addr = pt_ta_event_addr, 1121132332Smarcel .to_ta_event_getmsg = pt_ta_event_getmsg, 1122132332Smarcel .to_ta_map_id2thr = pt_ta_map_id2thr, 1123132332Smarcel .to_ta_map_lwp2thr = pt_ta_map_lwp2thr, 1124132332Smarcel .to_ta_new = pt_ta_new, 1125132332Smarcel .to_ta_set_event = pt_ta_set_event, 1126132332Smarcel .to_ta_thr_iter = pt_ta_thr_iter, 1127132332Smarcel .to_ta_tsd_iter = pt_ta_tsd_iter, 1128132332Smarcel .to_thr_clear_event = pt_thr_clear_event, 1129132332Smarcel .to_thr_dbresume = pt_thr_dbresume, 1130132332Smarcel .to_thr_dbsuspend = pt_thr_dbsuspend, 1131132332Smarcel .to_thr_event_enable = pt_thr_event_enable, 1132132332Smarcel .to_thr_event_getmsg = pt_thr_event_getmsg, 1133132332Smarcel .to_thr_get_info = pt_thr_get_info, 1134132332Smarcel .to_thr_getfpregs = pt_thr_getfpregs, 1135132332Smarcel .to_thr_getgregs = pt_thr_getgregs, 1136132332Smarcel .to_thr_set_event = pt_thr_set_event, 1137132332Smarcel .to_thr_setfpregs = pt_thr_setfpregs, 1138132332Smarcel .to_thr_setgregs = pt_thr_setgregs, 1139132332Smarcel .to_thr_validate = pt_thr_validate, 1140133342Sdavidxu .to_thr_tls_get_addr = pt_thr_tls_get_addr, 1141132332Smarcel 1142132332Smarcel /* FreeBSD specific extensions. */ 1143132332Smarcel .to_thr_sstep = pt_thr_sstep, 1144146818Sdfr#ifdef __i386__ 1145146818Sdfr .to_thr_getxmmregs = pt_thr_getxmmregs, 1146146818Sdfr .to_thr_setxmmregs = pt_thr_setxmmregs, 1147146818Sdfr#endif 1148132332Smarcel}; 1149177490Sdavidxu 1150177490SdavidxuDATA_SET(__ta_ops, libpthread_db_ops); 1151