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$"); 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 psaddr_t pt, tcb_addr; 224132332Smarcel lwpid_t lwp; 225132332Smarcel int ret; 226132332Smarcel 227132332Smarcel TDBG_FUNC(); 228132332Smarcel 229132332Smarcel if (id < 0 || id >= ta->map_len || ta->map[id].type == PT_NONE) 230132332Smarcel return (TD_NOTHR); 231183021Smarcel 232183021Smarcel ret = thr_pread_ptr(ta, ta->thread_list_addr, &pt); 233132332Smarcel if (ret != 0) 234183021Smarcel return (TD_ERR); 235132332Smarcel if (ta->map[id].type == PT_LWP) { 236132332Smarcel /* 237132332Smarcel * if we are referencing a lwp, make sure it was not already 238132332Smarcel * mapped to user thread. 239132332Smarcel */ 240132332Smarcel while (pt != 0) { 241183021Smarcel ret = thr_pread_ptr(ta, pt + ta->thread_off_tcb, 242183021Smarcel &tcb_addr); 243132332Smarcel if (ret != 0) 244183021Smarcel return (TD_ERR); 245183021Smarcel ret = thr_pread_int(ta, tcb_addr + ta->thread_off_tmbx + 246183021Smarcel offsetof(struct kse_thr_mailbox, tm_lwp), &lwp); 247132332Smarcel if (ret != 0) 248183021Smarcel return (TD_ERR); 249132332Smarcel /* 250132332Smarcel * If the lwp was already mapped to userland thread, 251132332Smarcel * we shouldn't reference it directly in future. 252132332Smarcel */ 253132332Smarcel if (lwp == ta->map[id].lwp) { 254132332Smarcel ta->map[id].type = PT_NONE; 255132332Smarcel return (TD_NOTHR); 256132332Smarcel } 257132332Smarcel /* get next thread */ 258183021Smarcel ret = thr_pread_ptr(ta, pt + ta->thread_off_next, &pt); 259132332Smarcel if (ret != 0) 260183021Smarcel return (TD_ERR); 261132332Smarcel } 262132332Smarcel /* check lwp */ 263155411Sdavidxu ret = ps_lgetregs(ta->ph, ta->map[id].lwp, gregs); 264155411Sdavidxu if (ret != PS_OK) { 265132332Smarcel /* no longer exists */ 266132332Smarcel ta->map[id].type = PT_NONE; 267132332Smarcel return (TD_NOTHR); 268132332Smarcel } 269132332Smarcel } else { 270132332Smarcel while (pt != 0 && ta->map[id].thr != pt) { 271183021Smarcel ret = thr_pread_ptr(ta, pt + ta->thread_off_tcb, 272183021Smarcel &tcb_addr); 273132332Smarcel if (ret != 0) 274183021Smarcel return (TD_ERR); 275132332Smarcel /* get next thread */ 276183021Smarcel ret = thr_pread_ptr(ta, pt + ta->thread_off_next, &pt); 277132332Smarcel if (ret != 0) 278183021Smarcel return (TD_ERR); 279132332Smarcel } 280132332Smarcel 281132332Smarcel if (pt == 0) { 282132332Smarcel /* no longer exists */ 283132332Smarcel ta->map[id].type = PT_NONE; 284132332Smarcel return (TD_NOTHR); 285132332Smarcel } 286132332Smarcel } 287132332Smarcel th->th_ta = ta; 288132332Smarcel th->th_tid = id; 289144663Sdavidxu th->th_thread = pt; 290132332Smarcel return (TD_OK); 291132332Smarcel} 292132332Smarcel 293132332Smarcelstatic td_err_e 294132332Smarcelpt_ta_map_lwp2thr(const td_thragent_t *ta, lwpid_t lwp, td_thrhandle_t *th) 295132332Smarcel{ 296183021Smarcel psaddr_t pt, tcb_addr; 297183021Smarcel lwpid_t lwp1; 298132332Smarcel int ret; 299183021Smarcel 300132332Smarcel TDBG_FUNC(); 301132332Smarcel 302183021Smarcel ret = thr_pread_ptr(ta, ta->thread_list_addr, &pt); 303132332Smarcel if (ret != 0) 304183021Smarcel return (TD_ERR); 305132332Smarcel while (pt != 0) { 306183021Smarcel ret = thr_pread_ptr(ta, pt + ta->thread_off_tcb, &tcb_addr); 307132332Smarcel if (ret != 0) 308183021Smarcel return (TD_ERR); 309183021Smarcel ret = thr_pread_int(ta, tcb_addr + ta->thread_off_tmbx + 310183021Smarcel offsetof(struct kse_thr_mailbox, tm_lwp), &lwp1); 311132332Smarcel if (ret != 0) 312183021Smarcel return (TD_ERR); 313183021Smarcel if (lwp1 == lwp) { 314132332Smarcel th->th_ta = ta; 315132332Smarcel th->th_tid = pt_map_thread(ta, pt, PT_USER); 316132332Smarcel if (th->th_tid == -1) 317132332Smarcel return (TD_MALLOC); 318132332Smarcel pt_unmap_lwp(ta, lwp); 319144663Sdavidxu th->th_thread = pt; 320132332Smarcel return (TD_OK); 321132332Smarcel } 322132332Smarcel 323132332Smarcel /* get next thread */ 324183021Smarcel ret = thr_pread_ptr(ta, pt + ta->thread_off_next, &pt); 325132332Smarcel if (ret != 0) 326183021Smarcel return (TD_ERR); 327132332Smarcel } 328132332Smarcel 329132332Smarcel return (TD_NOTHR); 330132332Smarcel} 331132332Smarcel 332132332Smarcelstatic td_err_e 333181341Smarcelpt_ta_thr_iter(const td_thragent_t *ta, td_thr_iter_f *callback, 334181341Smarcel void *cbdata_p, td_thr_state_e state __unused, int ti_pri __unused, 335181341Smarcel sigset_t *ti_sigmask_p __unused, unsigned int ti_user_flags __unused) 336132332Smarcel{ 337132332Smarcel td_thrhandle_t th; 338132332Smarcel psaddr_t pt; 339132332Smarcel ps_err_e pserr; 340183021Smarcel int activated, ret; 341132332Smarcel 342132332Smarcel TDBG_FUNC(); 343132332Smarcel 344132332Smarcel pserr = ps_pread(ta->ph, ta->thread_activated_addr, &activated, 345132332Smarcel sizeof(int)); 346132332Smarcel if (pserr != PS_OK) 347132332Smarcel return (P2T(pserr)); 348132332Smarcel if (!activated) 349132332Smarcel return (TD_OK); 350132332Smarcel 351183021Smarcel ret = thr_pread_ptr(ta, ta->thread_list_addr, &pt); 352183021Smarcel if (ret != 0) 353183021Smarcel return (TD_ERR); 354132332Smarcel while (pt != 0) { 355132332Smarcel th.th_ta = ta; 356132332Smarcel th.th_tid = pt_map_thread(ta, pt, PT_USER); 357144663Sdavidxu th.th_thread = pt; 358132332Smarcel /* should we unmap lwp here ? */ 359132332Smarcel if (th.th_tid == -1) 360132332Smarcel return (TD_MALLOC); 361132332Smarcel if ((*callback)(&th, cbdata_p)) 362132332Smarcel return (TD_DBERR); 363132332Smarcel /* get next thread */ 364183021Smarcel ret = thr_pread_ptr(ta, pt + ta->thread_off_next, &pt); 365183021Smarcel if (ret != 0) 366183021Smarcel return (TD_ERR); 367132332Smarcel } 368132332Smarcel return (TD_OK); 369132332Smarcel} 370132332Smarcel 371132332Smarcelstatic td_err_e 372132332Smarcelpt_ta_tsd_iter(const td_thragent_t *ta, td_key_iter_f *ki, void *arg) 373132332Smarcel{ 374181341Smarcel void *keytable; 375133802Sdavidxu void *destructor; 376133802Sdavidxu int i, ret, allocated; 377132332Smarcel 378132332Smarcel TDBG_FUNC(); 379132332Smarcel 380133802Sdavidxu keytable = malloc(ta->thread_max_keys * ta->thread_size_key); 381133802Sdavidxu if (keytable == NULL) 382133802Sdavidxu return (TD_MALLOC); 383132332Smarcel ret = ps_pread(ta->ph, (psaddr_t)ta->thread_keytable_addr, keytable, 384133802Sdavidxu ta->thread_max_keys * ta->thread_size_key); 385133805Sdavidxu if (ret != 0) { 386133805Sdavidxu free(keytable); 387132332Smarcel return (P2T(ret)); 388133805Sdavidxu } 389133802Sdavidxu for (i = 0; i < ta->thread_max_keys; i++) { 390181341Smarcel allocated = *(int *)(void *)((uintptr_t)keytable + 391181341Smarcel i * ta->thread_size_key + ta->thread_off_key_allocated); 392181341Smarcel destructor = *(void **)(void *)((uintptr_t)keytable + 393181341Smarcel i * ta->thread_size_key + ta->thread_off_key_destructor); 394133802Sdavidxu if (allocated) { 395133802Sdavidxu ret = (ki)(i, destructor, arg); 396133802Sdavidxu if (ret != 0) { 397133802Sdavidxu free(keytable); 398132332Smarcel return (TD_DBERR); 399133802Sdavidxu } 400132332Smarcel } 401132332Smarcel } 402133802Sdavidxu free(keytable); 403132332Smarcel return (TD_OK); 404132332Smarcel} 405132332Smarcel 406132332Smarcelstatic td_err_e 407181341Smarcelpt_ta_event_addr(const td_thragent_t *ta __unused, td_event_e event __unused, 408181341Smarcel td_notify_t *ptr __unused) 409132332Smarcel{ 410132332Smarcel TDBG_FUNC(); 411144922Sdavidxu return (TD_ERR); 412132332Smarcel} 413132332Smarcel 414132332Smarcelstatic td_err_e 415181341Smarcelpt_ta_set_event(const td_thragent_t *ta __unused, 416181341Smarcel td_thr_events_t *events __unused) 417132332Smarcel{ 418132332Smarcel TDBG_FUNC(); 419144922Sdavidxu return (0); 420132332Smarcel} 421132332Smarcel 422132332Smarcelstatic td_err_e 423181341Smarcelpt_ta_clear_event(const td_thragent_t *ta __unused, 424181341Smarcel td_thr_events_t *events __unused) 425132332Smarcel{ 426132332Smarcel TDBG_FUNC(); 427144922Sdavidxu return (0); 428132332Smarcel} 429132332Smarcel 430132332Smarcelstatic td_err_e 431181341Smarcelpt_ta_event_getmsg(const td_thragent_t *ta __unused, 432181341Smarcel td_event_msg_t *msg __unused) 433132332Smarcel{ 434132332Smarcel TDBG_FUNC(); 435132332Smarcel return (TD_NOMSG); 436132332Smarcel} 437132332Smarcel 438132332Smarcelstatic td_err_e 439132951Sdavidxupt_dbsuspend(const td_thrhandle_t *th, int suspend) 440132951Sdavidxu{ 441181341Smarcel const td_thragent_t *ta = th->th_ta; 442132951Sdavidxu psaddr_t tcb_addr, tmbx_addr, ptr; 443132951Sdavidxu lwpid_t lwp; 444132951Sdavidxu uint32_t dflags; 445133342Sdavidxu int attrflags, locklevel, ret; 446132951Sdavidxu 447132951Sdavidxu TDBG_FUNC(); 448132951Sdavidxu 449132951Sdavidxu ret = pt_validate(th); 450132951Sdavidxu if (ret) 451132951Sdavidxu return (ret); 452132951Sdavidxu 453132951Sdavidxu if (ta->map[th->th_tid].type == PT_LWP) { 454132951Sdavidxu if (suspend) 455132951Sdavidxu ret = ps_lstop(ta->ph, ta->map[th->th_tid].lwp); 456132951Sdavidxu else 457132951Sdavidxu ret = ps_lcontinue(ta->ph, ta->map[th->th_tid].lwp); 458132951Sdavidxu return (P2T(ret)); 459132951Sdavidxu } 460132951Sdavidxu 461132951Sdavidxu ret = ps_pread(ta->ph, ta->map[th->th_tid].thr + 462133802Sdavidxu ta->thread_off_attr_flags, 463132951Sdavidxu &attrflags, sizeof(attrflags)); 464132951Sdavidxu if (ret != 0) 465132951Sdavidxu return (P2T(ret)); 466132951Sdavidxu ret = ps_pread(ta->ph, ta->map[th->th_tid].thr + 467133802Sdavidxu ta->thread_off_tcb, 468133802Sdavidxu &tcb_addr, sizeof(tcb_addr)); 469132951Sdavidxu if (ret != 0) 470132951Sdavidxu return (P2T(ret)); 471133802Sdavidxu tmbx_addr = tcb_addr + ta->thread_off_tmbx; 472132951Sdavidxu ptr = tmbx_addr + offsetof(struct kse_thr_mailbox, tm_lwp); 473132951Sdavidxu ret = ps_pread(ta->ph, ptr, &lwp, sizeof(lwpid_t)); 474132951Sdavidxu if (ret != 0) 475132951Sdavidxu return (P2T(ret)); 476133342Sdavidxu 477133342Sdavidxu if (lwp != 0) { 478133342Sdavidxu /* don't suspend signal thread */ 479133802Sdavidxu if (attrflags & 0x200) 480133342Sdavidxu return (0); 481133342Sdavidxu if (attrflags & PTHREAD_SCOPE_SYSTEM) { 482133342Sdavidxu /* 483133342Sdavidxu * don't suspend system scope thread if it is holding 484133342Sdavidxu * some low level locks 485133342Sdavidxu */ 486133802Sdavidxu ptr = ta->map[th->th_tid].thr + ta->thread_off_kse; 487133342Sdavidxu ret = ps_pread(ta->ph, ptr, &ptr, sizeof(ptr)); 488133342Sdavidxu if (ret != 0) 489133342Sdavidxu return (P2T(ret)); 490133802Sdavidxu ret = ps_pread(ta->ph, ptr + ta->thread_off_kse_locklevel, 491133802Sdavidxu &locklevel, sizeof(int)); 492133342Sdavidxu if (ret != 0) 493133342Sdavidxu return (P2T(ret)); 494133342Sdavidxu if (locklevel <= 0) { 495133342Sdavidxu ptr = ta->map[th->th_tid].thr + 496133802Sdavidxu ta->thread_off_thr_locklevel; 497133342Sdavidxu ret = ps_pread(ta->ph, ptr, &locklevel, 498133342Sdavidxu sizeof(int)); 499133342Sdavidxu if (ret != 0) 500133342Sdavidxu return (P2T(ret)); 501133342Sdavidxu } 502133342Sdavidxu if (suspend) { 503133342Sdavidxu if (locklevel <= 0) 504133342Sdavidxu ret = ps_lstop(ta->ph, lwp); 505133342Sdavidxu } else { 506132951Sdavidxu ret = ps_lcontinue(ta->ph, lwp); 507133342Sdavidxu } 508132951Sdavidxu if (ret != 0) 509132951Sdavidxu return (P2T(ret)); 510133342Sdavidxu /* FALLTHROUGH */ 511133342Sdavidxu } else { 512133342Sdavidxu struct ptrace_lwpinfo pl; 513133342Sdavidxu 514155413Sdavidxu if (ps_linfo(ta->ph, lwp, (caddr_t)&pl)) 515133342Sdavidxu return (TD_ERR); 516133342Sdavidxu if (suspend) { 517133342Sdavidxu if (!(pl.pl_flags & PL_FLAG_BOUND)) 518133342Sdavidxu ret = ps_lstop(ta->ph, lwp); 519133342Sdavidxu } else { 520133342Sdavidxu ret = ps_lcontinue(ta->ph, lwp); 521133342Sdavidxu } 522133342Sdavidxu if (ret != 0) 523133342Sdavidxu return (P2T(ret)); 524133342Sdavidxu /* FALLTHROUGH */ 525132951Sdavidxu } 526132951Sdavidxu } 527132951Sdavidxu /* read tm_dflags */ 528132951Sdavidxu ret = ps_pread(ta->ph, 529132951Sdavidxu tmbx_addr + offsetof(struct kse_thr_mailbox, tm_dflags), 530132951Sdavidxu &dflags, sizeof(dflags)); 531132951Sdavidxu if (ret != 0) 532132951Sdavidxu return (P2T(ret)); 533132951Sdavidxu if (suspend) 534133047Sdavidxu dflags |= TMDF_SUSPEND; 535132951Sdavidxu else 536133047Sdavidxu dflags &= ~TMDF_SUSPEND; 537132951Sdavidxu ret = ps_pwrite(ta->ph, 538132951Sdavidxu tmbx_addr + offsetof(struct kse_thr_mailbox, tm_dflags), 539132951Sdavidxu &dflags, sizeof(dflags)); 540132951Sdavidxu return (P2T(ret)); 541132951Sdavidxu} 542132951Sdavidxu 543132951Sdavidxustatic td_err_e 544132332Smarcelpt_thr_dbresume(const td_thrhandle_t *th) 545132332Smarcel{ 546132332Smarcel TDBG_FUNC(); 547132951Sdavidxu 548132951Sdavidxu return pt_dbsuspend(th, 0); 549132332Smarcel} 550132332Smarcel 551132332Smarcelstatic td_err_e 552132332Smarcelpt_thr_dbsuspend(const td_thrhandle_t *th) 553132332Smarcel{ 554132332Smarcel TDBG_FUNC(); 555132951Sdavidxu 556132951Sdavidxu return pt_dbsuspend(th, 1); 557132332Smarcel} 558132332Smarcel 559132332Smarcelstatic td_err_e 560132332Smarcelpt_thr_validate(const td_thrhandle_t *th) 561132332Smarcel{ 562132332Smarcel td_thrhandle_t temp; 563132332Smarcel int ret; 564132332Smarcel 565132332Smarcel TDBG_FUNC(); 566132332Smarcel 567132332Smarcel ret = pt_ta_map_id2thr(th->th_ta, th->th_tid, 568132332Smarcel &temp); 569132951Sdavidxu return (ret); 570132332Smarcel} 571132332Smarcel 572132332Smarcelstatic td_err_e 573209689Skibpt_thr_old_get_info(const td_thrhandle_t *th, td_old_thrinfo_t *info) 574132332Smarcel{ 575132332Smarcel const td_thragent_t *ta = th->th_ta; 576158680Sdavidxu struct ptrace_lwpinfo linfo; 577133802Sdavidxu psaddr_t tcb_addr; 578133802Sdavidxu uint32_t dflags; 579158680Sdavidxu lwpid_t lwp; 580133802Sdavidxu int state; 581132332Smarcel int ret; 582158680Sdavidxu int attrflags; 583132332Smarcel 584132332Smarcel TDBG_FUNC(); 585132332Smarcel 586155387Sdavidxu bzero(info, sizeof(*info)); 587132332Smarcel ret = pt_validate(th); 588132332Smarcel if (ret) 589132332Smarcel return (ret); 590132332Smarcel 591132332Smarcel memset(info, 0, sizeof(*info)); 592132332Smarcel if (ta->map[th->th_tid].type == PT_LWP) { 593132332Smarcel info->ti_type = TD_THR_SYSTEM; 594132332Smarcel info->ti_lid = ta->map[th->th_tid].lwp; 595132332Smarcel info->ti_tid = th->th_tid; 596132332Smarcel info->ti_state = TD_THR_RUN; 597132332Smarcel info->ti_type = TD_THR_SYSTEM; 598132332Smarcel return (TD_OK); 599132332Smarcel } 600158680Sdavidxu 601158680Sdavidxu ret = ps_pread(ta->ph, ta->map[th->th_tid].thr + 602158680Sdavidxu ta->thread_off_attr_flags, 603158680Sdavidxu &attrflags, sizeof(attrflags)); 604158680Sdavidxu if (ret != 0) 605158680Sdavidxu return (P2T(ret)); 606133802Sdavidxu ret = ps_pread(ta->ph, ta->map[th->th_tid].thr + ta->thread_off_tcb, 607133802Sdavidxu &tcb_addr, sizeof(tcb_addr)); 608132332Smarcel if (ret != 0) 609132332Smarcel return (P2T(ret)); 610133802Sdavidxu ret = ps_pread(ta->ph, ta->map[th->th_tid].thr + ta->thread_off_state, 611133802Sdavidxu &state, sizeof(state)); 612132332Smarcel ret = ps_pread(ta->ph, 613133802Sdavidxu tcb_addr + ta->thread_off_tmbx + 614133802Sdavidxu offsetof(struct kse_thr_mailbox, tm_lwp), 615132332Smarcel &info->ti_lid, sizeof(lwpid_t)); 616132332Smarcel if (ret != 0) 617132332Smarcel return (P2T(ret)); 618132951Sdavidxu ret = ps_pread(ta->ph, 619133802Sdavidxu tcb_addr + ta->thread_off_tmbx + 620133802Sdavidxu offsetof(struct kse_thr_mailbox, tm_dflags), 621132951Sdavidxu &dflags, sizeof(dflags)); 622132951Sdavidxu if (ret != 0) 623132951Sdavidxu return (P2T(ret)); 624158680Sdavidxu ret = ps_pread(ta->ph, tcb_addr + ta->thread_off_tmbx + 625158680Sdavidxu offsetof(struct kse_thr_mailbox, tm_lwp), &lwp, sizeof(lwpid_t)); 626158680Sdavidxu if (ret != 0) 627158680Sdavidxu return (P2T(ret)); 628132332Smarcel info->ti_ta_p = th->th_ta; 629132332Smarcel info->ti_tid = th->th_tid; 630158680Sdavidxu 631158680Sdavidxu if (attrflags & PTHREAD_SCOPE_SYSTEM) { 632158680Sdavidxu ret = ps_linfo(ta->ph, lwp, &linfo); 633158680Sdavidxu if (ret == PS_OK) { 634158680Sdavidxu info->ti_sigmask = linfo.pl_sigmask; 635158680Sdavidxu info->ti_pending = linfo.pl_siglist; 636158680Sdavidxu } else 637158680Sdavidxu return (ret); 638158680Sdavidxu } else { 639158680Sdavidxu ret = ps_pread(ta->ph, 640158680Sdavidxu ta->map[th->th_tid].thr + ta->thread_off_sigmask, 641158680Sdavidxu &info->ti_sigmask, sizeof(sigset_t)); 642158680Sdavidxu if (ret) 643158680Sdavidxu return (ret); 644158680Sdavidxu ret = ps_pread(ta->ph, 645158680Sdavidxu ta->map[th->th_tid].thr + ta->thread_off_sigpend, 646158680Sdavidxu &info->ti_pending, sizeof(sigset_t)); 647158680Sdavidxu if (ret) 648158680Sdavidxu return (ret); 649158680Sdavidxu } 650158680Sdavidxu 651133802Sdavidxu if (state == ta->thread_state_running) 652132332Smarcel info->ti_state = TD_THR_RUN; 653133802Sdavidxu else if (state == ta->thread_state_zoombie) 654133802Sdavidxu info->ti_state = TD_THR_ZOMBIE; 655133802Sdavidxu else 656132332Smarcel info->ti_state = TD_THR_SLEEP; 657133047Sdavidxu info->ti_db_suspended = ((dflags & TMDF_SUSPEND) != 0); 658132332Smarcel info->ti_type = TD_THR_USER; 659132332Smarcel return (0); 660132332Smarcel} 661132332Smarcel 662209689Skibstatic td_err_e 663209689Skibpt_thr_get_info(const td_thrhandle_t *th, td_thrinfo_t *info) 664209689Skib{ 665209689Skib td_err_e e; 666209689Skib 667209689Skib e = pt_thr_old_get_info(th, (td_old_thrinfo_t *)info); 668209689Skib bzero(&info->ti_siginfo, sizeof(info->ti_siginfo)); 669209689Skib return (e); 670209689Skib} 671209689Skib 672146818Sdfr#ifdef __i386__ 673132332Smarcelstatic td_err_e 674146818Sdfrpt_thr_getxmmregs(const td_thrhandle_t *th, char *fxsave) 675146818Sdfr{ 676146818Sdfr const td_thragent_t *ta = th->th_ta; 677146818Sdfr struct kse_thr_mailbox tmbx; 678146818Sdfr psaddr_t tcb_addr, tmbx_addr, ptr; 679146818Sdfr lwpid_t lwp; 680146818Sdfr int ret; 681146818Sdfr 682146818Sdfr return TD_ERR; 683146818Sdfr 684146818Sdfr TDBG_FUNC(); 685146818Sdfr 686146818Sdfr ret = pt_validate(th); 687146818Sdfr if (ret) 688146818Sdfr return (ret); 689146818Sdfr 690146818Sdfr if (ta->map[th->th_tid].type == PT_LWP) { 691146818Sdfr ret = ps_lgetxmmregs(ta->ph, ta->map[th->th_tid].lwp, fxsave); 692146818Sdfr return (P2T(ret)); 693146818Sdfr } 694146818Sdfr 695146818Sdfr ret = ps_pread(ta->ph, ta->map[th->th_tid].thr + ta->thread_off_tcb, 696146818Sdfr &tcb_addr, sizeof(tcb_addr)); 697146818Sdfr if (ret != 0) 698146818Sdfr return (P2T(ret)); 699146818Sdfr tmbx_addr = tcb_addr + ta->thread_off_tmbx; 700146818Sdfr ptr = tmbx_addr + offsetof(struct kse_thr_mailbox, tm_lwp); 701146818Sdfr ret = ps_pread(ta->ph, ptr, &lwp, sizeof(lwpid_t)); 702146818Sdfr if (ret != 0) 703146818Sdfr return (P2T(ret)); 704146818Sdfr if (lwp != 0) { 705146818Sdfr ret = ps_lgetxmmregs(ta->ph, lwp, fxsave); 706146818Sdfr return (P2T(ret)); 707146818Sdfr } 708146818Sdfr 709146818Sdfr ret = ps_pread(ta->ph, tmbx_addr, &tmbx, sizeof(tmbx)); 710146818Sdfr if (ret != 0) 711146818Sdfr return (P2T(ret)); 712146818Sdfr pt_ucontext_to_fxsave(&tmbx.tm_context, fxsave); 713146818Sdfr return (0); 714146818Sdfr} 715146818Sdfr#endif 716146818Sdfr 717146818Sdfrstatic td_err_e 718132332Smarcelpt_thr_getfpregs(const td_thrhandle_t *th, prfpregset_t *fpregs) 719132332Smarcel{ 720132332Smarcel const td_thragent_t *ta = th->th_ta; 721132332Smarcel struct kse_thr_mailbox tmbx; 722132332Smarcel psaddr_t tcb_addr, tmbx_addr, ptr; 723132332Smarcel lwpid_t lwp; 724132332Smarcel int ret; 725132332Smarcel 726132332Smarcel TDBG_FUNC(); 727132332Smarcel 728132332Smarcel ret = pt_validate(th); 729132332Smarcel if (ret) 730132332Smarcel return (ret); 731132332Smarcel 732132332Smarcel if (ta->map[th->th_tid].type == PT_LWP) { 733132332Smarcel ret = ps_lgetfpregs(ta->ph, ta->map[th->th_tid].lwp, fpregs); 734132332Smarcel return (P2T(ret)); 735132332Smarcel } 736132332Smarcel 737133802Sdavidxu ret = ps_pread(ta->ph, ta->map[th->th_tid].thr + ta->thread_off_tcb, 738132951Sdavidxu &tcb_addr, sizeof(tcb_addr)); 739132332Smarcel if (ret != 0) 740132332Smarcel return (P2T(ret)); 741133802Sdavidxu tmbx_addr = tcb_addr + ta->thread_off_tmbx; 742132332Smarcel ptr = tmbx_addr + offsetof(struct kse_thr_mailbox, tm_lwp); 743132332Smarcel ret = ps_pread(ta->ph, ptr, &lwp, sizeof(lwpid_t)); 744132332Smarcel if (ret != 0) 745132332Smarcel return (P2T(ret)); 746132332Smarcel if (lwp != 0) { 747132332Smarcel ret = ps_lgetfpregs(ta->ph, lwp, fpregs); 748132332Smarcel return (P2T(ret)); 749132332Smarcel } 750132332Smarcel 751132332Smarcel ret = ps_pread(ta->ph, tmbx_addr, &tmbx, sizeof(tmbx)); 752132332Smarcel if (ret != 0) 753132332Smarcel return (P2T(ret)); 754132332Smarcel pt_ucontext_to_fpreg(&tmbx.tm_context, fpregs); 755132332Smarcel return (0); 756132332Smarcel} 757132332Smarcel 758132332Smarcelstatic td_err_e 759132332Smarcelpt_thr_getgregs(const td_thrhandle_t *th, prgregset_t gregs) 760132332Smarcel{ 761132332Smarcel const td_thragent_t *ta = th->th_ta; 762132332Smarcel struct kse_thr_mailbox tmbx; 763132332Smarcel psaddr_t tcb_addr, tmbx_addr, ptr; 764132332Smarcel lwpid_t lwp; 765132332Smarcel int ret; 766132332Smarcel 767132332Smarcel TDBG_FUNC(); 768132332Smarcel 769132332Smarcel ret = pt_validate(th); 770132332Smarcel if (ret) 771132332Smarcel return (ret); 772132332Smarcel 773132332Smarcel if (ta->map[th->th_tid].type == PT_LWP) { 774132332Smarcel ret = ps_lgetregs(ta->ph, 775132332Smarcel ta->map[th->th_tid].lwp, gregs); 776132332Smarcel return (P2T(ret)); 777132332Smarcel } 778132332Smarcel 779133802Sdavidxu ret = ps_pread(ta->ph, ta->map[th->th_tid].thr + ta->thread_off_tcb, 780132332Smarcel &tcb_addr, sizeof(tcb_addr)); 781132332Smarcel if (ret != 0) 782132332Smarcel return (P2T(ret)); 783133802Sdavidxu tmbx_addr = tcb_addr + ta->thread_off_tmbx; 784132332Smarcel ptr = tmbx_addr + offsetof(struct kse_thr_mailbox, tm_lwp); 785132332Smarcel ret = ps_pread(ta->ph, ptr, &lwp, sizeof(lwpid_t)); 786132332Smarcel if (ret != 0) 787132332Smarcel return (P2T(ret)); 788132332Smarcel if (lwp != 0) { 789132332Smarcel ret = ps_lgetregs(ta->ph, lwp, gregs); 790132332Smarcel return (P2T(ret)); 791132332Smarcel } 792132332Smarcel ret = ps_pread(ta->ph, tmbx_addr, &tmbx, sizeof(tmbx)); 793132332Smarcel if (ret != 0) 794132332Smarcel return (P2T(ret)); 795132332Smarcel pt_ucontext_to_reg(&tmbx.tm_context, gregs); 796132332Smarcel return (0); 797132332Smarcel} 798132332Smarcel 799146818Sdfr#ifdef __i386__ 800132332Smarcelstatic td_err_e 801146818Sdfrpt_thr_setxmmregs(const td_thrhandle_t *th, const char *fxsave) 802146818Sdfr{ 803146818Sdfr const td_thragent_t *ta = th->th_ta; 804146818Sdfr struct kse_thr_mailbox tmbx; 805146818Sdfr psaddr_t tcb_addr, tmbx_addr, ptr; 806146818Sdfr lwpid_t lwp; 807146818Sdfr int ret; 808146818Sdfr 809146818Sdfr return TD_ERR; 810146818Sdfr 811146818Sdfr TDBG_FUNC(); 812146818Sdfr 813146818Sdfr ret = pt_validate(th); 814146818Sdfr if (ret) 815146818Sdfr return (ret); 816146818Sdfr 817146818Sdfr if (ta->map[th->th_tid].type == PT_LWP) { 818146818Sdfr ret = ps_lsetxmmregs(ta->ph, ta->map[th->th_tid].lwp, fxsave); 819146818Sdfr return (P2T(ret)); 820146818Sdfr } 821146818Sdfr 822146818Sdfr ret = ps_pread(ta->ph, ta->map[th->th_tid].thr + 823146818Sdfr ta->thread_off_tcb, 824146818Sdfr &tcb_addr, sizeof(tcb_addr)); 825146818Sdfr if (ret != 0) 826146818Sdfr return (P2T(ret)); 827146818Sdfr tmbx_addr = tcb_addr + ta->thread_off_tmbx; 828146818Sdfr ptr = tmbx_addr + offsetof(struct kse_thr_mailbox, tm_lwp); 829146818Sdfr ret = ps_pread(ta->ph, ptr, &lwp, sizeof(lwpid_t)); 830146818Sdfr if (ret != 0) 831146818Sdfr return (P2T(ret)); 832146818Sdfr if (lwp != 0) { 833146818Sdfr ret = ps_lsetxmmregs(ta->ph, lwp, fxsave); 834146818Sdfr return (P2T(ret)); 835146818Sdfr } 836146818Sdfr /* 837146818Sdfr * Read a copy of context, this makes sure that registers 838146818Sdfr * not covered by structure reg won't be clobbered 839146818Sdfr */ 840146818Sdfr ret = ps_pread(ta->ph, tmbx_addr, &tmbx, sizeof(tmbx)); 841146818Sdfr if (ret != 0) 842146818Sdfr return (P2T(ret)); 843146818Sdfr 844146818Sdfr pt_fxsave_to_ucontext(fxsave, &tmbx.tm_context); 845146818Sdfr ret = ps_pwrite(ta->ph, tmbx_addr, &tmbx, sizeof(tmbx)); 846146818Sdfr return (P2T(ret)); 847146818Sdfr} 848146818Sdfr#endif 849146818Sdfr 850146818Sdfrstatic td_err_e 851132332Smarcelpt_thr_setfpregs(const td_thrhandle_t *th, const prfpregset_t *fpregs) 852132332Smarcel{ 853132332Smarcel const td_thragent_t *ta = th->th_ta; 854132332Smarcel struct kse_thr_mailbox tmbx; 855132332Smarcel psaddr_t tcb_addr, tmbx_addr, ptr; 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 ret = ps_lsetfpregs(ta->ph, ta->map[th->th_tid].lwp, fpregs); 867132332Smarcel return (P2T(ret)); 868132332Smarcel } 869132332Smarcel 870132332Smarcel ret = ps_pread(ta->ph, ta->map[th->th_tid].thr + 871133802Sdavidxu ta->thread_off_tcb, 872132332Smarcel &tcb_addr, sizeof(tcb_addr)); 873132332Smarcel if (ret != 0) 874132332Smarcel return (P2T(ret)); 875133802Sdavidxu tmbx_addr = tcb_addr + ta->thread_off_tmbx; 876132332Smarcel ptr = tmbx_addr + offsetof(struct kse_thr_mailbox, tm_lwp); 877132332Smarcel ret = ps_pread(ta->ph, ptr, &lwp, sizeof(lwpid_t)); 878132332Smarcel if (ret != 0) 879132332Smarcel return (P2T(ret)); 880132332Smarcel if (lwp != 0) { 881132332Smarcel ret = ps_lsetfpregs(ta->ph, lwp, fpregs); 882132332Smarcel return (P2T(ret)); 883132332Smarcel } 884132332Smarcel /* 885132332Smarcel * Read a copy of context, this makes sure that registers 886132332Smarcel * not covered by structure reg won't be clobbered 887132332Smarcel */ 888132332Smarcel ret = ps_pread(ta->ph, tmbx_addr, &tmbx, sizeof(tmbx)); 889132332Smarcel if (ret != 0) 890132332Smarcel return (P2T(ret)); 891132332Smarcel 892132332Smarcel pt_fpreg_to_ucontext(fpregs, &tmbx.tm_context); 893132332Smarcel ret = ps_pwrite(ta->ph, tmbx_addr, &tmbx, sizeof(tmbx)); 894132332Smarcel return (P2T(ret)); 895132332Smarcel} 896132332Smarcel 897132332Smarcelstatic td_err_e 898132332Smarcelpt_thr_setgregs(const td_thrhandle_t *th, const prgregset_t gregs) 899132332Smarcel{ 900132332Smarcel const td_thragent_t *ta = th->th_ta; 901132332Smarcel struct kse_thr_mailbox tmbx; 902132332Smarcel psaddr_t tcb_addr, tmbx_addr, ptr; 903132332Smarcel lwpid_t lwp; 904132332Smarcel int ret; 905132332Smarcel 906132332Smarcel TDBG_FUNC(); 907132332Smarcel 908132332Smarcel ret = pt_validate(th); 909132332Smarcel if (ret) 910132332Smarcel return (ret); 911132332Smarcel 912132332Smarcel if (ta->map[th->th_tid].type == PT_LWP) { 913132332Smarcel ret = ps_lsetregs(ta->ph, ta->map[th->th_tid].lwp, gregs); 914132332Smarcel return (P2T(ret)); 915132332Smarcel } 916132332Smarcel 917132332Smarcel ret = ps_pread(ta->ph, ta->map[th->th_tid].thr + 918133802Sdavidxu ta->thread_off_tcb, 919132332Smarcel &tcb_addr, sizeof(tcb_addr)); 920132332Smarcel if (ret != 0) 921132332Smarcel return (P2T(ret)); 922133802Sdavidxu tmbx_addr = tcb_addr + ta->thread_off_tmbx; 923132332Smarcel ptr = tmbx_addr + offsetof(struct kse_thr_mailbox, tm_lwp); 924132332Smarcel ret = ps_pread(ta->ph, ptr, &lwp, sizeof(lwpid_t)); 925132332Smarcel if (ret != 0) 926132332Smarcel return (P2T(ret)); 927132332Smarcel if (lwp != 0) { 928132332Smarcel ret = ps_lsetregs(ta->ph, lwp, gregs); 929132332Smarcel return (P2T(ret)); 930132332Smarcel } 931132332Smarcel 932132332Smarcel /* 933132332Smarcel * Read a copy of context, make sure that registers 934132332Smarcel * not covered by structure reg won't be clobbered 935132332Smarcel */ 936132332Smarcel ret = ps_pread(ta->ph, tmbx_addr, &tmbx, sizeof(tmbx)); 937132332Smarcel if (ret != 0) 938132332Smarcel return (P2T(ret)); 939132332Smarcel pt_reg_to_ucontext(gregs, &tmbx.tm_context); 940132332Smarcel ret = ps_pwrite(ta->ph, tmbx_addr, &tmbx, sizeof(tmbx)); 941132332Smarcel return (P2T(ret)); 942132332Smarcel} 943132332Smarcel 944132332Smarcelstatic td_err_e 945181341Smarcelpt_thr_event_enable(const td_thrhandle_t *th __unused, int en __unused) 946132332Smarcel{ 947132332Smarcel TDBG_FUNC(); 948144922Sdavidxu return (0); 949132332Smarcel} 950132332Smarcel 951132332Smarcelstatic td_err_e 952181341Smarcelpt_thr_set_event(const td_thrhandle_t *th __unused, 953181341Smarcel td_thr_events_t *setp __unused) 954132332Smarcel{ 955132332Smarcel TDBG_FUNC(); 956144922Sdavidxu return (0); 957132332Smarcel} 958132332Smarcel 959132332Smarcelstatic td_err_e 960181341Smarcelpt_thr_clear_event(const td_thrhandle_t *th __unused, 961181341Smarcel td_thr_events_t *setp __unused) 962132332Smarcel{ 963132332Smarcel TDBG_FUNC(); 964144922Sdavidxu return (0); 965132332Smarcel} 966132332Smarcel 967132332Smarcelstatic td_err_e 968181341Smarcelpt_thr_event_getmsg(const td_thrhandle_t *th __unused, 969181341Smarcel td_event_msg_t *msg __unused) 970132332Smarcel{ 971132332Smarcel TDBG_FUNC(); 972132332Smarcel return (TD_NOMSG); 973132332Smarcel} 974132332Smarcel 975132332Smarcelstatic td_err_e 976132332Smarcelpt_thr_sstep(const td_thrhandle_t *th, int step) 977132332Smarcel{ 978132332Smarcel const td_thragent_t *ta = th->th_ta; 979132332Smarcel struct kse_thr_mailbox tmbx; 980132332Smarcel struct reg regs; 981132332Smarcel psaddr_t tcb_addr, tmbx_addr; 982132951Sdavidxu uint32_t dflags; 983132332Smarcel lwpid_t lwp; 984132332Smarcel int ret; 985132332Smarcel 986132332Smarcel TDBG_FUNC(); 987132332Smarcel 988132332Smarcel ret = pt_validate(th); 989132332Smarcel if (ret) 990132332Smarcel return (ret); 991132332Smarcel 992132332Smarcel if (ta->map[th->th_tid].type == PT_LWP) 993132332Smarcel return (TD_BADTH); 994132332Smarcel 995132332Smarcel ret = ps_pread(ta->ph, ta->map[th->th_tid].thr + 996133802Sdavidxu ta->thread_off_tcb, 997132332Smarcel &tcb_addr, sizeof(tcb_addr)); 998132332Smarcel if (ret != 0) 999132332Smarcel return (P2T(ret)); 1000132332Smarcel 1001132332Smarcel /* Clear or set single step flag in thread mailbox */ 1002133802Sdavidxu ret = ps_pread(ta->ph, 1003133802Sdavidxu tcb_addr + ta->thread_off_tmbx + 1004133802Sdavidxu offsetof(struct kse_thr_mailbox, tm_dflags), 1005133802Sdavidxu &dflags, sizeof(uint32_t)); 1006132951Sdavidxu if (ret != 0) 1007132951Sdavidxu return (P2T(ret)); 1008132951Sdavidxu if (step != 0) 1009132951Sdavidxu dflags |= TMDF_SSTEP; 1010132951Sdavidxu else 1011132951Sdavidxu dflags &= ~TMDF_SSTEP; 1012133802Sdavidxu ret = ps_pwrite(ta->ph, 1013133802Sdavidxu tcb_addr + ta->thread_off_tmbx + 1014133802Sdavidxu offsetof(struct kse_thr_mailbox, tm_dflags), 1015133802Sdavidxu &dflags, sizeof(uint32_t)); 1016132332Smarcel if (ret != 0) 1017132332Smarcel return (P2T(ret)); 1018132332Smarcel /* Get lwp */ 1019133802Sdavidxu ret = ps_pread(ta->ph, 1020133802Sdavidxu tcb_addr + ta->thread_off_tmbx + 1021133802Sdavidxu offsetof(struct kse_thr_mailbox, tm_lwp), 1022133802Sdavidxu &lwp, sizeof(lwpid_t)); 1023132332Smarcel if (ret != 0) 1024132332Smarcel return (P2T(ret)); 1025132332Smarcel if (lwp != 0) 1026132951Sdavidxu return (0); 1027132332Smarcel 1028133802Sdavidxu tmbx_addr = tcb_addr + ta->thread_off_tmbx; 1029132332Smarcel /* 1030132332Smarcel * context is in userland, some architectures store 1031132332Smarcel * single step status in registers, we should change 1032132332Smarcel * these registers. 1033132332Smarcel */ 1034132332Smarcel ret = ps_pread(ta->ph, tmbx_addr, &tmbx, sizeof(tmbx)); 1035132332Smarcel if (ret == 0) { 1036132332Smarcel pt_ucontext_to_reg(&tmbx.tm_context, ®s); 1037132332Smarcel /* only write out if it is really changed. */ 1038132332Smarcel if (pt_reg_sstep(®s, step) != 0) { 1039132332Smarcel pt_reg_to_ucontext(®s, &tmbx.tm_context); 1040132332Smarcel ret = ps_pwrite(ta->ph, tmbx_addr, &tmbx, 1041132332Smarcel sizeof(tmbx)); 1042132332Smarcel } 1043132332Smarcel } 1044132332Smarcel return (P2T(ret)); 1045132332Smarcel} 1046132332Smarcel 1047132332Smarcelstatic void 1048132332Smarcelpt_unmap_lwp(const td_thragent_t *ta, lwpid_t lwp) 1049132332Smarcel{ 1050132332Smarcel int i; 1051132332Smarcel 1052132332Smarcel for (i = 0; i < ta->map_len; ++i) { 1053132332Smarcel if (ta->map[i].type == PT_LWP && ta->map[i].lwp == lwp) { 1054132332Smarcel ta->map[i].type = PT_NONE; 1055132332Smarcel return; 1056132332Smarcel } 1057132332Smarcel } 1058132332Smarcel} 1059132332Smarcel 1060132332Smarcelstatic int 1061132332Smarcelpt_validate(const td_thrhandle_t *th) 1062132332Smarcel{ 1063132332Smarcel 1064132332Smarcel if (th->th_tid < 0 || th->th_tid >= th->th_ta->map_len || 1065132332Smarcel th->th_ta->map[th->th_tid].type == PT_NONE) 1066132332Smarcel return (TD_NOTHR); 1067132332Smarcel return (TD_OK); 1068132332Smarcel} 1069132332Smarcel 1070181059Smarcelstatic td_err_e 1071180982Smarcelpt_thr_tls_get_addr(const td_thrhandle_t *th, psaddr_t _linkmap, size_t offset, 1072180982Smarcel psaddr_t *address) 1073133342Sdavidxu{ 1074133342Sdavidxu const td_thragent_t *ta = th->th_ta; 1075180982Smarcel psaddr_t dtv_addr, obj_entry, tcb_addr; 1076133342Sdavidxu int tls_index, ret; 1077133342Sdavidxu 1078133342Sdavidxu /* linkmap is a member of Obj_Entry */ 1079180982Smarcel obj_entry = _linkmap - ta->thread_off_linkmap; 1080133342Sdavidxu 1081133342Sdavidxu /* get tlsindex of the object file */ 1082133342Sdavidxu ret = ps_pread(ta->ph, 1083133802Sdavidxu obj_entry + ta->thread_off_tlsindex, 1084133342Sdavidxu &tls_index, sizeof(tls_index)); 1085133342Sdavidxu if (ret != 0) 1086133342Sdavidxu return (P2T(ret)); 1087133342Sdavidxu 1088133342Sdavidxu /* get thread tcb */ 1089133342Sdavidxu ret = ps_pread(ta->ph, ta->map[th->th_tid].thr + 1090133802Sdavidxu ta->thread_off_tcb, 1091133342Sdavidxu &tcb_addr, sizeof(tcb_addr)); 1092133342Sdavidxu if (ret != 0) 1093133342Sdavidxu return (P2T(ret)); 1094133342Sdavidxu 1095133342Sdavidxu /* get dtv array address */ 1096133802Sdavidxu ret = ps_pread(ta->ph, tcb_addr + ta->thread_off_dtv, 1097133342Sdavidxu &dtv_addr, sizeof(dtv_addr)); 1098133342Sdavidxu if (ret != 0) 1099133342Sdavidxu return (P2T(ret)); 1100133342Sdavidxu /* now get the object's tls block base address */ 1101180982Smarcel ret = ps_pread(ta->ph, dtv_addr + sizeof(void *) * (tls_index + 1), 1102180982Smarcel address, sizeof(*address)); 1103133342Sdavidxu if (ret != 0) 1104133342Sdavidxu return (P2T(ret)); 1105133342Sdavidxu 1106133342Sdavidxu *address += offset; 1107133342Sdavidxu return (TD_OK); 1108133342Sdavidxu} 1109133342Sdavidxu 1110132332Smarcelstruct ta_ops libpthread_db_ops = { 1111132332Smarcel .to_init = pt_init, 1112132332Smarcel .to_ta_clear_event = pt_ta_clear_event, 1113132332Smarcel .to_ta_delete = pt_ta_delete, 1114132332Smarcel .to_ta_event_addr = pt_ta_event_addr, 1115132332Smarcel .to_ta_event_getmsg = pt_ta_event_getmsg, 1116132332Smarcel .to_ta_map_id2thr = pt_ta_map_id2thr, 1117132332Smarcel .to_ta_map_lwp2thr = pt_ta_map_lwp2thr, 1118132332Smarcel .to_ta_new = pt_ta_new, 1119132332Smarcel .to_ta_set_event = pt_ta_set_event, 1120132332Smarcel .to_ta_thr_iter = pt_ta_thr_iter, 1121132332Smarcel .to_ta_tsd_iter = pt_ta_tsd_iter, 1122132332Smarcel .to_thr_clear_event = pt_thr_clear_event, 1123132332Smarcel .to_thr_dbresume = pt_thr_dbresume, 1124132332Smarcel .to_thr_dbsuspend = pt_thr_dbsuspend, 1125132332Smarcel .to_thr_event_enable = pt_thr_event_enable, 1126132332Smarcel .to_thr_event_getmsg = pt_thr_event_getmsg, 1127209689Skib .to_thr_old_get_info = pt_thr_old_get_info, 1128132332Smarcel .to_thr_get_info = pt_thr_get_info, 1129132332Smarcel .to_thr_getfpregs = pt_thr_getfpregs, 1130132332Smarcel .to_thr_getgregs = pt_thr_getgregs, 1131132332Smarcel .to_thr_set_event = pt_thr_set_event, 1132132332Smarcel .to_thr_setfpregs = pt_thr_setfpregs, 1133132332Smarcel .to_thr_setgregs = pt_thr_setgregs, 1134132332Smarcel .to_thr_validate = pt_thr_validate, 1135133342Sdavidxu .to_thr_tls_get_addr = pt_thr_tls_get_addr, 1136132332Smarcel 1137132332Smarcel /* FreeBSD specific extensions. */ 1138132332Smarcel .to_thr_sstep = pt_thr_sstep, 1139146818Sdfr#ifdef __i386__ 1140146818Sdfr .to_thr_getxmmregs = pt_thr_getxmmregs, 1141146818Sdfr .to_thr_setxmmregs = pt_thr_setxmmregs, 1142146818Sdfr#endif 1143132332Smarcel}; 1144177490Sdavidxu 1145177490SdavidxuDATA_SET(__ta_ops, libpthread_db_ops); 1146