libthr_db.c revision 133631
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: head/lib/libthread_db/libthr_db.c 133631 2004-08-13 06:47:33Z davidxu $"); 29 30#include <proc_service.h> 31#include <stdlib.h> 32#include <thread_db.h> 33 34#include "thread_db_int.h" 35 36struct 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 45static td_err_e 46libthr_db_init() 47{ 48 return (TD_OK); 49} 50 51static td_err_e 52libthr_db_ta_clear_event(const td_thragent_t *ta, td_thr_events_t *ev) 53{ 54 return (TD_ERR); 55} 56 57static td_err_e 58libthr_db_ta_delete(td_thragent_t *ta) 59{ 60 free(ta); 61 return (TD_OK); 62} 63 64static td_err_e 65libthr_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 71static td_err_e 72libthr_db_ta_event_getmsg(const td_thragent_t *ta, td_event_msg_t *msg) 73{ 74 return (TD_ERR); 75} 76 77static td_err_e 78libthr_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 111static td_err_e 112libthr_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 144static td_err_e 145libthr_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 192static td_err_e 193libthr_db_ta_set_event(const td_thragent_t *ta, td_thr_events_t *ev) 194{ 195 return (TD_ERR); 196} 197 198static td_err_e 199libthr_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 229static td_err_e 230libthr_db_thr_clear_event(const td_thrhandle_t *th, td_thr_events_t *ev) 231{ 232 return (TD_ERR); 233} 234 235static td_err_e 236libthr_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 244static td_err_e 245libthr_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 253static td_err_e 254libthr_db_thr_event_enable(const td_thrhandle_t *th, int oo) 255{ 256 return (TD_ERR); 257} 258 259static td_err_e 260libthr_db_thr_event_getmsg(const td_thrhandle_t *th, td_event_msg_t *msg) 261{ 262 return (TD_ERR); 263} 264 265static td_err_e 266libthr_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 282static td_err_e 283libthr_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 293static td_err_e 294libthr_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 305static td_err_e 306libthr_db_thr_set_event(const td_thrhandle_t *th, td_thr_events_t *ev) 307{ 308 return (TD_ERR); 309} 310 311static td_err_e 312libthr_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 320static td_err_e 321libthr_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 329static td_err_e 330libthr_db_thr_validate(const td_thrhandle_t *th) 331{ 332 return (TD_ERR); 333} 334 335static td_err_e 336libthr_db_sstep(const td_thrhandle_t *th, int step) 337{ 338 return (TD_OK); 339} 340 341struct 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