1132332Smarcel/* 2132332Smarcel * Copyright (c) 2004 Marcel Moolenaar 3144519Sdavidxu * Copyright (c) 2005 David Xu 4132332Smarcel * All rights reserved. 5132332Smarcel * 6132332Smarcel * Redistribution and use in source and binary forms, with or without 7132332Smarcel * modification, are permitted provided that the following conditions 8132332Smarcel * are met: 9132332Smarcel * 10132332Smarcel * 1. Redistributions of source code must retain the above copyright 11132332Smarcel * notice, this list of conditions and the following disclaimer. 12132332Smarcel * 2. Redistributions in binary form must reproduce the above copyright 13132332Smarcel * notice, this list of conditions and the following disclaimer in the 14132332Smarcel * documentation and/or other materials provided with the distribution. 15132332Smarcel * 16132332Smarcel * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 17132332Smarcel * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 18132332Smarcel * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 19132332Smarcel * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 20132332Smarcel * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 21132332Smarcel * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 22132332Smarcel * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 23132332Smarcel * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 24132332Smarcel * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 25132332Smarcel * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26132332Smarcel */ 27132332Smarcel 28132332Smarcel#include <sys/cdefs.h> 29132332Smarcel__FBSDID("$FreeBSD$"); 30132332Smarcel 31132332Smarcel#include <proc_service.h> 32144519Sdavidxu#include <stddef.h> 33132332Smarcel#include <stdlib.h> 34144519Sdavidxu#include <string.h> 35144519Sdavidxu#include <sys/types.h> 36177490Sdavidxu#include <sys/linker_set.h> 37144519Sdavidxu#include <sys/ptrace.h> 38132332Smarcel#include <thread_db.h> 39144519Sdavidxu#include <unistd.h> 40132332Smarcel 41132332Smarcel#include "thread_db_int.h" 42132332Smarcel 43144922Sdavidxu#define TERMINATED 1 44144922Sdavidxu 45132332Smarcelstruct td_thragent { 46132332Smarcel TD_THRAGENT_FIELDS; 47144519Sdavidxu psaddr_t libthr_debug_addr; 48144519Sdavidxu psaddr_t thread_list_addr; 49144519Sdavidxu psaddr_t thread_active_threads_addr; 50144519Sdavidxu psaddr_t thread_keytable_addr; 51144922Sdavidxu psaddr_t thread_last_event_addr; 52144922Sdavidxu psaddr_t thread_event_mask_addr; 53144922Sdavidxu psaddr_t thread_bp_create_addr; 54144922Sdavidxu psaddr_t thread_bp_death_addr; 55144519Sdavidxu int thread_off_dtv; 56144519Sdavidxu int thread_off_tlsindex; 57144519Sdavidxu int thread_off_attr_flags; 58144519Sdavidxu int thread_size_key; 59144519Sdavidxu int thread_off_tcb; 60144519Sdavidxu int thread_off_linkmap; 61144519Sdavidxu int thread_off_next; 62144519Sdavidxu int thread_off_state; 63144519Sdavidxu int thread_off_tid; 64144519Sdavidxu int thread_max_keys; 65144519Sdavidxu int thread_off_key_allocated; 66144519Sdavidxu int thread_off_key_destructor; 67144922Sdavidxu int thread_off_report_events; 68144922Sdavidxu int thread_off_event_mask; 69144922Sdavidxu int thread_off_event_buf; 70144519Sdavidxu int thread_state_zoombie; 71144519Sdavidxu int thread_state_running; 72132332Smarcel}; 73132332Smarcel 74144519Sdavidxu#define P2T(c) ps2td(c) 75144519Sdavidxu 76144519Sdavidxustatic int pt_validate(const td_thrhandle_t *th); 77144519Sdavidxu 78144519Sdavidxustatic int 79144519Sdavidxups2td(int c) 80132332Smarcel{ 81144519Sdavidxu switch (c) { 82144519Sdavidxu case PS_OK: 83144519Sdavidxu return TD_OK; 84144519Sdavidxu case PS_ERR: 85144519Sdavidxu return TD_ERR; 86144519Sdavidxu case PS_BADPID: 87144519Sdavidxu return TD_BADPH; 88144519Sdavidxu case PS_BADLID: 89144519Sdavidxu return TD_NOLWP; 90144519Sdavidxu case PS_BADADDR: 91144519Sdavidxu return TD_ERR; 92144519Sdavidxu case PS_NOSYM: 93144519Sdavidxu return TD_NOLIBTHREAD; 94144519Sdavidxu case PS_NOFREGS: 95144519Sdavidxu return TD_NOFPREGS; 96144519Sdavidxu default: 97144519Sdavidxu return TD_ERR; 98144519Sdavidxu } 99132332Smarcel} 100132332Smarcel 101132332Smarcelstatic td_err_e 102144519Sdavidxupt_init(void) 103132332Smarcel{ 104144519Sdavidxu return (0); 105132332Smarcel} 106132332Smarcel 107132332Smarcelstatic td_err_e 108144519Sdavidxupt_ta_new(struct ps_prochandle *ph, td_thragent_t **pta) 109132332Smarcel{ 110144519Sdavidxu#define LOOKUP_SYM(proc, sym, addr) \ 111144519Sdavidxu ret = ps_pglobal_lookup(proc, NULL, sym, addr); \ 112144519Sdavidxu if (ret != 0) { \ 113144519Sdavidxu TDBG("can not find symbol: %s\n", sym); \ 114144519Sdavidxu ret = TD_NOLIBTHREAD; \ 115144519Sdavidxu goto error; \ 116144519Sdavidxu } 117144519Sdavidxu 118144519Sdavidxu#define LOOKUP_VAL(proc, sym, val) \ 119144519Sdavidxu ret = ps_pglobal_lookup(proc, NULL, sym, &vaddr);\ 120144519Sdavidxu if (ret != 0) { \ 121144519Sdavidxu TDBG("can not find symbol: %s\n", sym); \ 122144519Sdavidxu ret = TD_NOLIBTHREAD; \ 123144519Sdavidxu goto error; \ 124144519Sdavidxu } \ 125144519Sdavidxu ret = ps_pread(proc, vaddr, val, sizeof(int)); \ 126144519Sdavidxu if (ret != 0) { \ 127144519Sdavidxu TDBG("can not read value of %s\n", sym);\ 128144519Sdavidxu ret = TD_NOLIBTHREAD; \ 129144519Sdavidxu goto error; \ 130144519Sdavidxu } 131144519Sdavidxu 132144519Sdavidxu td_thragent_t *ta; 133144519Sdavidxu psaddr_t vaddr; 134144519Sdavidxu int dbg; 135144519Sdavidxu int ret; 136144519Sdavidxu 137144519Sdavidxu TDBG_FUNC(); 138144519Sdavidxu 139144519Sdavidxu ta = malloc(sizeof(td_thragent_t)); 140144519Sdavidxu if (ta == NULL) 141144519Sdavidxu return (TD_MALLOC); 142144519Sdavidxu 143144519Sdavidxu ta->ph = ph; 144144519Sdavidxu 145144519Sdavidxu LOOKUP_SYM(ph, "_libthr_debug", &ta->libthr_debug_addr); 146144519Sdavidxu LOOKUP_SYM(ph, "_thread_list", &ta->thread_list_addr); 147144519Sdavidxu LOOKUP_SYM(ph, "_thread_active_threads",&ta->thread_active_threads_addr); 148144519Sdavidxu LOOKUP_SYM(ph, "_thread_keytable", &ta->thread_keytable_addr); 149144922Sdavidxu LOOKUP_SYM(ph, "_thread_last_event", &ta->thread_last_event_addr); 150144922Sdavidxu LOOKUP_SYM(ph, "_thread_event_mask", &ta->thread_event_mask_addr); 151144922Sdavidxu LOOKUP_SYM(ph, "_thread_bp_create", &ta->thread_bp_create_addr); 152144922Sdavidxu LOOKUP_SYM(ph, "_thread_bp_death", &ta->thread_bp_death_addr); 153144519Sdavidxu LOOKUP_VAL(ph, "_thread_off_dtv", &ta->thread_off_dtv); 154144519Sdavidxu LOOKUP_VAL(ph, "_thread_off_tlsindex", &ta->thread_off_tlsindex); 155144519Sdavidxu LOOKUP_VAL(ph, "_thread_off_attr_flags", &ta->thread_off_attr_flags); 156144519Sdavidxu LOOKUP_VAL(ph, "_thread_size_key", &ta->thread_size_key); 157144519Sdavidxu LOOKUP_VAL(ph, "_thread_off_tcb", &ta->thread_off_tcb); 158144519Sdavidxu LOOKUP_VAL(ph, "_thread_off_tid", &ta->thread_off_tid); 159144519Sdavidxu LOOKUP_VAL(ph, "_thread_off_linkmap", &ta->thread_off_linkmap); 160144519Sdavidxu LOOKUP_VAL(ph, "_thread_off_next", &ta->thread_off_next); 161144519Sdavidxu LOOKUP_VAL(ph, "_thread_off_state", &ta->thread_off_state); 162144519Sdavidxu LOOKUP_VAL(ph, "_thread_max_keys", &ta->thread_max_keys); 163144519Sdavidxu LOOKUP_VAL(ph, "_thread_off_key_allocated", &ta->thread_off_key_allocated); 164144519Sdavidxu LOOKUP_VAL(ph, "_thread_off_key_destructor", &ta->thread_off_key_destructor); 165144519Sdavidxu LOOKUP_VAL(ph, "_thread_state_running", &ta->thread_state_running); 166144519Sdavidxu LOOKUP_VAL(ph, "_thread_state_zoombie", &ta->thread_state_zoombie); 167144922Sdavidxu LOOKUP_VAL(ph, "_thread_off_report_events", &ta->thread_off_report_events); 168144922Sdavidxu LOOKUP_VAL(ph, "_thread_off_event_mask", &ta->thread_off_event_mask); 169144922Sdavidxu LOOKUP_VAL(ph, "_thread_off_event_buf", &ta->thread_off_event_buf); 170144519Sdavidxu dbg = getpid(); 171144519Sdavidxu /* 172144519Sdavidxu * If this fails it probably means we're debugging a core file and 173144519Sdavidxu * can't write to it. 174144519Sdavidxu */ 175144519Sdavidxu ps_pwrite(ph, ta->libthr_debug_addr, &dbg, sizeof(int)); 176144519Sdavidxu *pta = ta; 177144519Sdavidxu return (0); 178144519Sdavidxu 179144519Sdavidxuerror: 180132332Smarcel free(ta); 181144519Sdavidxu return (ret); 182132332Smarcel} 183132332Smarcel 184132332Smarcelstatic td_err_e 185144519Sdavidxupt_ta_delete(td_thragent_t *ta) 186132332Smarcel{ 187144519Sdavidxu int dbg; 188144519Sdavidxu 189144519Sdavidxu TDBG_FUNC(); 190144519Sdavidxu 191144519Sdavidxu dbg = 0; 192144519Sdavidxu /* 193144519Sdavidxu * Error returns from this write are not really a problem; 194144519Sdavidxu * the process doesn't exist any more. 195144519Sdavidxu */ 196144519Sdavidxu ps_pwrite(ta->ph, ta->libthr_debug_addr, &dbg, sizeof(int)); 197144519Sdavidxu free(ta); 198144519Sdavidxu return (TD_OK); 199132332Smarcel} 200132332Smarcel 201132332Smarcelstatic td_err_e 202144519Sdavidxupt_ta_map_id2thr(const td_thragent_t *ta, thread_t id, td_thrhandle_t *th) 203132332Smarcel{ 204144519Sdavidxu psaddr_t pt; 205224693Smarius int64_t lwp; 206144922Sdavidxu int ret; 207144519Sdavidxu 208144519Sdavidxu TDBG_FUNC(); 209144519Sdavidxu 210144989Sdavidxu if (id == 0) 211144519Sdavidxu return (TD_NOTHR); 212183021Smarcel ret = thr_pread_ptr(ta, ta->thread_list_addr, &pt); 213144519Sdavidxu if (ret != 0) 214183021Smarcel return (TD_ERR); 215144989Sdavidxu /* Iterate through thread list to find pthread */ 216180982Smarcel while (pt != 0) { 217224683Smarius ret = thr_pread_long(ta, pt + ta->thread_off_tid, &lwp); 218144519Sdavidxu if (ret != 0) 219183021Smarcel return (TD_ERR); 220144989Sdavidxu if (lwp == id) 221144519Sdavidxu break; 222144519Sdavidxu /* get next thread */ 223183021Smarcel ret = thr_pread_ptr(ta, pt + ta->thread_off_next, &pt); 224144519Sdavidxu if (ret != 0) 225183021Smarcel return (TD_ERR); 226133631Sdavidxu } 227180982Smarcel if (pt == 0) 228144519Sdavidxu return (TD_NOTHR); 229144989Sdavidxu th->th_ta = ta; 230144989Sdavidxu th->th_tid = id; 231144663Sdavidxu th->th_thread = pt; 232144519Sdavidxu return (TD_OK); 233132332Smarcel} 234132332Smarcel 235132332Smarcelstatic td_err_e 236144989Sdavidxupt_ta_map_lwp2thr(const td_thragent_t *ta, lwpid_t lwp, td_thrhandle_t *th) 237144989Sdavidxu{ 238144989Sdavidxu return (pt_ta_map_id2thr(ta, lwp, th)); 239144989Sdavidxu} 240144989Sdavidxu 241144989Sdavidxustatic td_err_e 242181341Smarcelpt_ta_thr_iter(const td_thragent_t *ta, td_thr_iter_f *callback, 243181341Smarcel void *cbdata_p, td_thr_state_e state __unused, int ti_pri __unused, 244181341Smarcel sigset_t *ti_sigmask_p __unused, unsigned int ti_user_flags __unused) 245132332Smarcel{ 246144519Sdavidxu td_thrhandle_t th; 247144519Sdavidxu psaddr_t pt; 248224693Smarius int64_t lwp; 249144989Sdavidxu int ret; 250132332Smarcel 251144519Sdavidxu TDBG_FUNC(); 252132332Smarcel 253183021Smarcel ret = thr_pread_ptr(ta, ta->thread_list_addr, &pt); 254144519Sdavidxu if (ret != 0) 255183021Smarcel return (TD_ERR); 256144519Sdavidxu while (pt != 0) { 257224683Smarius ret = thr_pread_long(ta, pt + ta->thread_off_tid, &lwp); 258144519Sdavidxu if (ret != 0) 259183021Smarcel return (TD_ERR); 260144989Sdavidxu if (lwp != 0 && lwp != TERMINATED) { 261144989Sdavidxu th.th_ta = ta; 262144989Sdavidxu th.th_tid = (thread_t)lwp; 263144922Sdavidxu th.th_thread = pt; 264144922Sdavidxu if ((*callback)(&th, cbdata_p)) 265144922Sdavidxu return (TD_DBERR); 266133631Sdavidxu } 267144519Sdavidxu /* get next thread */ 268183021Smarcel ret = thr_pread_ptr(ta, pt + ta->thread_off_next, &pt); 269144519Sdavidxu if (ret != 0) 270183021Smarcel return (TD_ERR); 271132332Smarcel } 272144519Sdavidxu return (TD_OK); 273132332Smarcel} 274132332Smarcel 275132332Smarcelstatic td_err_e 276144519Sdavidxupt_ta_tsd_iter(const td_thragent_t *ta, td_key_iter_f *ki, void *arg) 277132332Smarcel{ 278181341Smarcel void *keytable; 279144519Sdavidxu void *destructor; 280144519Sdavidxu int i, ret, allocated; 281132332Smarcel 282144519Sdavidxu TDBG_FUNC(); 283132332Smarcel 284144519Sdavidxu keytable = malloc(ta->thread_max_keys * ta->thread_size_key); 285144519Sdavidxu if (keytable == NULL) 286132332Smarcel return (TD_MALLOC); 287144519Sdavidxu ret = ps_pread(ta->ph, (psaddr_t)ta->thread_keytable_addr, keytable, 288144519Sdavidxu ta->thread_max_keys * ta->thread_size_key); 289144519Sdavidxu if (ret != 0) { 290144519Sdavidxu free(keytable); 291144519Sdavidxu return (P2T(ret)); 292144989Sdavidxu } 293144519Sdavidxu for (i = 0; i < ta->thread_max_keys; i++) { 294181341Smarcel allocated = *(int *)(void *)((uintptr_t)keytable + 295181341Smarcel i * ta->thread_size_key + ta->thread_off_key_allocated); 296181341Smarcel destructor = *(void **)(void *)((uintptr_t)keytable + 297181341Smarcel i * ta->thread_size_key + ta->thread_off_key_destructor); 298144519Sdavidxu if (allocated) { 299144519Sdavidxu ret = (ki)(i, destructor, arg); 300144519Sdavidxu if (ret != 0) { 301144519Sdavidxu free(keytable); 302144519Sdavidxu return (TD_DBERR); 303144519Sdavidxu } 304144519Sdavidxu } 305144519Sdavidxu } 306144519Sdavidxu free(keytable); 307144519Sdavidxu return (TD_OK); 308144519Sdavidxu} 309132332Smarcel 310144519Sdavidxustatic td_err_e 311144519Sdavidxupt_ta_event_addr(const td_thragent_t *ta, td_event_e event, td_notify_t *ptr) 312144519Sdavidxu{ 313144989Sdavidxu 314144519Sdavidxu TDBG_FUNC(); 315144922Sdavidxu 316144922Sdavidxu switch (event) { 317144922Sdavidxu case TD_CREATE: 318144922Sdavidxu ptr->type = NOTIFY_BPT; 319144922Sdavidxu ptr->u.bptaddr = ta->thread_bp_create_addr; 320144922Sdavidxu return (0); 321144922Sdavidxu case TD_DEATH: 322144922Sdavidxu ptr->type = NOTIFY_BPT; 323144922Sdavidxu ptr->u.bptaddr = ta->thread_bp_death_addr; 324144922Sdavidxu return (0); 325144922Sdavidxu default: 326144922Sdavidxu return (TD_ERR); 327144922Sdavidxu } 328144519Sdavidxu} 329132332Smarcel 330144519Sdavidxustatic td_err_e 331144519Sdavidxupt_ta_set_event(const td_thragent_t *ta, td_thr_events_t *events) 332144519Sdavidxu{ 333144989Sdavidxu td_thr_events_t mask; 334144922Sdavidxu int ret; 335144922Sdavidxu 336144519Sdavidxu TDBG_FUNC(); 337144922Sdavidxu ret = ps_pread(ta->ph, ta->thread_event_mask_addr, &mask, 338144922Sdavidxu sizeof(mask)); 339144922Sdavidxu if (ret != 0) 340144922Sdavidxu return (P2T(ret)); 341144922Sdavidxu mask |= *events; 342144922Sdavidxu ret = ps_pwrite(ta->ph, ta->thread_event_mask_addr, &mask, 343144922Sdavidxu sizeof(mask)); 344144922Sdavidxu return (P2T(ret)); 345132332Smarcel} 346132332Smarcel 347132332Smarcelstatic td_err_e 348144519Sdavidxupt_ta_clear_event(const td_thragent_t *ta, td_thr_events_t *events) 349132332Smarcel{ 350144989Sdavidxu td_thr_events_t mask; 351144922Sdavidxu int ret; 352144922Sdavidxu 353144519Sdavidxu TDBG_FUNC(); 354144922Sdavidxu ret = ps_pread(ta->ph, ta->thread_event_mask_addr, &mask, 355144922Sdavidxu sizeof(mask)); 356144922Sdavidxu if (ret != 0) 357144922Sdavidxu return (P2T(ret)); 358144922Sdavidxu mask &= ~*events; 359144922Sdavidxu ret = ps_pwrite(ta->ph, ta->thread_event_mask_addr, &mask, 360144922Sdavidxu sizeof(mask)); 361144922Sdavidxu return (P2T(ret)); 362132332Smarcel} 363132332Smarcel 364132332Smarcelstatic td_err_e 365144519Sdavidxupt_ta_event_getmsg(const td_thragent_t *ta, td_event_msg_t *msg) 366132332Smarcel{ 367144922Sdavidxu static td_thrhandle_t handle; 368144922Sdavidxu 369183021Smarcel psaddr_t pt; 370144989Sdavidxu td_thr_events_e tmp; 371224693Smarius int64_t lwp; 372144922Sdavidxu int ret; 373144922Sdavidxu 374144519Sdavidxu TDBG_FUNC(); 375144922Sdavidxu 376183021Smarcel ret = thr_pread_ptr(ta, ta->thread_last_event_addr, &pt); 377144922Sdavidxu if (ret != 0) 378183021Smarcel return (TD_ERR); 379180982Smarcel if (pt == 0) 380144922Sdavidxu return (TD_NOMSG); 381144989Sdavidxu /* 382144989Sdavidxu * Take the event pointer, at the time, libthr only reports event 383144989Sdavidxu * once a time, so it is not a link list. 384144989Sdavidxu */ 385183021Smarcel thr_pwrite_ptr(ta, ta->thread_last_event_addr, 0); 386144922Sdavidxu 387144989Sdavidxu /* Read event info */ 388144922Sdavidxu ret = ps_pread(ta->ph, pt + ta->thread_off_event_buf, msg, sizeof(*msg)); 389144922Sdavidxu if (ret != 0) 390144922Sdavidxu return (P2T(ret)); 391144922Sdavidxu if (msg->event == 0) 392144922Sdavidxu return (TD_NOMSG); 393144989Sdavidxu /* Clear event */ 394144922Sdavidxu tmp = 0; 395144922Sdavidxu ps_pwrite(ta->ph, pt + ta->thread_off_event_buf, &tmp, sizeof(tmp)); 396144989Sdavidxu /* Convert event */ 397183021Smarcel pt = msg->th_p; 398224683Smarius ret = thr_pread_long(ta, pt + ta->thread_off_tid, &lwp); 399144922Sdavidxu if (ret != 0) 400183021Smarcel return (TD_ERR); 401144922Sdavidxu handle.th_ta = ta; 402144989Sdavidxu handle.th_tid = lwp; 403144922Sdavidxu handle.th_thread = pt; 404183021Smarcel msg->th_p = (uintptr_t)&handle; 405144922Sdavidxu return (0); 406144519Sdavidxu} 407132332Smarcel 408144519Sdavidxustatic td_err_e 409144519Sdavidxupt_dbsuspend(const td_thrhandle_t *th, int suspend) 410144519Sdavidxu{ 411181341Smarcel const td_thragent_t *ta = th->th_ta; 412144519Sdavidxu int ret; 413132332Smarcel 414144519Sdavidxu TDBG_FUNC(); 415144519Sdavidxu 416144519Sdavidxu ret = pt_validate(th); 417144519Sdavidxu if (ret) 418144519Sdavidxu return (ret); 419144519Sdavidxu 420144519Sdavidxu if (suspend) 421144989Sdavidxu ret = ps_lstop(ta->ph, th->th_tid); 422144519Sdavidxu else 423144989Sdavidxu ret = ps_lcontinue(ta->ph, th->th_tid); 424144519Sdavidxu return (P2T(ret)); 425132332Smarcel} 426132332Smarcel 427132332Smarcelstatic td_err_e 428144519Sdavidxupt_thr_dbresume(const td_thrhandle_t *th) 429132332Smarcel{ 430144519Sdavidxu TDBG_FUNC(); 431144519Sdavidxu 432144519Sdavidxu return pt_dbsuspend(th, 0); 433132332Smarcel} 434132332Smarcel 435132332Smarcelstatic td_err_e 436144519Sdavidxupt_thr_dbsuspend(const td_thrhandle_t *th) 437133631Sdavidxu{ 438144519Sdavidxu TDBG_FUNC(); 439133631Sdavidxu 440144519Sdavidxu return pt_dbsuspend(th, 1); 441133631Sdavidxu} 442133631Sdavidxu 443133631Sdavidxustatic td_err_e 444144519Sdavidxupt_thr_validate(const td_thrhandle_t *th) 445133631Sdavidxu{ 446144519Sdavidxu td_thrhandle_t temp; 447144519Sdavidxu int ret; 448133631Sdavidxu 449144519Sdavidxu TDBG_FUNC(); 450144519Sdavidxu 451144989Sdavidxu ret = pt_ta_map_id2thr(th->th_ta, th->th_tid, &temp); 452144519Sdavidxu return (ret); 453133631Sdavidxu} 454133631Sdavidxu 455133631Sdavidxustatic td_err_e 456209689Skibpt_thr_get_info_common(const td_thrhandle_t *th, td_thrinfo_t *info, int old) 457132332Smarcel{ 458144519Sdavidxu const td_thragent_t *ta = th->th_ta; 459155414Sdavidxu struct ptrace_lwpinfo linfo; 460193826Sdes int traceme; 461144519Sdavidxu int state; 462144519Sdavidxu int ret; 463144519Sdavidxu 464144519Sdavidxu TDBG_FUNC(); 465144519Sdavidxu 466155387Sdavidxu bzero(info, sizeof(*info)); 467144519Sdavidxu ret = pt_validate(th); 468144519Sdavidxu if (ret) 469144519Sdavidxu return (ret); 470183021Smarcel ret = thr_pread_int(ta, th->th_thread + ta->thread_off_state, &state); 471144519Sdavidxu if (ret != 0) 472183021Smarcel return (TD_ERR); 473183021Smarcel ret = thr_pread_int(ta, th->th_thread + ta->thread_off_report_events, 474193826Sdes &traceme); 475193826Sdes info->ti_traceme = traceme; 476144974Sdavidxu if (ret != 0) 477183021Smarcel return (TD_ERR); 478144989Sdavidxu ret = ps_pread(ta->ph, th->th_thread + ta->thread_off_event_mask, 479144974Sdavidxu &info->ti_events, sizeof(td_thr_events_t)); 480144974Sdavidxu if (ret != 0) 481144974Sdavidxu return (P2T(ret)); 482144989Sdavidxu ret = ps_pread(ta->ph, th->th_thread + ta->thread_off_tcb, 483144989Sdavidxu &info->ti_tls, sizeof(void *)); 484144989Sdavidxu info->ti_lid = th->th_tid; 485144519Sdavidxu info->ti_tid = th->th_tid; 486144989Sdavidxu info->ti_thread = th->th_thread; 487144519Sdavidxu info->ti_ta_p = th->th_ta; 488155414Sdavidxu ret = ps_linfo(ta->ph, th->th_tid, &linfo); 489155414Sdavidxu if (ret == PS_OK) { 490155414Sdavidxu info->ti_sigmask = linfo.pl_sigmask; 491155414Sdavidxu info->ti_pending = linfo.pl_siglist; 492209689Skib if (!old) { 493209689Skib if ((linfo.pl_flags & PL_FLAG_SI) != 0) 494209689Skib info->ti_siginfo = linfo.pl_siginfo; 495209689Skib else 496209689Skib bzero(&info->ti_siginfo, 497209689Skib sizeof(info->ti_siginfo)); 498209689Skib } 499158681Sdavidxu } else 500158681Sdavidxu return (ret); 501144519Sdavidxu if (state == ta->thread_state_running) 502144519Sdavidxu info->ti_state = TD_THR_RUN; 503144519Sdavidxu else if (state == ta->thread_state_zoombie) 504144519Sdavidxu info->ti_state = TD_THR_ZOMBIE; 505144519Sdavidxu else 506144519Sdavidxu info->ti_state = TD_THR_SLEEP; 507144519Sdavidxu info->ti_type = TD_THR_USER; 508144519Sdavidxu return (0); 509132332Smarcel} 510132332Smarcel 511209689Skibstatic td_err_e 512209689Skibpt_thr_old_get_info(const td_thrhandle_t *th, td_old_thrinfo_t *info) 513209689Skib{ 514209689Skib 515209689Skib return (pt_thr_get_info_common(th, (td_thrinfo_t *)info, 1)); 516209689Skib} 517209689Skib 518209689Skibstatic td_err_e 519209689Skibpt_thr_get_info(const td_thrhandle_t *th, td_thrinfo_t *info) 520209689Skib{ 521209689Skib 522209689Skib return (pt_thr_get_info_common(th, info, 0)); 523209689Skib} 524209689Skib 525146818Sdfr#ifdef __i386__ 526132332Smarcelstatic td_err_e 527146818Sdfrpt_thr_getxmmregs(const td_thrhandle_t *th, char *fxsave) 528146818Sdfr{ 529146818Sdfr const td_thragent_t *ta = th->th_ta; 530146818Sdfr int ret; 531146818Sdfr 532146818Sdfr TDBG_FUNC(); 533146818Sdfr 534146818Sdfr ret = pt_validate(th); 535146818Sdfr if (ret) 536146818Sdfr return (ret); 537146818Sdfr 538146818Sdfr ret = ps_lgetxmmregs(ta->ph, th->th_tid, fxsave); 539146818Sdfr return (P2T(ret)); 540146818Sdfr} 541146818Sdfr#endif 542146818Sdfr 543146818Sdfrstatic td_err_e 544144519Sdavidxupt_thr_getfpregs(const td_thrhandle_t *th, prfpregset_t *fpregs) 545132332Smarcel{ 546144519Sdavidxu const td_thragent_t *ta = th->th_ta; 547144519Sdavidxu int ret; 548144519Sdavidxu 549144519Sdavidxu TDBG_FUNC(); 550144519Sdavidxu 551144519Sdavidxu ret = pt_validate(th); 552144519Sdavidxu if (ret) 553144519Sdavidxu return (ret); 554144519Sdavidxu 555144989Sdavidxu ret = ps_lgetfpregs(ta->ph, th->th_tid, fpregs); 556144519Sdavidxu return (P2T(ret)); 557132332Smarcel} 558132332Smarcel 559132332Smarcelstatic td_err_e 560144519Sdavidxupt_thr_getgregs(const td_thrhandle_t *th, prgregset_t gregs) 561132332Smarcel{ 562144519Sdavidxu const td_thragent_t *ta = th->th_ta; 563144519Sdavidxu int ret; 564132332Smarcel 565144519Sdavidxu TDBG_FUNC(); 566144519Sdavidxu 567144519Sdavidxu ret = pt_validate(th); 568144519Sdavidxu if (ret) 569144519Sdavidxu return (ret); 570144519Sdavidxu 571144989Sdavidxu ret = ps_lgetregs(ta->ph, th->th_tid, gregs); 572144519Sdavidxu return (P2T(ret)); 573132332Smarcel} 574132332Smarcel 575146818Sdfr#ifdef __i386__ 576132332Smarcelstatic td_err_e 577146818Sdfrpt_thr_setxmmregs(const td_thrhandle_t *th, const char *fxsave) 578146818Sdfr{ 579146818Sdfr const td_thragent_t *ta = th->th_ta; 580146818Sdfr int ret; 581146818Sdfr 582146818Sdfr TDBG_FUNC(); 583146818Sdfr 584146818Sdfr ret = pt_validate(th); 585146818Sdfr if (ret) 586146818Sdfr return (ret); 587146818Sdfr 588146818Sdfr ret = ps_lsetxmmregs(ta->ph, th->th_tid, fxsave); 589146818Sdfr return (P2T(ret)); 590146818Sdfr} 591146818Sdfr#endif 592146818Sdfr 593146818Sdfrstatic td_err_e 594144519Sdavidxupt_thr_setfpregs(const td_thrhandle_t *th, const prfpregset_t *fpregs) 595132332Smarcel{ 596144519Sdavidxu const td_thragent_t *ta = th->th_ta; 597144519Sdavidxu int ret; 598132332Smarcel 599144519Sdavidxu TDBG_FUNC(); 600144519Sdavidxu 601144519Sdavidxu ret = pt_validate(th); 602144519Sdavidxu if (ret) 603144519Sdavidxu return (ret); 604144519Sdavidxu 605144989Sdavidxu ret = ps_lsetfpregs(ta->ph, th->th_tid, fpregs); 606144519Sdavidxu return (P2T(ret)); 607132332Smarcel} 608132332Smarcel 609132332Smarcelstatic td_err_e 610144519Sdavidxupt_thr_setgregs(const td_thrhandle_t *th, const prgregset_t gregs) 611132332Smarcel{ 612144519Sdavidxu const td_thragent_t *ta = th->th_ta; 613144519Sdavidxu int ret; 614132332Smarcel 615144519Sdavidxu TDBG_FUNC(); 616144519Sdavidxu 617144519Sdavidxu ret = pt_validate(th); 618144519Sdavidxu if (ret) 619144519Sdavidxu return (ret); 620144519Sdavidxu 621144989Sdavidxu ret = ps_lsetregs(ta->ph, th->th_tid, gregs); 622144519Sdavidxu return (P2T(ret)); 623132332Smarcel} 624132332Smarcel 625132332Smarcelstatic td_err_e 626144519Sdavidxupt_thr_event_enable(const td_thrhandle_t *th, int en) 627132332Smarcel{ 628144922Sdavidxu const td_thragent_t *ta = th->th_ta; 629144922Sdavidxu int ret; 630144922Sdavidxu 631144519Sdavidxu TDBG_FUNC(); 632144922Sdavidxu ret = ps_pwrite(ta->ph, th->th_thread + ta->thread_off_report_events, 633144922Sdavidxu &en, sizeof(int)); 634144922Sdavidxu return (P2T(ret)); 635132332Smarcel} 636132332Smarcel 637132332Smarcelstatic td_err_e 638144519Sdavidxupt_thr_set_event(const td_thrhandle_t *th, td_thr_events_t *setp) 639132332Smarcel{ 640144922Sdavidxu const td_thragent_t *ta = th->th_ta; 641144922Sdavidxu td_thr_events_t mask; 642144922Sdavidxu int ret; 643144922Sdavidxu 644144519Sdavidxu TDBG_FUNC(); 645144922Sdavidxu ret = ps_pread(ta->ph, th->th_thread + ta->thread_off_event_mask, 646144922Sdavidxu &mask, sizeof(mask)); 647144922Sdavidxu mask |= *setp; 648144922Sdavidxu ret = ps_pwrite(ta->ph, th->th_thread + ta->thread_off_event_mask, 649144922Sdavidxu &mask, sizeof(mask)); 650144922Sdavidxu return (P2T(ret)); 651144519Sdavidxu} 652133631Sdavidxu 653144519Sdavidxustatic td_err_e 654144519Sdavidxupt_thr_clear_event(const td_thrhandle_t *th, td_thr_events_t *setp) 655144519Sdavidxu{ 656144922Sdavidxu const td_thragent_t *ta = th->th_ta; 657144922Sdavidxu td_thr_events_t mask; 658144922Sdavidxu int ret; 659144922Sdavidxu 660144519Sdavidxu TDBG_FUNC(); 661144922Sdavidxu ret = ps_pread(ta->ph, th->th_thread + ta->thread_off_event_mask, 662144922Sdavidxu &mask, sizeof(mask)); 663144922Sdavidxu mask &= ~*setp; 664144922Sdavidxu ret = ps_pwrite(ta->ph, th->th_thread + ta->thread_off_event_mask, 665144922Sdavidxu &mask, sizeof(mask)); 666144922Sdavidxu return (P2T(ret)); 667132332Smarcel} 668132332Smarcel 669132332Smarcelstatic td_err_e 670144519Sdavidxupt_thr_event_getmsg(const td_thrhandle_t *th, td_event_msg_t *msg) 671132332Smarcel{ 672144922Sdavidxu static td_thrhandle_t handle; 673181341Smarcel const td_thragent_t *ta = th->th_ta; 674144922Sdavidxu psaddr_t pt, pt_temp; 675224693Smarius int64_t lwp; 676144922Sdavidxu int ret; 677144922Sdavidxu td_thr_events_e tmp; 678144922Sdavidxu 679144519Sdavidxu TDBG_FUNC(); 680144922Sdavidxu pt = th->th_thread; 681183021Smarcel ret = thr_pread_ptr(ta, ta->thread_last_event_addr, &pt_temp); 682144922Sdavidxu if (ret != 0) 683183021Smarcel return (TD_ERR); 684144989Sdavidxu /* Get event */ 685144922Sdavidxu ret = ps_pread(ta->ph, pt + ta->thread_off_event_buf, msg, sizeof(*msg)); 686144922Sdavidxu if (ret != 0) 687144922Sdavidxu return (P2T(ret)); 688144922Sdavidxu if (msg->event == 0) 689144922Sdavidxu return (TD_NOMSG); 690144989Sdavidxu /* 691144989Sdavidxu * Take the event pointer, at the time, libthr only reports event 692144989Sdavidxu * once a time, so it is not a link list. 693144989Sdavidxu */ 694183021Smarcel if (pt == pt_temp) 695183021Smarcel thr_pwrite_ptr(ta, ta->thread_last_event_addr, 0); 696183021Smarcel 697144989Sdavidxu /* Clear event */ 698144922Sdavidxu tmp = 0; 699144922Sdavidxu ps_pwrite(ta->ph, pt + ta->thread_off_event_buf, &tmp, sizeof(tmp)); 700144989Sdavidxu /* Convert event */ 701183021Smarcel pt = msg->th_p; 702224683Smarius ret = thr_pread_long(ta, pt + ta->thread_off_tid, &lwp); 703144922Sdavidxu if (ret != 0) 704183021Smarcel return (TD_ERR); 705144922Sdavidxu handle.th_ta = ta; 706144989Sdavidxu handle.th_tid = lwp; 707144922Sdavidxu handle.th_thread = pt; 708183021Smarcel msg->th_p = (uintptr_t)&handle; 709144922Sdavidxu return (0); 710132332Smarcel} 711132332Smarcel 712132332Smarcelstatic td_err_e 713181341Smarcelpt_thr_sstep(const td_thrhandle_t *th, int step __unused) 714132332Smarcel{ 715144519Sdavidxu TDBG_FUNC(); 716144519Sdavidxu 717144989Sdavidxu return pt_validate(th); 718132332Smarcel} 719132332Smarcel 720144519Sdavidxustatic int 721144519Sdavidxupt_validate(const td_thrhandle_t *th) 722144519Sdavidxu{ 723144519Sdavidxu 724180982Smarcel if (th->th_tid == 0 || th->th_thread == 0) 725144989Sdavidxu return (TD_ERR); 726144519Sdavidxu return (TD_OK); 727144519Sdavidxu} 728144519Sdavidxu 729133631Sdavidxustatic td_err_e 730180982Smarcelpt_thr_tls_get_addr(const td_thrhandle_t *th, psaddr_t _linkmap, size_t offset, 731180982Smarcel psaddr_t *address) 732133631Sdavidxu{ 733144519Sdavidxu const td_thragent_t *ta = th->th_ta; 734180982Smarcel psaddr_t dtv_addr, obj_entry, tcb_addr; 735144519Sdavidxu int tls_index, ret; 736144519Sdavidxu 737144519Sdavidxu /* linkmap is a member of Obj_Entry */ 738180982Smarcel obj_entry = _linkmap - ta->thread_off_linkmap; 739144519Sdavidxu 740144519Sdavidxu /* get tlsindex of the object file */ 741144519Sdavidxu ret = ps_pread(ta->ph, 742144519Sdavidxu obj_entry + ta->thread_off_tlsindex, 743144519Sdavidxu &tls_index, sizeof(tls_index)); 744144519Sdavidxu if (ret != 0) 745144519Sdavidxu return (P2T(ret)); 746144519Sdavidxu 747144519Sdavidxu /* get thread tcb */ 748144989Sdavidxu ret = ps_pread(ta->ph, th->th_thread + ta->thread_off_tcb, 749144519Sdavidxu &tcb_addr, sizeof(tcb_addr)); 750144519Sdavidxu if (ret != 0) 751144519Sdavidxu return (P2T(ret)); 752144519Sdavidxu 753144519Sdavidxu /* get dtv array address */ 754144519Sdavidxu ret = ps_pread(ta->ph, tcb_addr + ta->thread_off_dtv, 755144519Sdavidxu &dtv_addr, sizeof(dtv_addr)); 756144519Sdavidxu if (ret != 0) 757144519Sdavidxu return (P2T(ret)); 758144519Sdavidxu /* now get the object's tls block base address */ 759180982Smarcel ret = ps_pread(ta->ph, dtv_addr + sizeof(void *) * (tls_index+1), 760180982Smarcel address, sizeof(*address)); 761144519Sdavidxu if (ret != 0) 762144519Sdavidxu return (P2T(ret)); 763144519Sdavidxu 764144519Sdavidxu *address += offset; 765133631Sdavidxu return (TD_OK); 766133631Sdavidxu} 767133631Sdavidxu 768241720Sedstatic struct ta_ops libthr_db_ops = { 769144519Sdavidxu .to_init = pt_init, 770144519Sdavidxu .to_ta_clear_event = pt_ta_clear_event, 771144519Sdavidxu .to_ta_delete = pt_ta_delete, 772144519Sdavidxu .to_ta_event_addr = pt_ta_event_addr, 773144519Sdavidxu .to_ta_event_getmsg = pt_ta_event_getmsg, 774144519Sdavidxu .to_ta_map_id2thr = pt_ta_map_id2thr, 775144519Sdavidxu .to_ta_map_lwp2thr = pt_ta_map_lwp2thr, 776144519Sdavidxu .to_ta_new = pt_ta_new, 777144519Sdavidxu .to_ta_set_event = pt_ta_set_event, 778144519Sdavidxu .to_ta_thr_iter = pt_ta_thr_iter, 779144519Sdavidxu .to_ta_tsd_iter = pt_ta_tsd_iter, 780144519Sdavidxu .to_thr_clear_event = pt_thr_clear_event, 781144519Sdavidxu .to_thr_dbresume = pt_thr_dbresume, 782144519Sdavidxu .to_thr_dbsuspend = pt_thr_dbsuspend, 783144519Sdavidxu .to_thr_event_enable = pt_thr_event_enable, 784144519Sdavidxu .to_thr_event_getmsg = pt_thr_event_getmsg, 785209689Skib .to_thr_old_get_info = pt_thr_old_get_info, 786144519Sdavidxu .to_thr_get_info = pt_thr_get_info, 787144519Sdavidxu .to_thr_getfpregs = pt_thr_getfpregs, 788144519Sdavidxu .to_thr_getgregs = pt_thr_getgregs, 789144519Sdavidxu .to_thr_set_event = pt_thr_set_event, 790144519Sdavidxu .to_thr_setfpregs = pt_thr_setfpregs, 791144519Sdavidxu .to_thr_setgregs = pt_thr_setgregs, 792144519Sdavidxu .to_thr_validate = pt_thr_validate, 793144519Sdavidxu .to_thr_tls_get_addr = pt_thr_tls_get_addr, 794132332Smarcel 795133631Sdavidxu /* FreeBSD specific extensions. */ 796144519Sdavidxu .to_thr_sstep = pt_thr_sstep, 797146818Sdfr#ifdef __i386__ 798146818Sdfr .to_thr_getxmmregs = pt_thr_getxmmregs, 799146818Sdfr .to_thr_setxmmregs = pt_thr_setxmmregs, 800146818Sdfr#endif 801132332Smarcel}; 802177490Sdavidxu 803177490SdavidxuDATA_SET(__ta_ops, libthr_db_ops); 804