1 /* 2 * Copyright (c) 2004 Marcel Moolenaar 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 * 9 * 1. Redistributions of source code must retain the above copyright 10 * notice, this list of conditions and the following disclaimer. 11 * 2. Redistributions in binary form must reproduce the above copyright 12 * notice, this list of conditions and the following disclaimer in the 13 * documentation and/or other materials provided with the distribution. 14 * 15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 16 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 17 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 18 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 19 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT 20 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 21 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 22 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 23 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF 24 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 25 */ 26 27 #include <sys/cdefs.h> 28 __FBSDID("$FreeBSD$"); 29 30 #include <proc_service.h> 31 #include <stdlib.h> 32 #include <thread_db.h> 33 34 #include "thread_db_int.h" 35 36 struct td_thragent { 37 TD_THRAGENT_FIELDS; 38 struct ps_prochandle *ta_ph; 39 psaddr_t ta_thread_list; 40 int ta_ofs_ctx; 41 int ta_ofs_next; 42 int ta_ofs_thr_id; 43 }; 44 45 static td_err_e 46 libthr_db_init() 47 { 48 return (TD_OK); 49 } 50 51 static td_err_e 52 libthr_db_ta_clear_event(const td_thragent_t *ta, td_thr_events_t *ev) 53 { 54 return (TD_ERR); 55 } 56 57 static td_err_e 58 libthr_db_ta_delete(td_thragent_t *ta) 59 { 60 free(ta); 61 return (TD_OK); 62 } 63 64 static td_err_e 65 libthr_db_ta_event_addr(const td_thragent_t *ta, td_thr_events_e event, 66 td_notify_t *n) 67 { 68 return (TD_ERR); 69 } 70 71 static td_err_e 72 libthr_db_ta_event_getmsg(const td_thragent_t *ta, td_event_msg_t *msg) 73 { 74 return (TD_ERR); 75 } 76 77 static td_err_e 78 libthr_db_ta_map_id2thr(const td_thragent_t *ta, thread_t tid, 79 td_thrhandle_t *th) 80 { 81 return (TD_ERR); 82 } 83 84 static td_err_e 85 libthr_db_ta_map_lwp2thr(const td_thragent_t *ta, lwpid_t lwpid, 86 td_thrhandle_t *th) 87 { 88 psaddr_t addr; 89 thread_t tid; 90 ps_err_e err; 91 92 th->th_ta = ta; 93 94 err = ps_pread(ta->ta_ph, ta->ta_thread_list, &th->th_thread, 95 sizeof(th->th_thread)); 96 if (err != PS_OK) 97 return (TD_ERR); 98 while (th->th_thread != NULL) { 99 addr = (psaddr_t)((uintptr_t)th->th_thread + 100 ta->ta_ofs_thr_id); 101 err = ps_pread(ta->ta_ph, addr, &tid, sizeof(thread_t)); 102 if (err != PS_OK) 103 return (TD_ERR); 104 if (tid == lwpid) 105 return (TD_OK); 106 addr = (psaddr_t)((uintptr_t)th->th_thread + ta->ta_ofs_next); 107 err = ps_pread(ta->ta_ph, addr, &th->th_thread, 108 sizeof(th->th_thread)); 109 if (err != PS_OK) 110 return (TD_ERR); 111 } 112 return (TD_NOLWP); 113 } 114 115 static td_err_e 116 libthr_db_ta_new(struct ps_prochandle *ph, td_thragent_t **ta_p) 117 { 118 td_thragent_t *ta; 119 psaddr_t addr; 120 ps_err_e err; 121 122 err = ps_pglobal_lookup(ph, NULL, "_libthr_debug", &addr); 123 if (err != PS_OK) 124 return (TD_NOLIBTHREAD); 125 126 ta = malloc(sizeof(td_thragent_t)); 127 if (ta == NULL) 128 return (TD_MALLOC); 129 130 ta->ta_ph = ph; 131 132 err = ps_pglobal_lookup(ph, NULL, "_thread_list", &ta->ta_thread_list); 133 if (err != PS_OK) 134 goto fail; 135 err = ps_pglobal_lookup(ph, NULL, "_thread_ctx_offset", &addr); 136 if (err != PS_OK) 137 goto fail; 138 err = ps_pread(ph, addr, &ta->ta_ofs_ctx, sizeof(int)); 139 if (err != PS_OK) 140 goto fail; 141 err = ps_pglobal_lookup(ph, NULL, "_thread_next_offset", &addr); 142 if (err != PS_OK) 143 goto fail; 144 err = ps_pread(ph, addr, &ta->ta_ofs_next, sizeof(int)); 145 if (err != PS_OK) 146 goto fail; 147 err = ps_pglobal_lookup(ph, NULL, "_thread_thr_id_offset", &addr); 148 if (err != PS_OK) 149 goto fail; 150 err = ps_pread(ph, addr, &ta->ta_ofs_thr_id, sizeof(int)); 151 if (err != PS_OK) 152 goto fail; 153 154 *ta_p = ta; 155 return (TD_OK); 156 157 fail: 158 free(ta); 159 *ta_p = NULL; 160 return (TD_ERR); 161 } 162 163 static td_err_e 164 libthr_db_ta_set_event(const td_thragent_t *ta, td_thr_events_t *ev) 165 { 166 return (TD_ERR); 167 } 168 169 static td_err_e 170 libthr_db_ta_thr_iter(const td_thragent_t *ta, td_thr_iter_f *cb, void *data, 171 td_thr_state_e state, int pri, sigset_t *mask, unsigned int flags) 172 { 173 td_thrhandle_t th; 174 psaddr_t addr; 175 ps_err_e err; 176 177 th.th_ta = ta; 178 179 err = ps_pread(ta->ta_ph, ta->ta_thread_list, &th.th_thread, 180 sizeof(th.th_thread)); 181 if (err != PS_OK) 182 return (TD_ERR); 183 while (th.th_thread != NULL) { 184 if (cb(&th, data) != 0) 185 return (TD_OK); 186 addr = (psaddr_t)((uintptr_t)th.th_thread + ta->ta_ofs_next); 187 err = ps_pread(ta->ta_ph, addr, &th.th_thread, 188 sizeof(th.th_thread)); 189 if (err != PS_OK) 190 return (TD_ERR); 191 } 192 return (TD_OK); 193 } 194 195 static td_err_e 196 libthr_db_thr_clear_event(const td_thrhandle_t *th, td_thr_events_t *ev) 197 { 198 return (TD_ERR); 199 } 200 201 static td_err_e 202 libthr_db_thr_event_enable(const td_thrhandle_t *th, int oo) 203 { 204 return (TD_ERR); 205 } 206 207 static td_err_e 208 libthr_db_thr_event_getmsg(const td_thrhandle_t *th, td_event_msg_t *msg) 209 { 210 return (TD_ERR); 211 } 212 213 static td_err_e 214 libthr_db_thr_get_info(const td_thrhandle_t *th, td_thrinfo_t *ti) 215 { 216 const td_thragent_t *ta; 217 psaddr_t addr; 218 thread_t tid; 219 ps_err_e err; 220 221 ta = th->th_ta; 222 ti->ti_ta_p = ta; 223 addr = (psaddr_t)((uintptr_t)th->th_thread + ta->ta_ofs_thr_id); 224 err = ps_pread(ta->ta_ph, addr, &tid, sizeof(thread_t)); 225 ti->ti_lid = tid; 226 ti->ti_tid = tid; 227 return ((err == PS_OK) ? TD_OK : TD_ERR); 228 } 229 230 static td_err_e 231 libthr_db_thr_getfpregs(const td_thrhandle_t *th, prfpregset_t *r) 232 { 233 const td_thragent_t *ta; 234 psaddr_t addr; 235 thread_t tid; 236 ps_err_e err; 237 238 ta = th->th_ta; 239 addr = (psaddr_t)((uintptr_t)th->th_thread + ta->ta_ofs_thr_id); 240 err = ps_pread(ta->ta_ph, addr, &tid, sizeof(thread_t)); 241 if (err != PS_OK) 242 return (TD_ERR); 243 err = ps_lgetfpregs(ta->ta_ph, tid, r); 244 return ((err == PS_OK) ? TD_OK : TD_ERR); 245 } 246 247 static td_err_e 248 libthr_db_thr_getgregs(const td_thrhandle_t *th, prgregset_t r) 249 { 250 const td_thragent_t *ta; 251 psaddr_t addr; 252 thread_t tid; 253 ps_err_e err; 254 255 ta = th->th_ta; 256 addr = (psaddr_t)((uintptr_t)th->th_thread + ta->ta_ofs_thr_id); 257 err = ps_pread(ta->ta_ph, addr, &tid, sizeof(thread_t)); 258 if (err != PS_OK) 259 return (TD_ERR); 260 err = ps_lgetregs(ta->ta_ph, tid, r); 261 return ((err == PS_OK) ? TD_OK : TD_ERR); 262 } 263 264 static td_err_e 265 libthr_db_thr_set_event(const td_thrhandle_t *th, td_thr_events_t *ev) 266 { 267 return (TD_ERR); 268 } 269 270 static td_err_e 271 libthr_db_thr_setfpregs(const td_thrhandle_t *th, const prfpregset_t *r) 272 { 273 return (TD_ERR); 274 } 275 276 static td_err_e 277 libthr_db_thr_setgregs(const td_thrhandle_t *th, const prgregset_t r) 278 { 279 return (TD_ERR); 280 } 281 282 static td_err_e 283 libthr_db_thr_validate(const td_thrhandle_t *th) 284 { 285 return (TD_ERR); 286 } 287 288 struct ta_ops libthr_db_ops = { 289 .to_init = libthr_db_init, 290 291 .to_ta_clear_event = libthr_db_ta_clear_event, 292 .to_ta_delete = libthr_db_ta_delete, 293 .to_ta_event_addr = libthr_db_ta_event_addr, 294 .to_ta_event_getmsg = libthr_db_ta_event_getmsg, 295 .to_ta_map_id2thr = libthr_db_ta_map_id2thr, 296 .to_ta_map_lwp2thr = libthr_db_ta_map_lwp2thr, 297 .to_ta_new = libthr_db_ta_new, 298 .to_ta_set_event = libthr_db_ta_set_event, 299 .to_ta_thr_iter = libthr_db_ta_thr_iter, 300 301 .to_thr_clear_event = libthr_db_thr_clear_event, 302 .to_thr_event_enable = libthr_db_thr_event_enable, 303 .to_thr_event_getmsg = libthr_db_thr_event_getmsg, 304 .to_thr_get_info = libthr_db_thr_get_info, 305 .to_thr_getfpregs = libthr_db_thr_getfpregs, 306 .to_thr_getgregs = libthr_db_thr_getgregs, 307 .to_thr_set_event = libthr_db_thr_set_event, 308 .to_thr_setfpregs = libthr_db_thr_setfpregs, 309 .to_thr_setgregs = libthr_db_thr_setgregs, 310 .to_thr_validate = libthr_db_thr_validate 311 }; 312