thread_db.c revision 181044
1/* 2 * Copyright (c) 2004 David Xu <davidxu@freebsd.org> 3 * All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 14 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24 * SUCH DAMAGE. 25 */ 26 27#include <sys/cdefs.h> 28__FBSDID("$FreeBSD: head/lib/libthread_db/thread_db.c 181044 2008-07-31 05:25:52Z marcel $"); 29 30#include <proc_service.h> 31#include <stddef.h> 32#include <thread_db.h> 33#include <unistd.h> 34#include <sys/cdefs.h> 35#include <sys/linker_set.h> 36 37#include "thread_db_int.h" 38 39struct td_thragent 40{ 41 TD_THRAGENT_FIELDS; 42}; 43 44static TAILQ_HEAD(, td_thragent) proclist = TAILQ_HEAD_INITIALIZER(proclist); 45 46SET_DECLARE(__ta_ops, struct ta_ops); 47 48td_err_e 49td_init(void) 50{ 51 td_err_e ret, tmp; 52 struct ta_ops *ops_p, **ops_pp; 53 54 ret = 0; 55 SET_FOREACH(ops_pp, __ta_ops) { 56 ops_p = *ops_pp; 57 if (ops_p->to_init != NULL) { 58 tmp = ops_p->to_init(); 59 if (tmp != TD_OK) 60 ret = tmp; 61 } 62 } 63 return (ret); 64} 65 66td_err_e 67td_ta_clear_event(const td_thragent_t *ta, td_thr_events_t *events) 68{ 69 return (ta->ta_ops->to_ta_clear_event(ta, events)); 70} 71 72td_err_e 73td_ta_delete(td_thragent_t *ta) 74{ 75 TAILQ_REMOVE(&proclist, ta, ta_next); 76 return (ta->ta_ops->to_ta_delete(ta)); 77} 78 79td_err_e 80td_ta_event_addr(const td_thragent_t *ta, td_event_e event, td_notify_t *ptr) 81{ 82 return (ta->ta_ops->to_ta_event_addr(ta, event, ptr)); 83} 84 85td_err_e 86td_ta_event_getmsg(const td_thragent_t *ta, td_event_msg_t *msg) 87{ 88 return (ta->ta_ops->to_ta_event_getmsg(ta, msg)); 89} 90 91td_err_e 92td_ta_map_id2thr(const td_thragent_t *ta, thread_t id, td_thrhandle_t *th) 93{ 94 return (ta->ta_ops->to_ta_map_id2thr(ta, id, th)); 95} 96 97td_err_e 98td_ta_map_lwp2thr(const td_thragent_t *ta, lwpid_t lwpid, td_thrhandle_t *th) 99{ 100 return (ta->ta_ops->to_ta_map_lwp2thr(ta, lwpid, th)); 101} 102 103td_err_e 104td_ta_new(struct ps_prochandle *ph, td_thragent_t **pta) 105{ 106 struct ta_ops *ops_p, **ops_pp; 107 108 SET_FOREACH(ops_pp, __ta_ops) { 109 ops_p = *ops_pp; 110 if (ops_p->to_ta_new(ph, pta) == TD_OK) { 111 TAILQ_INSERT_HEAD(&proclist, *pta, ta_next); 112 (*pta)->ta_ops = ops_p; 113 return (TD_OK); 114 } 115 } 116 return (TD_NOLIBTHREAD); 117} 118 119td_err_e 120td_ta_set_event(const td_thragent_t *ta, td_thr_events_t *events) 121{ 122 return (ta->ta_ops->to_ta_set_event(ta, events)); 123} 124 125td_err_e 126td_ta_thr_iter(const td_thragent_t *ta, td_thr_iter_f *callback, 127 void *cbdata_p, td_thr_state_e state, int ti_pri, sigset_t *ti_sigmask_p, 128 unsigned int ti_user_flags) 129{ 130 return (ta->ta_ops->to_ta_thr_iter(ta, callback, cbdata_p, state, 131 ti_pri, ti_sigmask_p, ti_user_flags)); 132} 133 134td_err_e 135td_ta_tsd_iter(const td_thragent_t *ta, td_key_iter_f *callback, 136 void *cbdata_p) 137{ 138 return (ta->ta_ops->to_ta_tsd_iter(ta, callback, cbdata_p)); 139} 140 141td_err_e 142td_thr_clear_event(const td_thrhandle_t *th, td_thr_events_t *events) 143{ 144 const td_thragent_t *ta = th->th_ta; 145 return (ta->ta_ops->to_thr_clear_event(th, events)); 146} 147 148td_err_e 149td_thr_dbresume(const td_thrhandle_t *th) 150{ 151 const td_thragent_t *ta = th->th_ta; 152 return (ta->ta_ops->to_thr_dbresume(th)); 153} 154 155td_err_e 156td_thr_dbsuspend(const td_thrhandle_t *th) 157{ 158 const td_thragent_t *ta = th->th_ta; 159 return (ta->ta_ops->to_thr_dbsuspend(th)); 160} 161 162td_err_e 163td_thr_event_enable(const td_thrhandle_t *th, int en) 164{ 165 const td_thragent_t *ta = th->th_ta; 166 return (ta->ta_ops->to_thr_event_enable(th, en)); 167} 168 169td_err_e 170td_thr_event_getmsg(const td_thrhandle_t *th, td_event_msg_t *msg) 171{ 172 const td_thragent_t *ta = th->th_ta; 173 return (ta->ta_ops->to_thr_event_getmsg(th, msg)); 174} 175 176td_err_e 177td_thr_get_info(const td_thrhandle_t *th, td_thrinfo_t *info) 178{ 179 const td_thragent_t *ta = th->th_ta; 180 return (ta->ta_ops->to_thr_get_info(th, info)); 181} 182 183#ifdef __i386__ 184td_err_e 185td_thr_getxmmregs(const td_thrhandle_t *th, char *fxsave) 186{ 187 const td_thragent_t *ta = th->th_ta; 188 return (ta->ta_ops->to_thr_getxmmregs(th, fxsave)); 189} 190#endif 191 192 193td_err_e 194td_thr_getfpregs(const td_thrhandle_t *th, prfpregset_t *fpregset) 195{ 196 const td_thragent_t *ta = th->th_ta; 197 return (ta->ta_ops->to_thr_getfpregs(th, fpregset)); 198} 199 200td_err_e 201td_thr_getgregs(const td_thrhandle_t *th, prgregset_t gregs) 202{ 203 const td_thragent_t *ta = th->th_ta; 204 return (ta->ta_ops->to_thr_getgregs(th, gregs)); 205} 206 207td_err_e 208td_thr_set_event(const td_thrhandle_t *th, td_thr_events_t *events) 209{ 210 const td_thragent_t *ta = th->th_ta; 211 return (ta->ta_ops->to_thr_set_event(th, events)); 212} 213 214#ifdef __i386__ 215td_err_e 216td_thr_setxmmregs(const td_thrhandle_t *th, const char *fxsave) 217{ 218 const td_thragent_t *ta = th->th_ta; 219 return (ta->ta_ops->to_thr_setxmmregs(th, fxsave)); 220} 221#endif 222 223td_err_e 224td_thr_setfpregs(const td_thrhandle_t *th, const prfpregset_t *fpregs) 225{ 226 const td_thragent_t *ta = th->th_ta; 227 return (ta->ta_ops->to_thr_setfpregs(th, fpregs)); 228} 229 230td_err_e 231td_thr_setgregs(const td_thrhandle_t *th, const prgregset_t gregs) 232{ 233 const td_thragent_t *ta = th->th_ta; 234 return (ta->ta_ops->to_thr_setgregs(th, gregs)); 235} 236 237td_err_e 238td_thr_validate(const td_thrhandle_t *th) 239{ 240 const td_thragent_t *ta = th->th_ta; 241 return (ta->ta_ops->to_thr_validate(th)); 242} 243 244td_err_e 245td_thr_tls_get_addr(const td_thrhandle_t *th, psaddr_t linkmap, size_t offset, 246 psaddr_t *address) 247{ 248 const td_thragent_t *ta = th->th_ta; 249 return (ta->ta_ops->to_thr_tls_get_addr(th, linkmap, offset, address)); 250} 251 252/* FreeBSD specific extensions. */ 253 254td_err_e 255td_thr_sstep(const td_thrhandle_t *th, int step) 256{ 257 const td_thragent_t *ta = th->th_ta; 258 return (ta->ta_ops->to_thr_sstep(th, step)); 259} 260