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#include <sys/cdefs.h> 35#include <sys/endian.h> 36#include <sys/errno.h> 37#include <sys/linker_set.h> 38 39#include "thread_db_int.h" 40 41struct td_thragent 42{ 43 TD_THRAGENT_FIELDS; 44}; 45 46static TAILQ_HEAD(, td_thragent) proclist = TAILQ_HEAD_INITIALIZER(proclist); 47 48SET_DECLARE(__ta_ops, struct ta_ops); 49 50td_err_e 51td_init(void) 52{ 53 td_err_e ret, tmp; 54 struct ta_ops *ops_p, **ops_pp; 55 56 ret = 0; 57 SET_FOREACH(ops_pp, __ta_ops) { 58 ops_p = *ops_pp; 59 if (ops_p->to_init != NULL) { 60 tmp = ops_p->to_init(); 61 if (tmp != TD_OK) 62 ret = tmp; 63 } 64 } 65 return (ret); 66} 67 68td_err_e 69td_ta_clear_event(const td_thragent_t *ta, td_thr_events_t *events) 70{ 71 return (ta->ta_ops->to_ta_clear_event(ta, events)); 72} 73 74td_err_e 75td_ta_delete(td_thragent_t *ta) 76{ 77 TAILQ_REMOVE(&proclist, ta, ta_next); 78 return (ta->ta_ops->to_ta_delete(ta)); 79} 80 81td_err_e 82td_ta_event_addr(const td_thragent_t *ta, td_event_e event, td_notify_t *ptr) 83{ 84 return (ta->ta_ops->to_ta_event_addr(ta, event, ptr)); 85} 86 87td_err_e 88td_ta_event_getmsg(const td_thragent_t *ta, td_event_msg_t *msg) 89{ 90 return (ta->ta_ops->to_ta_event_getmsg(ta, msg)); 91} 92 93td_err_e 94td_ta_map_id2thr(const td_thragent_t *ta, thread_t id, td_thrhandle_t *th) 95{ 96 return (ta->ta_ops->to_ta_map_id2thr(ta, id, th)); 97} 98 99td_err_e 100td_ta_map_lwp2thr(const td_thragent_t *ta, lwpid_t lwpid, td_thrhandle_t *th) 101{ 102 return (ta->ta_ops->to_ta_map_lwp2thr(ta, lwpid, th)); 103} 104 105td_err_e 106td_ta_new(struct ps_prochandle *ph, td_thragent_t **pta) 107{ 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_old_get_info(const td_thrhandle_t *th, td_old_thrinfo_t *info) 180{ 181 const td_thragent_t *ta = th->th_ta; 182 return (ta->ta_ops->to_thr_old_get_info(th, info)); 183} 184__sym_compat(td_thr_get_info, td_thr_old_get_info, FBSD_1.0); 185 186td_err_e 187td_thr_get_info(const td_thrhandle_t *th, td_thrinfo_t *info) 188{ 189 const td_thragent_t *ta = th->th_ta; 190 return (ta->ta_ops->to_thr_get_info(th, info)); 191} 192 193#ifdef __i386__ 194td_err_e 195td_thr_getxmmregs(const td_thrhandle_t *th, char *fxsave) 196{ 197 const td_thragent_t *ta = th->th_ta; 198 return (ta->ta_ops->to_thr_getxmmregs(th, fxsave)); 199} 200#endif 201 202 203td_err_e 204td_thr_getfpregs(const td_thrhandle_t *th, prfpregset_t *fpregset) 205{ 206 const td_thragent_t *ta = th->th_ta; 207 return (ta->ta_ops->to_thr_getfpregs(th, fpregset)); 208} 209 210td_err_e 211td_thr_getgregs(const td_thrhandle_t *th, prgregset_t gregs) 212{ 213 const td_thragent_t *ta = th->th_ta; 214 return (ta->ta_ops->to_thr_getgregs(th, gregs)); 215} 216 217td_err_e 218td_thr_set_event(const td_thrhandle_t *th, td_thr_events_t *events) 219{ 220 const td_thragent_t *ta = th->th_ta; 221 return (ta->ta_ops->to_thr_set_event(th, events)); 222} 223 224#ifdef __i386__ 225td_err_e 226td_thr_setxmmregs(const td_thrhandle_t *th, const char *fxsave) 227{ 228 const td_thragent_t *ta = th->th_ta; 229 return (ta->ta_ops->to_thr_setxmmregs(th, fxsave)); 230} 231#endif 232 233td_err_e 234td_thr_setfpregs(const td_thrhandle_t *th, const prfpregset_t *fpregs) 235{ 236 const td_thragent_t *ta = th->th_ta; 237 return (ta->ta_ops->to_thr_setfpregs(th, fpregs)); 238} 239 240td_err_e 241td_thr_setgregs(const td_thrhandle_t *th, const prgregset_t gregs) 242{ 243 const td_thragent_t *ta = th->th_ta; 244 return (ta->ta_ops->to_thr_setgregs(th, gregs)); 245} 246 247td_err_e 248td_thr_validate(const td_thrhandle_t *th) 249{ 250 const td_thragent_t *ta = th->th_ta; 251 return (ta->ta_ops->to_thr_validate(th)); 252} 253 254td_err_e 255td_thr_tls_get_addr(const td_thrhandle_t *th, psaddr_t linkmap, size_t offset, 256 psaddr_t *address) 257{ 258 const td_thragent_t *ta = th->th_ta; 259 return (ta->ta_ops->to_thr_tls_get_addr(th, linkmap, offset, address)); 260} 261 262/* FreeBSD specific extensions. */ 263 264td_err_e 265td_thr_sstep(const td_thrhandle_t *th, int step) 266{ 267 const td_thragent_t *ta = th->th_ta; 268 return (ta->ta_ops->to_thr_sstep(th, step)); 269} 270 271/* 272 * Support functions for reading from and writing to the target 273 * address space. 274 */ 275 276static int 277thr_pread(struct ps_prochandle *ph, psaddr_t addr, uint64_t *val, 278 u_int size, u_int byteorder) 279{ 280 uint8_t buf[sizeof(*val)]; 281 ps_err_e err; 282 283 if (size > sizeof(buf)) 284 return (EOVERFLOW); 285 286 err = ps_pread(ph, addr, buf, size); 287 if (err != PS_OK) 288 return (EFAULT); 289 290 switch (byteorder) { 291 case BIG_ENDIAN: 292 switch (size) { 293 case 1: 294 *val = buf[0]; 295 break; 296 case 2: 297 *val = be16dec(buf); 298 break; 299 case 4: 300 *val = be32dec(buf); 301 break; 302 case 8: 303 *val = be64dec(buf); 304 break; 305 default: 306 return (EINVAL); 307 } 308 break; 309 case LITTLE_ENDIAN: 310 switch (size) { 311 case 1: 312 *val = buf[0]; 313 break; 314 case 2: 315 *val = le16dec(buf); 316 break; 317 case 4: 318 *val = le32dec(buf); 319 break; 320 case 8: 321 *val = le64dec(buf); 322 break; 323 default: 324 return (EINVAL); 325 } 326 break; 327 default: 328 return (EINVAL); 329 } 330 331 return (0); 332} 333 334int 335thr_pread_int(const struct td_thragent *ta, psaddr_t addr, uint32_t *val) 336{ 337 uint64_t tmp; 338 int error; 339 340 error = thr_pread(ta->ph, addr, &tmp, sizeof(int), BYTE_ORDER); 341 if (!error) 342 *val = tmp; 343 344 return (error); 345} 346 347int 348thr_pread_long(const struct td_thragent *ta, psaddr_t addr, uint64_t *val) 349{ 350 351 return (thr_pread(ta->ph, addr, val, sizeof(long), BYTE_ORDER)); 352} 353 354int 355thr_pread_ptr(const struct td_thragent *ta, psaddr_t addr, psaddr_t *val) 356{ 357 uint64_t tmp; 358 int error; 359 360 error = thr_pread(ta->ph, addr, &tmp, sizeof(void *), BYTE_ORDER); 361 if (!error) 362 *val = tmp; 363 364 return (error); 365} 366 367static int 368thr_pwrite(struct ps_prochandle *ph, psaddr_t addr, uint64_t val, 369 u_int size, u_int byteorder) 370{ 371 uint8_t buf[sizeof(val)]; 372 ps_err_e err; 373 374 if (size > sizeof(buf)) 375 return (EOVERFLOW); 376 377 switch (byteorder) { 378 case BIG_ENDIAN: 379 switch (size) { 380 case 1: 381 buf[0] = (uint8_t)val; 382 break; 383 case 2: 384 be16enc(buf, (uint16_t)val); 385 break; 386 case 4: 387 be32enc(buf, (uint32_t)val); 388 break; 389 case 8: 390 be64enc(buf, (uint64_t)val); 391 break; 392 default: 393 return (EINVAL); 394 } 395 break; 396 case LITTLE_ENDIAN: 397 switch (size) { 398 case 1: 399 buf[0] = (uint8_t)val; 400 break; 401 case 2: 402 le16enc(buf, (uint16_t)val); 403 break; 404 case 4: 405 le32enc(buf, (uint32_t)val); 406 break; 407 case 8: 408 le64enc(buf, (uint64_t)val); 409 break; 410 default: 411 return (EINVAL); 412 } 413 break; 414 default: 415 return (EINVAL); 416 } 417 418 err = ps_pwrite(ph, addr, buf, size); 419 return ((err != PS_OK) ? EFAULT : 0); 420} 421 422int 423thr_pwrite_int(const struct td_thragent *ta, psaddr_t addr, uint32_t val) 424{ 425 426 return (thr_pwrite(ta->ph, addr, val, sizeof(int), BYTE_ORDER)); 427} 428 429int 430thr_pwrite_long(const struct td_thragent *ta, psaddr_t addr, uint64_t val) 431{ 432 433 return (thr_pwrite(ta->ph, addr, val, sizeof(long), BYTE_ORDER)); 434} 435 436int 437thr_pwrite_ptr(const struct td_thragent *ta, psaddr_t addr, psaddr_t val) 438{ 439 440 return (thr_pwrite(ta->ph, addr, val, sizeof(void *), BYTE_ORDER)); 441} 442 443