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$"); 29 30 #include <proc_service.h> 31 #include <stddef.h> 32 #include <thread_db.h> 33 #include <unistd.h> 34 35 #include "thread_db_int.h" 36 37 struct td_thragent 38 { 39 TD_THRAGENT_FIELDS; 40 }; 41 42 static TAILQ_HEAD(, td_thragent) proclist = TAILQ_HEAD_INITIALIZER(proclist); 43 44 extern struct ta_ops libc_r_db_ops; 45 extern struct ta_ops libpthread_db_ops; 46 extern struct ta_ops libthr_db_ops; 47 48 static struct ta_ops *ops[] = { 49 &libpthread_db_ops, 50 &libthr_db_ops, 51 &libc_r_db_ops 52 }; 53 54 td_err_e 55 td_init(void) 56 { 57 td_err_e ret, tmp; 58 size_t i; 59 60 ret = 0; 61 for (i = 0; i < sizeof(ops)/sizeof(ops[0]); i++) { 62 if (ops[i]->to_init != NULL) { 63 tmp = ops[i]->to_init(); 64 if (tmp != TD_OK) 65 ret = tmp; 66 } 67 } 68 return (ret); 69 } 70 71 td_err_e 72 td_ta_clear_event(const td_thragent_t *ta, td_thr_events_t *events) 73 { 74 return (ta->ta_ops->to_ta_clear_event(ta, events)); 75 } 76 77 td_err_e 78 td_ta_delete(td_thragent_t *ta) 79 { 80 TAILQ_REMOVE(&proclist, ta, ta_next); 81 return (ta->ta_ops->to_ta_delete(ta)); 82 } 83 84 td_err_e 85 td_ta_event_addr(const td_thragent_t *ta, td_event_e event, td_notify_t *ptr) 86 { 87 return (ta->ta_ops->to_ta_event_addr(ta, event, ptr)); 88 } 89 90 td_err_e 91 td_ta_event_getmsg(const td_thragent_t *ta, td_event_msg_t *msg) 92 { 93 return (ta->ta_ops->to_ta_event_getmsg(ta, msg)); 94 } 95 96 td_err_e 97 td_ta_map_id2thr(const td_thragent_t *ta, thread_t id, td_thrhandle_t *th) 98 { 99 return (ta->ta_ops->to_ta_map_id2thr(ta, id, th)); 100 } 101 102 td_err_e 103 td_ta_map_lwp2thr(const td_thragent_t *ta, lwpid_t lwpid, td_thrhandle_t *th) 104 { 105 return (ta->ta_ops->to_ta_map_lwp2thr(ta, lwpid, th)); 106 } 107 108 td_err_e 109 td_ta_new(struct ps_prochandle *ph, td_thragent_t **pta) 110 { 111 size_t i; 112 113 for (i = 0; i < sizeof(ops)/sizeof(ops[0]); ++i) { 114 if (ops[i]->to_ta_new(ph, pta) == TD_OK) { 115 TAILQ_INSERT_HEAD(&proclist, *pta, ta_next); 116 (*pta)->ta_ops = ops[i]; 117 return (TD_OK); 118 } 119 } 120 return (TD_NOLIBTHREAD); 121 } 122 123 td_err_e 124 td_ta_set_event(const td_thragent_t *ta, td_thr_events_t *events) 125 { 126 return (ta->ta_ops->to_ta_set_event(ta, events)); 127 } 128 129 td_err_e 130 td_ta_thr_iter(const td_thragent_t *ta, td_thr_iter_f *callback, 131 void *cbdata_p, td_thr_state_e state, int ti_pri, sigset_t *ti_sigmask_p, 132 unsigned int ti_user_flags) 133 { 134 return (ta->ta_ops->to_ta_thr_iter(ta, callback, cbdata_p, state, 135 ti_pri, ti_sigmask_p, ti_user_flags)); 136 } 137 138 td_err_e 139 td_ta_tsd_iter(const td_thragent_t *ta, td_key_iter_f *callback, 140 void *cbdata_p) 141 { 142 return (ta->ta_ops->to_ta_tsd_iter(ta, callback, cbdata_p)); 143 } 144 145 td_err_e 146 td_thr_clear_event(const td_thrhandle_t *th, td_thr_events_t *events) 147 { 148 const td_thragent_t *ta = th->th_ta; 149 return (ta->ta_ops->to_thr_clear_event(th, events)); 150 } 151 152 td_err_e 153 td_thr_dbresume(const td_thrhandle_t *th) 154 { 155 const td_thragent_t *ta = th->th_ta; 156 return (ta->ta_ops->to_thr_dbresume(th)); 157 } 158 159 td_err_e 160 td_thr_dbsuspend(const td_thrhandle_t *th) 161 { 162 const td_thragent_t *ta = th->th_ta; 163 return (ta->ta_ops->to_thr_dbsuspend(th)); 164 } 165 166 td_err_e 167 td_thr_event_enable(const td_thrhandle_t *th, int en) 168 { 169 const td_thragent_t *ta = th->th_ta; 170 return (ta->ta_ops->to_thr_event_enable(th, en)); 171 } 172 173 td_err_e 174 td_thr_event_getmsg(const td_thrhandle_t *th, td_event_msg_t *msg) 175 { 176 const td_thragent_t *ta = th->th_ta; 177 return (ta->ta_ops->to_thr_event_getmsg(th, msg)); 178 } 179 180 td_err_e 181 td_thr_get_info(const td_thrhandle_t *th, td_thrinfo_t *info) 182 { 183 const td_thragent_t *ta = th->th_ta; 184 return (ta->ta_ops->to_thr_get_info(th, info)); 185 } 186 187 td_err_e 188 td_thr_getfpregs(const td_thrhandle_t *th, prfpregset_t *fpregset) 189 { 190 const td_thragent_t *ta = th->th_ta; 191 return (ta->ta_ops->to_thr_getfpregs(th, fpregset)); 192 } 193 194 td_err_e 195 td_thr_getgregs(const td_thrhandle_t *th, prgregset_t gregs) 196 { 197 const td_thragent_t *ta = th->th_ta; 198 return (ta->ta_ops->to_thr_getgregs(th, gregs)); 199 } 200 201 td_err_e 202 td_thr_set_event(const td_thrhandle_t *th, td_thr_events_t *events) 203 { 204 const td_thragent_t *ta = th->th_ta; 205 return (ta->ta_ops->to_thr_set_event(th, events)); 206 } 207 208 td_err_e 209 td_thr_setfpregs(const td_thrhandle_t *th, const prfpregset_t *fpregs) 210 { 211 const td_thragent_t *ta = th->th_ta; 212 return (ta->ta_ops->to_thr_setfpregs(th, fpregs)); 213 } 214 215 td_err_e 216 td_thr_setgregs(const td_thrhandle_t *th, const prgregset_t gregs) 217 { 218 const td_thragent_t *ta = th->th_ta; 219 return (ta->ta_ops->to_thr_setgregs(th, gregs)); 220 } 221 222 td_err_e 223 td_thr_validate(const td_thrhandle_t *th) 224 { 225 const td_thragent_t *ta = th->th_ta; 226 return (ta->ta_ops->to_thr_validate(th)); 227 } 228 229 /* FreeBSD specific extensions. */ 230 231 td_err_e 232 td_thr_sstep(const td_thrhandle_t *th, int step) 233 { 234 const td_thragent_t *ta = th->th_ta; 235 return (ta->ta_ops->to_thr_sstep(th, step)); 236 } 237