thread_db.c revision 177490
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 177490 2008-03-22 05:40:44Z davidxu $"); 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 size_t i; 54 55 ret = 0; 56 SET_FOREACH(ops_pp, __ta_ops) { 57 ops_p = *ops_pp; 58 if (ops_p->to_init != NULL) { 59 tmp = ops_p->to_init(); 60 if (tmp != TD_OK) 61 ret = tmp; 62 } 63 } 64 return (ret); 65} 66 67td_err_e 68td_ta_clear_event(const td_thragent_t *ta, td_thr_events_t *events) 69{ 70 return (ta->ta_ops->to_ta_clear_event(ta, events)); 71} 72 73td_err_e 74td_ta_delete(td_thragent_t *ta) 75{ 76 TAILQ_REMOVE(&proclist, ta, ta_next); 77 return (ta->ta_ops->to_ta_delete(ta)); 78} 79 80td_err_e 81td_ta_event_addr(const td_thragent_t *ta, td_event_e event, td_notify_t *ptr) 82{ 83 return (ta->ta_ops->to_ta_event_addr(ta, event, ptr)); 84} 85 86td_err_e 87td_ta_event_getmsg(const td_thragent_t *ta, td_event_msg_t *msg) 88{ 89 return (ta->ta_ops->to_ta_event_getmsg(ta, msg)); 90} 91 92td_err_e 93td_ta_map_id2thr(const td_thragent_t *ta, thread_t id, td_thrhandle_t *th) 94{ 95 return (ta->ta_ops->to_ta_map_id2thr(ta, id, th)); 96} 97 98td_err_e 99td_ta_map_lwp2thr(const td_thragent_t *ta, lwpid_t lwpid, td_thrhandle_t *th) 100{ 101 return (ta->ta_ops->to_ta_map_lwp2thr(ta, lwpid, th)); 102} 103 104td_err_e 105td_ta_new(struct ps_prochandle *ph, td_thragent_t **pta) 106{ 107 size_t i; 108 struct ta_ops *ops_p, **ops_pp; 109 110 SET_FOREACH(ops_pp, __ta_ops) { 111 ops_p = *ops_pp; 112 if (ops_p->to_ta_new(ph, pta) == TD_OK) { 113 TAILQ_INSERT_HEAD(&proclist, *pta, ta_next); 114 (*pta)->ta_ops = ops_p; 115 return (TD_OK); 116 } 117 } 118 return (TD_NOLIBTHREAD); 119} 120 121td_err_e 122td_ta_set_event(const td_thragent_t *ta, td_thr_events_t *events) 123{ 124 return (ta->ta_ops->to_ta_set_event(ta, events)); 125} 126 127td_err_e 128td_ta_thr_iter(const td_thragent_t *ta, td_thr_iter_f *callback, 129 void *cbdata_p, td_thr_state_e state, int ti_pri, sigset_t *ti_sigmask_p, 130 unsigned int ti_user_flags) 131{ 132 return (ta->ta_ops->to_ta_thr_iter(ta, callback, cbdata_p, state, 133 ti_pri, ti_sigmask_p, ti_user_flags)); 134} 135 136td_err_e 137td_ta_tsd_iter(const td_thragent_t *ta, td_key_iter_f *callback, 138 void *cbdata_p) 139{ 140 return (ta->ta_ops->to_ta_tsd_iter(ta, callback, cbdata_p)); 141} 142 143td_err_e 144td_thr_clear_event(const td_thrhandle_t *th, td_thr_events_t *events) 145{ 146 const td_thragent_t *ta = th->th_ta; 147 return (ta->ta_ops->to_thr_clear_event(th, events)); 148} 149 150td_err_e 151td_thr_dbresume(const td_thrhandle_t *th) 152{ 153 const td_thragent_t *ta = th->th_ta; 154 return (ta->ta_ops->to_thr_dbresume(th)); 155} 156 157td_err_e 158td_thr_dbsuspend(const td_thrhandle_t *th) 159{ 160 const td_thragent_t *ta = th->th_ta; 161 return (ta->ta_ops->to_thr_dbsuspend(th)); 162} 163 164td_err_e 165td_thr_event_enable(const td_thrhandle_t *th, int en) 166{ 167 const td_thragent_t *ta = th->th_ta; 168 return (ta->ta_ops->to_thr_event_enable(th, en)); 169} 170 171td_err_e 172td_thr_event_getmsg(const td_thrhandle_t *th, td_event_msg_t *msg) 173{ 174 const td_thragent_t *ta = th->th_ta; 175 return (ta->ta_ops->to_thr_event_getmsg(th, msg)); 176} 177 178td_err_e 179td_thr_get_info(const td_thrhandle_t *th, td_thrinfo_t *info) 180{ 181 const td_thragent_t *ta = th->th_ta; 182 return (ta->ta_ops->to_thr_get_info(th, info)); 183} 184 185#ifdef __i386__ 186td_err_e 187td_thr_getxmmregs(const td_thrhandle_t *th, char *fxsave) 188{ 189 const td_thragent_t *ta = th->th_ta; 190 return (ta->ta_ops->to_thr_getxmmregs(th, fxsave)); 191} 192#endif 193 194 195td_err_e 196td_thr_getfpregs(const td_thrhandle_t *th, prfpregset_t *fpregset) 197{ 198 const td_thragent_t *ta = th->th_ta; 199 return (ta->ta_ops->to_thr_getfpregs(th, fpregset)); 200} 201 202td_err_e 203td_thr_getgregs(const td_thrhandle_t *th, prgregset_t gregs) 204{ 205 const td_thragent_t *ta = th->th_ta; 206 return (ta->ta_ops->to_thr_getgregs(th, gregs)); 207} 208 209td_err_e 210td_thr_set_event(const td_thrhandle_t *th, td_thr_events_t *events) 211{ 212 const td_thragent_t *ta = th->th_ta; 213 return (ta->ta_ops->to_thr_set_event(th, events)); 214} 215 216#ifdef __i386__ 217td_err_e 218td_thr_setxmmregs(const td_thrhandle_t *th, const char *fxsave) 219{ 220 const td_thragent_t *ta = th->th_ta; 221 return (ta->ta_ops->to_thr_setxmmregs(th, fxsave)); 222} 223#endif 224 225td_err_e 226td_thr_setfpregs(const td_thrhandle_t *th, const prfpregset_t *fpregs) 227{ 228 const td_thragent_t *ta = th->th_ta; 229 return (ta->ta_ops->to_thr_setfpregs(th, fpregs)); 230} 231 232td_err_e 233td_thr_setgregs(const td_thrhandle_t *th, const prgregset_t gregs) 234{ 235 const td_thragent_t *ta = th->th_ta; 236 return (ta->ta_ops->to_thr_setgregs(th, gregs)); 237} 238 239td_err_e 240td_thr_validate(const td_thrhandle_t *th) 241{ 242 const td_thragent_t *ta = th->th_ta; 243 return (ta->ta_ops->to_thr_validate(th)); 244} 245 246td_err_e 247td_thr_tls_get_addr(const td_thrhandle_t *th, void *linkmap, size_t offset, 248 void **address) 249{ 250 const td_thragent_t *ta = th->th_ta; 251 return (ta->ta_ops->to_thr_tls_get_addr(th, linkmap, offset, address)); 252} 253 254/* FreeBSD specific extensions. */ 255 256td_err_e 257td_thr_sstep(const td_thrhandle_t *th, int step) 258{ 259 const td_thragent_t *ta = th->th_ta; 260 return (ta->ta_ops->to_thr_sstep(th, step)); 261} 262