libthr_db.c revision 155414
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: head/lib/libthread_db/libthr_db.c 155414 2006-02-07 02:55:34Z davidxu $"); 30132332Smarcel 31132332Smarcel#include <proc_service.h> 32144519Sdavidxu#include <stddef.h> 33132332Smarcel#include <stdlib.h> 34144519Sdavidxu#include <string.h> 35144519Sdavidxu#include <sys/types.h> 36144519Sdavidxu#include <sys/ptrace.h> 37132332Smarcel#include <thread_db.h> 38144519Sdavidxu#include <unistd.h> 39132332Smarcel 40132332Smarcel#include "thread_db_int.h" 41132332Smarcel 42144922Sdavidxu#define TERMINATED 1 43144922Sdavidxu 44132332Smarcelstruct td_thragent { 45132332Smarcel TD_THRAGENT_FIELDS; 46144519Sdavidxu psaddr_t libthr_debug_addr; 47144519Sdavidxu psaddr_t thread_list_addr; 48144519Sdavidxu psaddr_t thread_active_threads_addr; 49144519Sdavidxu psaddr_t thread_keytable_addr; 50144922Sdavidxu psaddr_t thread_last_event_addr; 51144922Sdavidxu psaddr_t thread_event_mask_addr; 52144922Sdavidxu psaddr_t thread_bp_create_addr; 53144922Sdavidxu psaddr_t thread_bp_death_addr; 54144519Sdavidxu int thread_off_dtv; 55144519Sdavidxu int thread_off_tlsindex; 56144519Sdavidxu int thread_off_attr_flags; 57144519Sdavidxu int thread_size_key; 58144519Sdavidxu int thread_off_tcb; 59144519Sdavidxu int thread_off_linkmap; 60144519Sdavidxu int thread_off_next; 61144519Sdavidxu int thread_off_state; 62144519Sdavidxu int thread_off_tid; 63144519Sdavidxu int thread_max_keys; 64144519Sdavidxu int thread_off_key_allocated; 65144519Sdavidxu int thread_off_key_destructor; 66144922Sdavidxu int thread_off_report_events; 67144922Sdavidxu int thread_off_event_mask; 68144922Sdavidxu int thread_off_event_buf; 69144519Sdavidxu int thread_state_zoombie; 70144519Sdavidxu int thread_state_running; 71132332Smarcel}; 72132332Smarcel 73144519Sdavidxu#define P2T(c) ps2td(c) 74144519Sdavidxu 75144519Sdavidxustatic int pt_validate(const td_thrhandle_t *th); 76144519Sdavidxu 77144519Sdavidxustatic int 78144519Sdavidxups2td(int c) 79132332Smarcel{ 80144519Sdavidxu switch (c) { 81144519Sdavidxu case PS_OK: 82144519Sdavidxu return TD_OK; 83144519Sdavidxu case PS_ERR: 84144519Sdavidxu return TD_ERR; 85144519Sdavidxu case PS_BADPID: 86144519Sdavidxu return TD_BADPH; 87144519Sdavidxu case PS_BADLID: 88144519Sdavidxu return TD_NOLWP; 89144519Sdavidxu case PS_BADADDR: 90144519Sdavidxu return TD_ERR; 91144519Sdavidxu case PS_NOSYM: 92144519Sdavidxu return TD_NOLIBTHREAD; 93144519Sdavidxu case PS_NOFREGS: 94144519Sdavidxu return TD_NOFPREGS; 95144519Sdavidxu default: 96144519Sdavidxu return TD_ERR; 97144519Sdavidxu } 98132332Smarcel} 99132332Smarcel 100132332Smarcelstatic td_err_e 101144519Sdavidxupt_init(void) 102132332Smarcel{ 103144519Sdavidxu return (0); 104132332Smarcel} 105132332Smarcel 106132332Smarcelstatic td_err_e 107144519Sdavidxupt_ta_new(struct ps_prochandle *ph, td_thragent_t **pta) 108132332Smarcel{ 109144519Sdavidxu#define LOOKUP_SYM(proc, sym, addr) \ 110144519Sdavidxu ret = ps_pglobal_lookup(proc, NULL, sym, addr); \ 111144519Sdavidxu if (ret != 0) { \ 112144519Sdavidxu TDBG("can not find symbol: %s\n", sym); \ 113144519Sdavidxu ret = TD_NOLIBTHREAD; \ 114144519Sdavidxu goto error; \ 115144519Sdavidxu } 116144519Sdavidxu 117144519Sdavidxu#define LOOKUP_VAL(proc, sym, val) \ 118144519Sdavidxu ret = ps_pglobal_lookup(proc, NULL, sym, &vaddr);\ 119144519Sdavidxu if (ret != 0) { \ 120144519Sdavidxu TDBG("can not find symbol: %s\n", sym); \ 121144519Sdavidxu ret = TD_NOLIBTHREAD; \ 122144519Sdavidxu goto error; \ 123144519Sdavidxu } \ 124144519Sdavidxu ret = ps_pread(proc, vaddr, val, sizeof(int)); \ 125144519Sdavidxu if (ret != 0) { \ 126144519Sdavidxu TDBG("can not read value of %s\n", sym);\ 127144519Sdavidxu ret = TD_NOLIBTHREAD; \ 128144519Sdavidxu goto error; \ 129144519Sdavidxu } 130144519Sdavidxu 131144519Sdavidxu td_thragent_t *ta; 132144519Sdavidxu psaddr_t vaddr; 133144519Sdavidxu int dbg; 134144519Sdavidxu int ret; 135144519Sdavidxu 136144519Sdavidxu TDBG_FUNC(); 137144519Sdavidxu 138144519Sdavidxu ta = malloc(sizeof(td_thragent_t)); 139144519Sdavidxu if (ta == NULL) 140144519Sdavidxu return (TD_MALLOC); 141144519Sdavidxu 142144519Sdavidxu ta->ph = ph; 143144519Sdavidxu 144144519Sdavidxu LOOKUP_SYM(ph, "_libthr_debug", &ta->libthr_debug_addr); 145144519Sdavidxu LOOKUP_SYM(ph, "_thread_list", &ta->thread_list_addr); 146144519Sdavidxu LOOKUP_SYM(ph, "_thread_active_threads",&ta->thread_active_threads_addr); 147144519Sdavidxu LOOKUP_SYM(ph, "_thread_keytable", &ta->thread_keytable_addr); 148144922Sdavidxu LOOKUP_SYM(ph, "_thread_last_event", &ta->thread_last_event_addr); 149144922Sdavidxu LOOKUP_SYM(ph, "_thread_event_mask", &ta->thread_event_mask_addr); 150144922Sdavidxu LOOKUP_SYM(ph, "_thread_bp_create", &ta->thread_bp_create_addr); 151144922Sdavidxu LOOKUP_SYM(ph, "_thread_bp_death", &ta->thread_bp_death_addr); 152144519Sdavidxu LOOKUP_VAL(ph, "_thread_off_dtv", &ta->thread_off_dtv); 153144519Sdavidxu LOOKUP_VAL(ph, "_thread_off_tlsindex", &ta->thread_off_tlsindex); 154144519Sdavidxu LOOKUP_VAL(ph, "_thread_off_attr_flags", &ta->thread_off_attr_flags); 155144519Sdavidxu LOOKUP_VAL(ph, "_thread_size_key", &ta->thread_size_key); 156144519Sdavidxu LOOKUP_VAL(ph, "_thread_off_tcb", &ta->thread_off_tcb); 157144519Sdavidxu LOOKUP_VAL(ph, "_thread_off_tid", &ta->thread_off_tid); 158144519Sdavidxu LOOKUP_VAL(ph, "_thread_off_linkmap", &ta->thread_off_linkmap); 159144519Sdavidxu LOOKUP_VAL(ph, "_thread_off_next", &ta->thread_off_next); 160144519Sdavidxu LOOKUP_VAL(ph, "_thread_off_state", &ta->thread_off_state); 161144519Sdavidxu LOOKUP_VAL(ph, "_thread_max_keys", &ta->thread_max_keys); 162144519Sdavidxu LOOKUP_VAL(ph, "_thread_off_key_allocated", &ta->thread_off_key_allocated); 163144519Sdavidxu LOOKUP_VAL(ph, "_thread_off_key_destructor", &ta->thread_off_key_destructor); 164144519Sdavidxu LOOKUP_VAL(ph, "_thread_state_running", &ta->thread_state_running); 165144519Sdavidxu LOOKUP_VAL(ph, "_thread_state_zoombie", &ta->thread_state_zoombie); 166144922Sdavidxu LOOKUP_VAL(ph, "_thread_off_report_events", &ta->thread_off_report_events); 167144922Sdavidxu LOOKUP_VAL(ph, "_thread_off_event_mask", &ta->thread_off_event_mask); 168144922Sdavidxu LOOKUP_VAL(ph, "_thread_off_event_buf", &ta->thread_off_event_buf); 169144519Sdavidxu dbg = getpid(); 170144519Sdavidxu /* 171144519Sdavidxu * If this fails it probably means we're debugging a core file and 172144519Sdavidxu * can't write to it. 173144519Sdavidxu */ 174144519Sdavidxu ps_pwrite(ph, ta->libthr_debug_addr, &dbg, sizeof(int)); 175144519Sdavidxu *pta = ta; 176144519Sdavidxu return (0); 177144519Sdavidxu 178144519Sdavidxuerror: 179132332Smarcel free(ta); 180144519Sdavidxu return (ret); 181132332Smarcel} 182132332Smarcel 183132332Smarcelstatic td_err_e 184144519Sdavidxupt_ta_delete(td_thragent_t *ta) 185132332Smarcel{ 186144519Sdavidxu int dbg; 187144519Sdavidxu 188144519Sdavidxu TDBG_FUNC(); 189144519Sdavidxu 190144519Sdavidxu dbg = 0; 191144519Sdavidxu /* 192144519Sdavidxu * Error returns from this write are not really a problem; 193144519Sdavidxu * the process doesn't exist any more. 194144519Sdavidxu */ 195144519Sdavidxu ps_pwrite(ta->ph, ta->libthr_debug_addr, &dbg, sizeof(int)); 196144519Sdavidxu free(ta); 197144519Sdavidxu return (TD_OK); 198132332Smarcel} 199132332Smarcel 200132332Smarcelstatic td_err_e 201144519Sdavidxupt_ta_map_id2thr(const td_thragent_t *ta, thread_t id, td_thrhandle_t *th) 202132332Smarcel{ 203144519Sdavidxu TAILQ_HEAD(, pthread) thread_list; 204144519Sdavidxu psaddr_t pt; 205144989Sdavidxu long lwp; 206144922Sdavidxu int ret; 207144519Sdavidxu 208144519Sdavidxu TDBG_FUNC(); 209144519Sdavidxu 210144989Sdavidxu if (id == 0) 211144519Sdavidxu return (TD_NOTHR); 212144519Sdavidxu ret = ps_pread(ta->ph, ta->thread_list_addr, &thread_list, 213144989Sdavidxu sizeof(thread_list)); 214144519Sdavidxu if (ret != 0) 215144519Sdavidxu return (P2T(ret)); 216144989Sdavidxu /* Iterate through thread list to find pthread */ 217144519Sdavidxu pt = (psaddr_t)thread_list.tqh_first; 218144989Sdavidxu while (pt != NULL) { 219144519Sdavidxu ret = ps_pread(ta->ph, pt + ta->thread_off_tid, 220144989Sdavidxu &lwp, sizeof(lwp)); 221144519Sdavidxu if (ret != 0) 222144519Sdavidxu return (P2T(ret)); 223144989Sdavidxu if (lwp == id) 224144519Sdavidxu break; 225144519Sdavidxu /* get next thread */ 226144519Sdavidxu ret = ps_pread(ta->ph, 227144989Sdavidxu pt + ta->thread_off_next, 228144989Sdavidxu &pt, sizeof(pt)); 229144519Sdavidxu if (ret != 0) 230144519Sdavidxu return (P2T(ret)); 231133631Sdavidxu } 232144989Sdavidxu if (pt == NULL) 233144519Sdavidxu return (TD_NOTHR); 234144989Sdavidxu th->th_ta = ta; 235144989Sdavidxu th->th_tid = id; 236144663Sdavidxu th->th_thread = pt; 237144519Sdavidxu return (TD_OK); 238132332Smarcel} 239132332Smarcel 240132332Smarcelstatic td_err_e 241144989Sdavidxupt_ta_map_lwp2thr(const td_thragent_t *ta, lwpid_t lwp, td_thrhandle_t *th) 242144989Sdavidxu{ 243144989Sdavidxu return (pt_ta_map_id2thr(ta, lwp, th)); 244144989Sdavidxu} 245144989Sdavidxu 246144989Sdavidxustatic td_err_e 247144519Sdavidxupt_ta_thr_iter(const td_thragent_t *ta, 248144519Sdavidxu td_thr_iter_f *callback, void *cbdata_p, 249144519Sdavidxu td_thr_state_e state, int ti_pri, 250144519Sdavidxu sigset_t *ti_sigmask_p, 251144519Sdavidxu unsigned int ti_user_flags) 252132332Smarcel{ 253144519Sdavidxu TAILQ_HEAD(, pthread) thread_list; 254144519Sdavidxu td_thrhandle_t th; 255144519Sdavidxu psaddr_t pt; 256144989Sdavidxu long lwp; 257144989Sdavidxu int ret; 258132332Smarcel 259144519Sdavidxu TDBG_FUNC(); 260132332Smarcel 261144519Sdavidxu ret = ps_pread(ta->ph, ta->thread_list_addr, &thread_list, 262144519Sdavidxu sizeof(thread_list)); 263144519Sdavidxu if (ret != 0) 264144519Sdavidxu return (P2T(ret)); 265144519Sdavidxu pt = (psaddr_t)thread_list.tqh_first; 266144519Sdavidxu while (pt != 0) { 267144989Sdavidxu ret = ps_pread(ta->ph, pt + ta->thread_off_tid, &lwp, 268144989Sdavidxu sizeof(lwp)); 269144519Sdavidxu if (ret != 0) 270144519Sdavidxu return (P2T(ret)); 271144989Sdavidxu if (lwp != 0 && lwp != TERMINATED) { 272144989Sdavidxu th.th_ta = ta; 273144989Sdavidxu th.th_tid = (thread_t)lwp; 274144922Sdavidxu th.th_thread = pt; 275144922Sdavidxu if ((*callback)(&th, cbdata_p)) 276144922Sdavidxu return (TD_DBERR); 277133631Sdavidxu } 278144519Sdavidxu /* get next thread */ 279144519Sdavidxu ret = ps_pread(ta->ph, pt + ta->thread_off_next, &pt, 280144519Sdavidxu sizeof(pt)); 281144519Sdavidxu if (ret != 0) 282144519Sdavidxu return (P2T(ret)); 283132332Smarcel } 284144519Sdavidxu return (TD_OK); 285132332Smarcel} 286132332Smarcel 287132332Smarcelstatic td_err_e 288144519Sdavidxupt_ta_tsd_iter(const td_thragent_t *ta, td_key_iter_f *ki, void *arg) 289132332Smarcel{ 290144519Sdavidxu char *keytable; 291144519Sdavidxu void *destructor; 292144519Sdavidxu int i, ret, allocated; 293132332Smarcel 294144519Sdavidxu TDBG_FUNC(); 295132332Smarcel 296144519Sdavidxu keytable = malloc(ta->thread_max_keys * ta->thread_size_key); 297144519Sdavidxu if (keytable == NULL) 298132332Smarcel return (TD_MALLOC); 299144519Sdavidxu ret = ps_pread(ta->ph, (psaddr_t)ta->thread_keytable_addr, keytable, 300144519Sdavidxu ta->thread_max_keys * ta->thread_size_key); 301144519Sdavidxu if (ret != 0) { 302144519Sdavidxu free(keytable); 303144519Sdavidxu return (P2T(ret)); 304144989Sdavidxu } 305144519Sdavidxu for (i = 0; i < ta->thread_max_keys; i++) { 306144519Sdavidxu allocated = *(int *)(keytable + i * ta->thread_size_key + 307144519Sdavidxu ta->thread_off_key_allocated); 308144519Sdavidxu destructor = *(void **)(keytable + i * ta->thread_size_key + 309144519Sdavidxu ta->thread_off_key_destructor); 310144519Sdavidxu if (allocated) { 311144519Sdavidxu ret = (ki)(i, destructor, arg); 312144519Sdavidxu if (ret != 0) { 313144519Sdavidxu free(keytable); 314144519Sdavidxu return (TD_DBERR); 315144519Sdavidxu } 316144519Sdavidxu } 317144519Sdavidxu } 318144519Sdavidxu free(keytable); 319144519Sdavidxu return (TD_OK); 320144519Sdavidxu} 321132332Smarcel 322144519Sdavidxustatic td_err_e 323144519Sdavidxupt_ta_event_addr(const td_thragent_t *ta, td_event_e event, td_notify_t *ptr) 324144519Sdavidxu{ 325144989Sdavidxu 326144519Sdavidxu TDBG_FUNC(); 327144922Sdavidxu 328144922Sdavidxu switch (event) { 329144922Sdavidxu case TD_CREATE: 330144922Sdavidxu ptr->type = NOTIFY_BPT; 331144922Sdavidxu ptr->u.bptaddr = ta->thread_bp_create_addr; 332144922Sdavidxu return (0); 333144922Sdavidxu case TD_DEATH: 334144922Sdavidxu ptr->type = NOTIFY_BPT; 335144922Sdavidxu ptr->u.bptaddr = ta->thread_bp_death_addr; 336144922Sdavidxu return (0); 337144922Sdavidxu default: 338144922Sdavidxu return (TD_ERR); 339144922Sdavidxu } 340144519Sdavidxu} 341132332Smarcel 342144519Sdavidxustatic td_err_e 343144519Sdavidxupt_ta_set_event(const td_thragent_t *ta, td_thr_events_t *events) 344144519Sdavidxu{ 345144989Sdavidxu td_thr_events_t mask; 346144922Sdavidxu int ret; 347144922Sdavidxu 348144519Sdavidxu TDBG_FUNC(); 349144922Sdavidxu ret = ps_pread(ta->ph, ta->thread_event_mask_addr, &mask, 350144922Sdavidxu sizeof(mask)); 351144922Sdavidxu if (ret != 0) 352144922Sdavidxu return (P2T(ret)); 353144922Sdavidxu mask |= *events; 354144922Sdavidxu ret = ps_pwrite(ta->ph, ta->thread_event_mask_addr, &mask, 355144922Sdavidxu sizeof(mask)); 356144922Sdavidxu return (P2T(ret)); 357132332Smarcel} 358132332Smarcel 359132332Smarcelstatic td_err_e 360144519Sdavidxupt_ta_clear_event(const td_thragent_t *ta, td_thr_events_t *events) 361132332Smarcel{ 362144989Sdavidxu td_thr_events_t mask; 363144922Sdavidxu int ret; 364144922Sdavidxu 365144519Sdavidxu TDBG_FUNC(); 366144922Sdavidxu ret = ps_pread(ta->ph, ta->thread_event_mask_addr, &mask, 367144922Sdavidxu sizeof(mask)); 368144922Sdavidxu if (ret != 0) 369144922Sdavidxu return (P2T(ret)); 370144922Sdavidxu mask &= ~*events; 371144922Sdavidxu ret = ps_pwrite(ta->ph, ta->thread_event_mask_addr, &mask, 372144922Sdavidxu sizeof(mask)); 373144922Sdavidxu return (P2T(ret)); 374132332Smarcel} 375132332Smarcel 376132332Smarcelstatic td_err_e 377144519Sdavidxupt_ta_event_getmsg(const td_thragent_t *ta, td_event_msg_t *msg) 378132332Smarcel{ 379144922Sdavidxu static td_thrhandle_t handle; 380144922Sdavidxu 381144922Sdavidxu psaddr_t pt, pt_temp; 382144989Sdavidxu td_thr_events_e tmp; 383144922Sdavidxu long lwp; 384144922Sdavidxu int ret; 385144922Sdavidxu 386144519Sdavidxu TDBG_FUNC(); 387144922Sdavidxu 388144922Sdavidxu ret = ps_pread(ta->ph, ta->thread_last_event_addr, &pt, sizeof(pt)); 389144922Sdavidxu if (ret != 0) 390144922Sdavidxu return (P2T(ret)); 391144922Sdavidxu if (pt == NULL) 392144922Sdavidxu return (TD_NOMSG); 393144989Sdavidxu /* 394144989Sdavidxu * Take the event pointer, at the time, libthr only reports event 395144989Sdavidxu * once a time, so it is not a link list. 396144989Sdavidxu */ 397144922Sdavidxu pt_temp = NULL; 398144922Sdavidxu ps_pwrite(ta->ph, ta->thread_last_event_addr, &pt_temp, sizeof(pt_temp)); 399144922Sdavidxu 400144989Sdavidxu /* Read event info */ 401144922Sdavidxu ret = ps_pread(ta->ph, pt + ta->thread_off_event_buf, msg, sizeof(*msg)); 402144922Sdavidxu if (ret != 0) 403144922Sdavidxu return (P2T(ret)); 404144922Sdavidxu if (msg->event == 0) 405144922Sdavidxu return (TD_NOMSG); 406144989Sdavidxu /* Clear event */ 407144922Sdavidxu tmp = 0; 408144922Sdavidxu ps_pwrite(ta->ph, pt + ta->thread_off_event_buf, &tmp, sizeof(tmp)); 409144989Sdavidxu /* Convert event */ 410144922Sdavidxu pt = (psaddr_t)msg->th_p; 411144922Sdavidxu ret = ps_pread(ta->ph, pt + ta->thread_off_tid, &lwp, sizeof(lwp)); 412144922Sdavidxu if (ret != 0) 413144922Sdavidxu return (P2T(ret)); 414144922Sdavidxu handle.th_ta = ta; 415144989Sdavidxu handle.th_tid = lwp; 416144922Sdavidxu handle.th_thread = pt; 417144922Sdavidxu msg->th_p = &handle; 418144922Sdavidxu return (0); 419144519Sdavidxu} 420132332Smarcel 421144519Sdavidxustatic td_err_e 422144519Sdavidxupt_dbsuspend(const td_thrhandle_t *th, int suspend) 423144519Sdavidxu{ 424144519Sdavidxu td_thragent_t *ta = (td_thragent_t *)th->th_ta; 425144519Sdavidxu int ret; 426132332Smarcel 427144519Sdavidxu TDBG_FUNC(); 428144519Sdavidxu 429144519Sdavidxu ret = pt_validate(th); 430144519Sdavidxu if (ret) 431144519Sdavidxu return (ret); 432144519Sdavidxu 433144519Sdavidxu if (suspend) 434144989Sdavidxu ret = ps_lstop(ta->ph, th->th_tid); 435144519Sdavidxu else 436144989Sdavidxu ret = ps_lcontinue(ta->ph, th->th_tid); 437144519Sdavidxu return (P2T(ret)); 438132332Smarcel} 439132332Smarcel 440132332Smarcelstatic td_err_e 441144519Sdavidxupt_thr_dbresume(const td_thrhandle_t *th) 442132332Smarcel{ 443144519Sdavidxu TDBG_FUNC(); 444144519Sdavidxu 445144519Sdavidxu return pt_dbsuspend(th, 0); 446132332Smarcel} 447132332Smarcel 448132332Smarcelstatic td_err_e 449144519Sdavidxupt_thr_dbsuspend(const td_thrhandle_t *th) 450133631Sdavidxu{ 451144519Sdavidxu TDBG_FUNC(); 452133631Sdavidxu 453144519Sdavidxu return pt_dbsuspend(th, 1); 454133631Sdavidxu} 455133631Sdavidxu 456133631Sdavidxustatic td_err_e 457144519Sdavidxupt_thr_validate(const td_thrhandle_t *th) 458133631Sdavidxu{ 459144519Sdavidxu td_thrhandle_t temp; 460144519Sdavidxu int ret; 461133631Sdavidxu 462144519Sdavidxu TDBG_FUNC(); 463144519Sdavidxu 464144989Sdavidxu ret = pt_ta_map_id2thr(th->th_ta, th->th_tid, &temp); 465144519Sdavidxu return (ret); 466133631Sdavidxu} 467133631Sdavidxu 468133631Sdavidxustatic td_err_e 469144519Sdavidxupt_thr_get_info(const td_thrhandle_t *th, td_thrinfo_t *info) 470132332Smarcel{ 471144519Sdavidxu const td_thragent_t *ta = th->th_ta; 472155414Sdavidxu struct ptrace_lwpinfo linfo; 473144519Sdavidxu int state; 474144519Sdavidxu int ret; 475144519Sdavidxu 476144519Sdavidxu TDBG_FUNC(); 477144519Sdavidxu 478155387Sdavidxu bzero(info, sizeof(*info)); 479144519Sdavidxu ret = pt_validate(th); 480144519Sdavidxu if (ret) 481144519Sdavidxu return (ret); 482144989Sdavidxu ret = ps_pread(ta->ph, th->th_thread + ta->thread_off_state, 483144519Sdavidxu &state, sizeof(state)); 484144519Sdavidxu if (ret != 0) 485144519Sdavidxu return (P2T(ret)); 486144989Sdavidxu ret = ps_pread(ta->ph, th->th_thread + ta->thread_off_report_events, 487144974Sdavidxu &info->ti_traceme, sizeof(int)); 488144974Sdavidxu if (ret != 0) 489144974Sdavidxu return (P2T(ret)); 490144989Sdavidxu ret = ps_pread(ta->ph, th->th_thread + ta->thread_off_event_mask, 491144974Sdavidxu &info->ti_events, sizeof(td_thr_events_t)); 492144974Sdavidxu if (ret != 0) 493144974Sdavidxu return (P2T(ret)); 494144989Sdavidxu ret = ps_pread(ta->ph, th->th_thread + ta->thread_off_tcb, 495144989Sdavidxu &info->ti_tls, sizeof(void *)); 496144989Sdavidxu info->ti_lid = th->th_tid; 497144519Sdavidxu info->ti_tid = th->th_tid; 498144989Sdavidxu info->ti_thread = th->th_thread; 499144519Sdavidxu info->ti_ta_p = th->th_ta; 500155414Sdavidxu ret = ps_linfo(ta->ph, th->th_tid, &linfo); 501155414Sdavidxu if (ret == PS_OK) { 502155414Sdavidxu info->ti_sigmask = linfo.pl_sigmask; 503155414Sdavidxu info->ti_pending = linfo.pl_siglist; 504155414Sdavidxu } 505144519Sdavidxu if (state == ta->thread_state_running) 506144519Sdavidxu info->ti_state = TD_THR_RUN; 507144519Sdavidxu else if (state == ta->thread_state_zoombie) 508144519Sdavidxu info->ti_state = TD_THR_ZOMBIE; 509144519Sdavidxu else 510144519Sdavidxu info->ti_state = TD_THR_SLEEP; 511144519Sdavidxu info->ti_type = TD_THR_USER; 512144519Sdavidxu return (0); 513132332Smarcel} 514132332Smarcel 515146818Sdfr#ifdef __i386__ 516132332Smarcelstatic td_err_e 517146818Sdfrpt_thr_getxmmregs(const td_thrhandle_t *th, char *fxsave) 518146818Sdfr{ 519146818Sdfr const td_thragent_t *ta = th->th_ta; 520146818Sdfr int ret; 521146818Sdfr 522146818Sdfr TDBG_FUNC(); 523146818Sdfr 524146818Sdfr ret = pt_validate(th); 525146818Sdfr if (ret) 526146818Sdfr return (ret); 527146818Sdfr 528146818Sdfr ret = ps_lgetxmmregs(ta->ph, th->th_tid, fxsave); 529146818Sdfr return (P2T(ret)); 530146818Sdfr} 531146818Sdfr#endif 532146818Sdfr 533146818Sdfrstatic td_err_e 534144519Sdavidxupt_thr_getfpregs(const td_thrhandle_t *th, prfpregset_t *fpregs) 535132332Smarcel{ 536144519Sdavidxu const td_thragent_t *ta = th->th_ta; 537144519Sdavidxu int ret; 538144519Sdavidxu 539144519Sdavidxu TDBG_FUNC(); 540144519Sdavidxu 541144519Sdavidxu ret = pt_validate(th); 542144519Sdavidxu if (ret) 543144519Sdavidxu return (ret); 544144519Sdavidxu 545144989Sdavidxu ret = ps_lgetfpregs(ta->ph, th->th_tid, fpregs); 546144519Sdavidxu return (P2T(ret)); 547132332Smarcel} 548132332Smarcel 549132332Smarcelstatic td_err_e 550144519Sdavidxupt_thr_getgregs(const td_thrhandle_t *th, prgregset_t gregs) 551132332Smarcel{ 552144519Sdavidxu const td_thragent_t *ta = th->th_ta; 553144519Sdavidxu int ret; 554132332Smarcel 555144519Sdavidxu TDBG_FUNC(); 556144519Sdavidxu 557144519Sdavidxu ret = pt_validate(th); 558144519Sdavidxu if (ret) 559144519Sdavidxu return (ret); 560144519Sdavidxu 561144989Sdavidxu ret = ps_lgetregs(ta->ph, th->th_tid, gregs); 562144519Sdavidxu return (P2T(ret)); 563132332Smarcel} 564132332Smarcel 565146818Sdfr#ifdef __i386__ 566132332Smarcelstatic td_err_e 567146818Sdfrpt_thr_setxmmregs(const td_thrhandle_t *th, const char *fxsave) 568146818Sdfr{ 569146818Sdfr const td_thragent_t *ta = th->th_ta; 570146818Sdfr int ret; 571146818Sdfr 572146818Sdfr TDBG_FUNC(); 573146818Sdfr 574146818Sdfr ret = pt_validate(th); 575146818Sdfr if (ret) 576146818Sdfr return (ret); 577146818Sdfr 578146818Sdfr ret = ps_lsetxmmregs(ta->ph, th->th_tid, fxsave); 579146818Sdfr return (P2T(ret)); 580146818Sdfr} 581146818Sdfr#endif 582146818Sdfr 583146818Sdfrstatic td_err_e 584144519Sdavidxupt_thr_setfpregs(const td_thrhandle_t *th, const prfpregset_t *fpregs) 585132332Smarcel{ 586144519Sdavidxu const td_thragent_t *ta = th->th_ta; 587144519Sdavidxu int ret; 588132332Smarcel 589144519Sdavidxu TDBG_FUNC(); 590144519Sdavidxu 591144519Sdavidxu ret = pt_validate(th); 592144519Sdavidxu if (ret) 593144519Sdavidxu return (ret); 594144519Sdavidxu 595144989Sdavidxu ret = ps_lsetfpregs(ta->ph, th->th_tid, fpregs); 596144519Sdavidxu return (P2T(ret)); 597132332Smarcel} 598132332Smarcel 599132332Smarcelstatic td_err_e 600144519Sdavidxupt_thr_setgregs(const td_thrhandle_t *th, const prgregset_t gregs) 601132332Smarcel{ 602144519Sdavidxu const td_thragent_t *ta = th->th_ta; 603144519Sdavidxu int ret; 604132332Smarcel 605144519Sdavidxu TDBG_FUNC(); 606144519Sdavidxu 607144519Sdavidxu ret = pt_validate(th); 608144519Sdavidxu if (ret) 609144519Sdavidxu return (ret); 610144519Sdavidxu 611144989Sdavidxu ret = ps_lsetregs(ta->ph, th->th_tid, gregs); 612144519Sdavidxu return (P2T(ret)); 613132332Smarcel} 614132332Smarcel 615132332Smarcelstatic td_err_e 616144519Sdavidxupt_thr_event_enable(const td_thrhandle_t *th, int en) 617132332Smarcel{ 618144922Sdavidxu const td_thragent_t *ta = th->th_ta; 619144922Sdavidxu int ret; 620144922Sdavidxu 621144519Sdavidxu TDBG_FUNC(); 622144922Sdavidxu ret = ps_pwrite(ta->ph, th->th_thread + ta->thread_off_report_events, 623144922Sdavidxu &en, sizeof(int)); 624144922Sdavidxu return (P2T(ret)); 625132332Smarcel} 626132332Smarcel 627132332Smarcelstatic td_err_e 628144519Sdavidxupt_thr_set_event(const td_thrhandle_t *th, td_thr_events_t *setp) 629132332Smarcel{ 630144922Sdavidxu const td_thragent_t *ta = th->th_ta; 631144922Sdavidxu td_thr_events_t mask; 632144922Sdavidxu int ret; 633144922Sdavidxu 634144519Sdavidxu TDBG_FUNC(); 635144922Sdavidxu ret = ps_pread(ta->ph, th->th_thread + ta->thread_off_event_mask, 636144922Sdavidxu &mask, sizeof(mask)); 637144922Sdavidxu mask |= *setp; 638144922Sdavidxu ret = ps_pwrite(ta->ph, th->th_thread + ta->thread_off_event_mask, 639144922Sdavidxu &mask, sizeof(mask)); 640144922Sdavidxu return (P2T(ret)); 641144519Sdavidxu} 642133631Sdavidxu 643144519Sdavidxustatic td_err_e 644144519Sdavidxupt_thr_clear_event(const td_thrhandle_t *th, td_thr_events_t *setp) 645144519Sdavidxu{ 646144922Sdavidxu const td_thragent_t *ta = th->th_ta; 647144922Sdavidxu td_thr_events_t mask; 648144922Sdavidxu int ret; 649144922Sdavidxu 650144519Sdavidxu TDBG_FUNC(); 651144922Sdavidxu ret = ps_pread(ta->ph, th->th_thread + ta->thread_off_event_mask, 652144922Sdavidxu &mask, sizeof(mask)); 653144922Sdavidxu mask &= ~*setp; 654144922Sdavidxu ret = ps_pwrite(ta->ph, th->th_thread + ta->thread_off_event_mask, 655144922Sdavidxu &mask, sizeof(mask)); 656144922Sdavidxu return (P2T(ret)); 657132332Smarcel} 658132332Smarcel 659132332Smarcelstatic td_err_e 660144519Sdavidxupt_thr_event_getmsg(const td_thrhandle_t *th, td_event_msg_t *msg) 661132332Smarcel{ 662144922Sdavidxu static td_thrhandle_t handle; 663144922Sdavidxu td_thragent_t *ta = (td_thragent_t *)th->th_ta; 664144922Sdavidxu psaddr_t pt, pt_temp; 665144922Sdavidxu long lwp; 666144922Sdavidxu int ret; 667144922Sdavidxu td_thr_events_e tmp; 668144922Sdavidxu 669144519Sdavidxu TDBG_FUNC(); 670144922Sdavidxu pt = th->th_thread; 671144922Sdavidxu ret = ps_pread(ta->ph, ta->thread_last_event_addr, &pt_temp, sizeof(pt_temp)); 672144922Sdavidxu if (ret != 0) 673144922Sdavidxu return (P2T(ret)); 674144989Sdavidxu /* Get event */ 675144922Sdavidxu ret = ps_pread(ta->ph, pt + ta->thread_off_event_buf, msg, sizeof(*msg)); 676144922Sdavidxu if (ret != 0) 677144922Sdavidxu return (P2T(ret)); 678144922Sdavidxu if (msg->event == 0) 679144922Sdavidxu return (TD_NOMSG); 680144989Sdavidxu /* 681144989Sdavidxu * Take the event pointer, at the time, libthr only reports event 682144989Sdavidxu * once a time, so it is not a link list. 683144989Sdavidxu */ 684144922Sdavidxu if (pt == pt_temp) { 685144922Sdavidxu pt_temp = NULL; 686144922Sdavidxu ps_pwrite(ta->ph, ta->thread_last_event_addr, &pt_temp, sizeof(pt_temp)); 687144922Sdavidxu } 688144989Sdavidxu /* Clear event */ 689144922Sdavidxu tmp = 0; 690144922Sdavidxu ps_pwrite(ta->ph, pt + ta->thread_off_event_buf, &tmp, sizeof(tmp)); 691144989Sdavidxu /* Convert event */ 692144922Sdavidxu pt = (psaddr_t)msg->th_p; 693144922Sdavidxu ret = ps_pread(ta->ph, pt + ta->thread_off_tid, &lwp, sizeof(lwp)); 694144922Sdavidxu if (ret != 0) 695144922Sdavidxu return (P2T(ret)); 696144922Sdavidxu handle.th_ta = ta; 697144989Sdavidxu handle.th_tid = lwp; 698144922Sdavidxu handle.th_thread = pt; 699144922Sdavidxu msg->th_p = &handle; 700144922Sdavidxu return (0); 701132332Smarcel} 702132332Smarcel 703132332Smarcelstatic td_err_e 704144519Sdavidxupt_thr_sstep(const td_thrhandle_t *th, int step) 705132332Smarcel{ 706144519Sdavidxu TDBG_FUNC(); 707144519Sdavidxu 708144989Sdavidxu return pt_validate(th); 709132332Smarcel} 710132332Smarcel 711144519Sdavidxustatic int 712144519Sdavidxupt_validate(const td_thrhandle_t *th) 713144519Sdavidxu{ 714144519Sdavidxu 715144989Sdavidxu if (th->th_tid == 0 || th->th_thread == NULL) 716144989Sdavidxu return (TD_ERR); 717144519Sdavidxu return (TD_OK); 718144519Sdavidxu} 719144519Sdavidxu 720133631Sdavidxustatic td_err_e 721144519Sdavidxupt_thr_tls_get_addr(const td_thrhandle_t *th, void *_linkmap, size_t offset, 722144519Sdavidxu void **address) 723133631Sdavidxu{ 724144519Sdavidxu char *obj_entry; 725144519Sdavidxu const td_thragent_t *ta = th->th_ta; 726146447Scharnier psaddr_t tcb_addr, *dtv_addr; 727144519Sdavidxu int tls_index, ret; 728144519Sdavidxu 729144519Sdavidxu /* linkmap is a member of Obj_Entry */ 730144519Sdavidxu obj_entry = (char *)_linkmap - ta->thread_off_linkmap; 731144519Sdavidxu 732144519Sdavidxu /* get tlsindex of the object file */ 733144519Sdavidxu ret = ps_pread(ta->ph, 734144519Sdavidxu obj_entry + ta->thread_off_tlsindex, 735144519Sdavidxu &tls_index, sizeof(tls_index)); 736144519Sdavidxu if (ret != 0) 737144519Sdavidxu return (P2T(ret)); 738144519Sdavidxu 739144519Sdavidxu /* get thread tcb */ 740144989Sdavidxu ret = ps_pread(ta->ph, th->th_thread + ta->thread_off_tcb, 741144519Sdavidxu &tcb_addr, sizeof(tcb_addr)); 742144519Sdavidxu if (ret != 0) 743144519Sdavidxu return (P2T(ret)); 744144519Sdavidxu 745144519Sdavidxu /* get dtv array address */ 746144519Sdavidxu ret = ps_pread(ta->ph, tcb_addr + ta->thread_off_dtv, 747144519Sdavidxu &dtv_addr, sizeof(dtv_addr)); 748144519Sdavidxu if (ret != 0) 749144519Sdavidxu return (P2T(ret)); 750144519Sdavidxu /* now get the object's tls block base address */ 751144519Sdavidxu ret = ps_pread(ta->ph, &dtv_addr[tls_index+1], address, 752144519Sdavidxu sizeof(*address)); 753144519Sdavidxu if (ret != 0) 754144519Sdavidxu return (P2T(ret)); 755144519Sdavidxu 756144519Sdavidxu *address += offset; 757133631Sdavidxu return (TD_OK); 758133631Sdavidxu} 759133631Sdavidxu 760132332Smarcelstruct ta_ops libthr_db_ops = { 761144519Sdavidxu .to_init = pt_init, 762144519Sdavidxu .to_ta_clear_event = pt_ta_clear_event, 763144519Sdavidxu .to_ta_delete = pt_ta_delete, 764144519Sdavidxu .to_ta_event_addr = pt_ta_event_addr, 765144519Sdavidxu .to_ta_event_getmsg = pt_ta_event_getmsg, 766144519Sdavidxu .to_ta_map_id2thr = pt_ta_map_id2thr, 767144519Sdavidxu .to_ta_map_lwp2thr = pt_ta_map_lwp2thr, 768144519Sdavidxu .to_ta_new = pt_ta_new, 769144519Sdavidxu .to_ta_set_event = pt_ta_set_event, 770144519Sdavidxu .to_ta_thr_iter = pt_ta_thr_iter, 771144519Sdavidxu .to_ta_tsd_iter = pt_ta_tsd_iter, 772144519Sdavidxu .to_thr_clear_event = pt_thr_clear_event, 773144519Sdavidxu .to_thr_dbresume = pt_thr_dbresume, 774144519Sdavidxu .to_thr_dbsuspend = pt_thr_dbsuspend, 775144519Sdavidxu .to_thr_event_enable = pt_thr_event_enable, 776144519Sdavidxu .to_thr_event_getmsg = pt_thr_event_getmsg, 777144519Sdavidxu .to_thr_get_info = pt_thr_get_info, 778144519Sdavidxu .to_thr_getfpregs = pt_thr_getfpregs, 779144519Sdavidxu .to_thr_getgregs = pt_thr_getgregs, 780144519Sdavidxu .to_thr_set_event = pt_thr_set_event, 781144519Sdavidxu .to_thr_setfpregs = pt_thr_setfpregs, 782144519Sdavidxu .to_thr_setgregs = pt_thr_setgregs, 783144519Sdavidxu .to_thr_validate = pt_thr_validate, 784144519Sdavidxu .to_thr_tls_get_addr = pt_thr_tls_get_addr, 785132332Smarcel 786133631Sdavidxu /* FreeBSD specific extensions. */ 787144519Sdavidxu .to_thr_sstep = pt_thr_sstep, 788146818Sdfr#ifdef __i386__ 789146818Sdfr .to_thr_getxmmregs = pt_thr_getxmmregs, 790146818Sdfr .to_thr_setxmmregs = pt_thr_setxmmregs, 791146818Sdfr#endif 792132332Smarcel}; 793