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 psaddr_t addr; 82 ps_err_e err; 83 thread_t lwpid; 84 85 th->th_ta = ta; 86 87 err = ps_pread(ta->ta_ph, ta->ta_thread_list, &th->th_thread, 88 sizeof(th->th_thread)); 89 if (err != PS_OK) 90 return (TD_ERR); 91 while (th->th_thread != NULL) { 92 addr = (psaddr_t)((uintptr_t)th->th_thread + 93 ta->ta_ofs_thr_id); 94 err = ps_pread(ta->ta_ph, addr, &lwpid, sizeof(thread_t)); 95 if (err != PS_OK) 96 return (TD_ERR); 97 if (tid == lwpid) { 98 th->th_tid = tid; 99 return (TD_OK); 100 } 101 addr = (psaddr_t)((uintptr_t)th->th_thread + ta->ta_ofs_next); 102 err = ps_pread(ta->ta_ph, addr, &th->th_thread, 103 sizeof(th->th_thread)); 104 if (err != PS_OK) 105 return (TD_ERR); 106 } 107 108 return (TD_NOTHR); 109 } 110 111 static td_err_e 112 libthr_db_ta_map_lwp2thr(const td_thragent_t *ta, lwpid_t lwpid, 113 td_thrhandle_t *th) 114 { 115 psaddr_t addr; 116 thread_t tid; 117 ps_err_e err; 118 119 th->th_ta = ta; 120 121 err = ps_pread(ta->ta_ph, ta->ta_thread_list, &th->th_thread, 122 sizeof(th->th_thread)); 123 if (err != PS_OK) 124 return (TD_ERR); 125 while (th->th_thread != NULL) { 126 addr = (psaddr_t)((uintptr_t)th->th_thread + 127 ta->ta_ofs_thr_id); 128 err = ps_pread(ta->ta_ph, addr, &tid, sizeof(thread_t)); 129 if (err != PS_OK) 130 return (TD_ERR); 131 if (tid == lwpid) { 132 th->th_tid = tid; 133 return (TD_OK); 134 } 135 addr = (psaddr_t)((uintptr_t)th->th_thread + ta->ta_ofs_next); 136 err = ps_pread(ta->ta_ph, addr, &th->th_thread, 137 sizeof(th->th_thread)); 138 if (err != PS_OK) 139 return (TD_ERR); 140 } 141 return (TD_ERR); 142 } 143 144 static td_err_e 145 libthr_db_ta_new(struct ps_prochandle *ph, td_thragent_t **ta_p) 146 { 147 td_thragent_t *ta; 148 psaddr_t addr; 149 ps_err_e err; 150 151 err = ps_pglobal_lookup(ph, NULL, "_libthr_debug", &addr); 152 if (err != PS_OK) 153 return (TD_NOLIBTHREAD); 154 155 ta = malloc(sizeof(td_thragent_t)); 156 if (ta == NULL) 157 return (TD_MALLOC); 158 159 ta->ta_ph = ph; 160 161 err = ps_pglobal_lookup(ph, NULL, "_thread_list", &ta->ta_thread_list); 162 if (err != PS_OK) 163 goto fail; 164 err = ps_pglobal_lookup(ph, NULL, "_thread_ctx_offset", &addr); 165 if (err != PS_OK) 166 goto fail; 167 err = ps_pread(ph, addr, &ta->ta_ofs_ctx, sizeof(int)); 168 if (err != PS_OK) 169 goto fail; 170 err = ps_pglobal_lookup(ph, NULL, "_thread_next_offset", &addr); 171 if (err != PS_OK) 172 goto fail; 173 err = ps_pread(ph, addr, &ta->ta_ofs_next, sizeof(int)); 174 if (err != PS_OK) 175 goto fail; 176 err = ps_pglobal_lookup(ph, NULL, "_thread_thr_id_offset", &addr); 177 if (err != PS_OK) 178 goto fail; 179 err = ps_pread(ph, addr, &ta->ta_ofs_thr_id, sizeof(int)); 180 if (err != PS_OK) 181 goto fail; 182 183 *ta_p = ta; 184 return (TD_OK); 185 186 fail: 187 free(ta); 188 *ta_p = NULL; 189 return (TD_ERR); 190 } 191 192 static td_err_e 193 libthr_db_ta_set_event(const td_thragent_t *ta, td_thr_events_t *ev) 194 { 195 return (TD_ERR); 196 } 197 198 static td_err_e 199 libthr_db_ta_thr_iter(const td_thragent_t *ta, td_thr_iter_f *cb, void *data, 200 td_thr_state_e state, int pri, sigset_t *mask, unsigned int flags) 201 { 202 td_thrhandle_t th; 203 psaddr_t addr; 204 ps_err_e err; 205 206 th.th_ta = ta; 207 208 err = ps_pread(ta->ta_ph, ta->ta_thread_list, &th.th_thread, 209 sizeof(th.th_thread)); 210 if (err != PS_OK) 211 return (TD_ERR); 212 while (th.th_thread != NULL) { 213 addr = (psaddr_t)((uintptr_t)th.th_thread + 214 ta->ta_ofs_thr_id); 215 err = ps_pread(ta->ta_ph, addr, &th.th_tid, sizeof(thread_t)); 216 if (err != PS_OK) 217 return (TD_ERR); 218 if (cb(&th, data) != 0) 219 return (TD_OK); 220 addr = (psaddr_t)((uintptr_t)th.th_thread + ta->ta_ofs_next); 221 err = ps_pread(ta->ta_ph, addr, &th.th_thread, 222 sizeof(th.th_thread)); 223 if (err != PS_OK) 224 return (TD_ERR); 225 } 226 return (TD_OK); 227 } 228 229 static td_err_e 230 libthr_db_thr_clear_event(const td_thrhandle_t *th, td_thr_events_t *ev) 231 { 232 return (TD_ERR); 233 } 234 235 static td_err_e 236 libthr_dbresume(const td_thrhandle_t *th) 237 { 238 ps_err_e err; 239 240 err = ps_lcontinue(th->th_ta->ta_ph, (lwpid_t)th->th_tid); 241 return ((err == PS_OK) ? TD_OK : TD_ERR); 242 } 243 244 static td_err_e 245 libthr_dbsuspend(const td_thrhandle_t *th) 246 { 247 ps_err_e err; 248 249 err = ps_lstop(th->th_ta->ta_ph, (lwpid_t)th->th_tid); 250 return ((err == PS_OK) ? TD_OK : TD_ERR); 251 } 252 253 static td_err_e 254 libthr_db_thr_event_enable(const td_thrhandle_t *th, int oo) 255 { 256 return (TD_ERR); 257 } 258 259 static td_err_e 260 libthr_db_thr_event_getmsg(const td_thrhandle_t *th, td_event_msg_t *msg) 261 { 262 return (TD_ERR); 263 } 264 265 static td_err_e 266 libthr_db_thr_get_info(const td_thrhandle_t *th, td_thrinfo_t *ti) 267 { 268 const td_thragent_t *ta; 269 psaddr_t addr; 270 thread_t tid; 271 ps_err_e err; 272 273 ta = th->th_ta; 274 ti->ti_ta_p = ta; 275 addr = (psaddr_t)((uintptr_t)th->th_thread + ta->ta_ofs_thr_id); 276 err = ps_pread(ta->ta_ph, addr, &tid, sizeof(thread_t)); 277 ti->ti_lid = tid; 278 ti->ti_tid = tid; 279 return ((err == PS_OK) ? TD_OK : TD_ERR); 280 } 281 282 static td_err_e 283 libthr_db_thr_getfpregs(const td_thrhandle_t *th, prfpregset_t *r) 284 { 285 const td_thragent_t *ta; 286 ps_err_e err; 287 288 ta = th->th_ta; 289 err = ps_lgetfpregs(ta->ta_ph, (lwpid_t)th->th_tid, r); 290 return ((err == PS_OK) ? TD_OK : TD_ERR); 291 } 292 293 static td_err_e 294 libthr_db_thr_getgregs(const td_thrhandle_t *th, prgregset_t r) 295 { 296 const td_thragent_t *ta; 297 psaddr_t addr; 298 ps_err_e err; 299 300 ta = th->th_ta; 301 err = ps_lgetregs(ta->ta_ph, (lwpid_t)th->th_tid, r); 302 return ((err == PS_OK) ? TD_OK : TD_ERR); 303 } 304 305 static td_err_e 306 libthr_db_thr_set_event(const td_thrhandle_t *th, td_thr_events_t *ev) 307 { 308 return (TD_ERR); 309 } 310 311 static td_err_e 312 libthr_db_thr_setfpregs(const td_thrhandle_t *th, const prfpregset_t *r) 313 { 314 ps_err_e err; 315 316 err = ps_lsetfpregs(th->th_ta->ta_ph, (lwpid_t)th->th_tid, r); 317 return ((err == PS_OK) ? TD_OK : TD_ERR); 318 } 319 320 static td_err_e 321 libthr_db_thr_setgregs(const td_thrhandle_t *th, const prgregset_t r) 322 { 323 ps_err_e err; 324 325 err = ps_lsetregs(th->th_ta->ta_ph, (lwpid_t)th->th_tid, r); 326 return ((err == PS_OK) ? TD_OK : TD_ERR); 327 } 328 329 static td_err_e 330 libthr_db_thr_validate(const td_thrhandle_t *th) 331 { 332 return (TD_ERR); 333 } 334 335 static td_err_e 336 libthr_db_sstep(const td_thrhandle_t *th, int step) 337 { 338 return (TD_OK); 339 } 340 341 struct ta_ops libthr_db_ops = { 342 .to_init = libthr_db_init, 343 344 .to_ta_clear_event = libthr_db_ta_clear_event, 345 .to_ta_delete = libthr_db_ta_delete, 346 .to_ta_event_addr = libthr_db_ta_event_addr, 347 .to_ta_event_getmsg = libthr_db_ta_event_getmsg, 348 .to_ta_map_id2thr = libthr_db_ta_map_id2thr, 349 .to_ta_map_lwp2thr = libthr_db_ta_map_lwp2thr, 350 .to_ta_new = libthr_db_ta_new, 351 .to_ta_set_event = libthr_db_ta_set_event, 352 .to_ta_thr_iter = libthr_db_ta_thr_iter, 353 .to_thr_clear_event = libthr_db_thr_clear_event, 354 .to_thr_dbresume = libthr_dbresume, 355 .to_thr_dbsuspend = libthr_dbsuspend, 356 .to_thr_event_enable = libthr_db_thr_event_enable, 357 .to_thr_event_getmsg = libthr_db_thr_event_getmsg, 358 .to_thr_get_info = libthr_db_thr_get_info, 359 .to_thr_getfpregs = libthr_db_thr_getfpregs, 360 .to_thr_getgregs = libthr_db_thr_getgregs, 361 .to_thr_set_event = libthr_db_thr_set_event, 362 .to_thr_setfpregs = libthr_db_thr_setfpregs, 363 .to_thr_setgregs = libthr_db_thr_setgregs, 364 .to_thr_validate = libthr_db_thr_validate, 365 366 /* FreeBSD specific extensions. */ 367 .to_thr_sstep = libthr_db_sstep 368 }; 369