thread_db.c revision 181065
1132332Smarcel/* 2132332Smarcel * Copyright (c) 2004 David Xu <davidxu@freebsd.org> 3132332Smarcel * All rights reserved. 4132332Smarcel * 5132332Smarcel * Redistribution and use in source and binary forms, with or without 6132332Smarcel * modification, are permitted provided that the following conditions 7132332Smarcel * are met: 8132332Smarcel * 1. Redistributions of source code must retain the above copyright 9132332Smarcel * notice, this list of conditions and the following disclaimer. 10132332Smarcel * 2. Redistributions in binary form must reproduce the above copyright 11132332Smarcel * notice, this list of conditions and the following disclaimer in the 12132332Smarcel * documentation and/or other materials provided with the distribution. 13132332Smarcel * 14132332Smarcel * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 15132332Smarcel * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16132332Smarcel * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17132332Smarcel * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 18132332Smarcel * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 19132332Smarcel * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 20132332Smarcel * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 21132332Smarcel * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 22132332Smarcel * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 23132332Smarcel * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 24132332Smarcel * SUCH DAMAGE. 25132332Smarcel */ 26132332Smarcel 27132332Smarcel#include <sys/cdefs.h> 28132332Smarcel__FBSDID("$FreeBSD: head/lib/libthread_db/thread_db.c 181065 2008-07-31 20:25:52Z marcel $"); 29132332Smarcel 30132332Smarcel#include <proc_service.h> 31132332Smarcel#include <stddef.h> 32132332Smarcel#include <thread_db.h> 33132332Smarcel#include <unistd.h> 34177490Sdavidxu#include <sys/cdefs.h> 35181065Smarcel#include <sys/endian.h> 36181065Smarcel#include <sys/errno.h> 37177490Sdavidxu#include <sys/linker_set.h> 38132332Smarcel 39132332Smarcel#include "thread_db_int.h" 40132332Smarcel 41132332Smarcelstruct td_thragent 42132332Smarcel{ 43132332Smarcel TD_THRAGENT_FIELDS; 44132332Smarcel}; 45132332Smarcel 46132332Smarcelstatic TAILQ_HEAD(, td_thragent) proclist = TAILQ_HEAD_INITIALIZER(proclist); 47132332Smarcel 48177490SdavidxuSET_DECLARE(__ta_ops, struct ta_ops); 49132332Smarcel 50132332Smarceltd_err_e 51132332Smarceltd_init(void) 52132332Smarcel{ 53132332Smarcel td_err_e ret, tmp; 54177490Sdavidxu struct ta_ops *ops_p, **ops_pp; 55132332Smarcel 56132332Smarcel ret = 0; 57177490Sdavidxu SET_FOREACH(ops_pp, __ta_ops) { 58177490Sdavidxu ops_p = *ops_pp; 59177490Sdavidxu if (ops_p->to_init != NULL) { 60177490Sdavidxu tmp = ops_p->to_init(); 61132332Smarcel if (tmp != TD_OK) 62132332Smarcel ret = tmp; 63132332Smarcel } 64132332Smarcel } 65132332Smarcel return (ret); 66132332Smarcel} 67132332Smarcel 68132332Smarceltd_err_e 69132332Smarceltd_ta_clear_event(const td_thragent_t *ta, td_thr_events_t *events) 70132332Smarcel{ 71132332Smarcel return (ta->ta_ops->to_ta_clear_event(ta, events)); 72132332Smarcel} 73132332Smarcel 74132332Smarceltd_err_e 75132332Smarceltd_ta_delete(td_thragent_t *ta) 76132332Smarcel{ 77132332Smarcel TAILQ_REMOVE(&proclist, ta, ta_next); 78132332Smarcel return (ta->ta_ops->to_ta_delete(ta)); 79132332Smarcel} 80132332Smarcel 81132332Smarceltd_err_e 82132332Smarceltd_ta_event_addr(const td_thragent_t *ta, td_event_e event, td_notify_t *ptr) 83132332Smarcel{ 84132332Smarcel return (ta->ta_ops->to_ta_event_addr(ta, event, ptr)); 85132332Smarcel} 86132332Smarcel 87132332Smarceltd_err_e 88132332Smarceltd_ta_event_getmsg(const td_thragent_t *ta, td_event_msg_t *msg) 89132332Smarcel{ 90132332Smarcel return (ta->ta_ops->to_ta_event_getmsg(ta, msg)); 91132332Smarcel} 92132332Smarcel 93132332Smarceltd_err_e 94132332Smarceltd_ta_map_id2thr(const td_thragent_t *ta, thread_t id, td_thrhandle_t *th) 95132332Smarcel{ 96132332Smarcel return (ta->ta_ops->to_ta_map_id2thr(ta, id, th)); 97132332Smarcel} 98132332Smarcel 99132332Smarceltd_err_e 100132332Smarceltd_ta_map_lwp2thr(const td_thragent_t *ta, lwpid_t lwpid, td_thrhandle_t *th) 101132332Smarcel{ 102132332Smarcel return (ta->ta_ops->to_ta_map_lwp2thr(ta, lwpid, th)); 103132332Smarcel} 104132332Smarcel 105132332Smarceltd_err_e 106132332Smarceltd_ta_new(struct ps_prochandle *ph, td_thragent_t **pta) 107132332Smarcel{ 108177490Sdavidxu struct ta_ops *ops_p, **ops_pp; 109132332Smarcel 110177490Sdavidxu SET_FOREACH(ops_pp, __ta_ops) { 111177490Sdavidxu ops_p = *ops_pp; 112177490Sdavidxu if (ops_p->to_ta_new(ph, pta) == TD_OK) { 113132332Smarcel TAILQ_INSERT_HEAD(&proclist, *pta, ta_next); 114177490Sdavidxu (*pta)->ta_ops = ops_p; 115132332Smarcel return (TD_OK); 116132332Smarcel } 117132332Smarcel } 118132332Smarcel return (TD_NOLIBTHREAD); 119132332Smarcel} 120132332Smarcel 121132332Smarceltd_err_e 122132332Smarceltd_ta_set_event(const td_thragent_t *ta, td_thr_events_t *events) 123132332Smarcel{ 124132332Smarcel return (ta->ta_ops->to_ta_set_event(ta, events)); 125132332Smarcel} 126132332Smarcel 127132332Smarceltd_err_e 128132332Smarceltd_ta_thr_iter(const td_thragent_t *ta, td_thr_iter_f *callback, 129132332Smarcel void *cbdata_p, td_thr_state_e state, int ti_pri, sigset_t *ti_sigmask_p, 130132332Smarcel unsigned int ti_user_flags) 131132332Smarcel{ 132132332Smarcel return (ta->ta_ops->to_ta_thr_iter(ta, callback, cbdata_p, state, 133132332Smarcel ti_pri, ti_sigmask_p, ti_user_flags)); 134132332Smarcel} 135132332Smarcel 136132332Smarceltd_err_e 137132332Smarceltd_ta_tsd_iter(const td_thragent_t *ta, td_key_iter_f *callback, 138132332Smarcel void *cbdata_p) 139132332Smarcel{ 140132332Smarcel return (ta->ta_ops->to_ta_tsd_iter(ta, callback, cbdata_p)); 141132332Smarcel} 142132332Smarcel 143132332Smarceltd_err_e 144132332Smarceltd_thr_clear_event(const td_thrhandle_t *th, td_thr_events_t *events) 145132332Smarcel{ 146132332Smarcel const td_thragent_t *ta = th->th_ta; 147132332Smarcel return (ta->ta_ops->to_thr_clear_event(th, events)); 148132332Smarcel} 149132332Smarcel 150132332Smarceltd_err_e 151132332Smarceltd_thr_dbresume(const td_thrhandle_t *th) 152132332Smarcel{ 153132332Smarcel const td_thragent_t *ta = th->th_ta; 154132332Smarcel return (ta->ta_ops->to_thr_dbresume(th)); 155132332Smarcel} 156132332Smarcel 157132332Smarceltd_err_e 158132332Smarceltd_thr_dbsuspend(const td_thrhandle_t *th) 159132332Smarcel{ 160132332Smarcel const td_thragent_t *ta = th->th_ta; 161132332Smarcel return (ta->ta_ops->to_thr_dbsuspend(th)); 162132332Smarcel} 163132332Smarcel 164132332Smarceltd_err_e 165132332Smarceltd_thr_event_enable(const td_thrhandle_t *th, int en) 166132332Smarcel{ 167132332Smarcel const td_thragent_t *ta = th->th_ta; 168132332Smarcel return (ta->ta_ops->to_thr_event_enable(th, en)); 169132332Smarcel} 170132332Smarcel 171132332Smarceltd_err_e 172132332Smarceltd_thr_event_getmsg(const td_thrhandle_t *th, td_event_msg_t *msg) 173132332Smarcel{ 174132332Smarcel const td_thragent_t *ta = th->th_ta; 175132332Smarcel return (ta->ta_ops->to_thr_event_getmsg(th, msg)); 176132332Smarcel} 177132332Smarcel 178132332Smarceltd_err_e 179132332Smarceltd_thr_get_info(const td_thrhandle_t *th, td_thrinfo_t *info) 180132332Smarcel{ 181132332Smarcel const td_thragent_t *ta = th->th_ta; 182132332Smarcel return (ta->ta_ops->to_thr_get_info(th, info)); 183132332Smarcel} 184132332Smarcel 185146818Sdfr#ifdef __i386__ 186132332Smarceltd_err_e 187146818Sdfrtd_thr_getxmmregs(const td_thrhandle_t *th, char *fxsave) 188146818Sdfr{ 189146818Sdfr const td_thragent_t *ta = th->th_ta; 190146818Sdfr return (ta->ta_ops->to_thr_getxmmregs(th, fxsave)); 191146818Sdfr} 192146818Sdfr#endif 193146818Sdfr 194146818Sdfr 195146818Sdfrtd_err_e 196132332Smarceltd_thr_getfpregs(const td_thrhandle_t *th, prfpregset_t *fpregset) 197132332Smarcel{ 198132332Smarcel const td_thragent_t *ta = th->th_ta; 199132332Smarcel return (ta->ta_ops->to_thr_getfpregs(th, fpregset)); 200132332Smarcel} 201132332Smarcel 202132332Smarceltd_err_e 203132332Smarceltd_thr_getgregs(const td_thrhandle_t *th, prgregset_t gregs) 204132332Smarcel{ 205132332Smarcel const td_thragent_t *ta = th->th_ta; 206132332Smarcel return (ta->ta_ops->to_thr_getgregs(th, gregs)); 207132332Smarcel} 208132332Smarcel 209132332Smarceltd_err_e 210132332Smarceltd_thr_set_event(const td_thrhandle_t *th, td_thr_events_t *events) 211132332Smarcel{ 212132332Smarcel const td_thragent_t *ta = th->th_ta; 213132332Smarcel return (ta->ta_ops->to_thr_set_event(th, events)); 214132332Smarcel} 215132332Smarcel 216146818Sdfr#ifdef __i386__ 217132332Smarceltd_err_e 218146818Sdfrtd_thr_setxmmregs(const td_thrhandle_t *th, const char *fxsave) 219146818Sdfr{ 220146818Sdfr const td_thragent_t *ta = th->th_ta; 221146818Sdfr return (ta->ta_ops->to_thr_setxmmregs(th, fxsave)); 222146818Sdfr} 223146818Sdfr#endif 224146818Sdfr 225146818Sdfrtd_err_e 226132332Smarceltd_thr_setfpregs(const td_thrhandle_t *th, const prfpregset_t *fpregs) 227132332Smarcel{ 228132332Smarcel const td_thragent_t *ta = th->th_ta; 229132332Smarcel return (ta->ta_ops->to_thr_setfpregs(th, fpregs)); 230132332Smarcel} 231132332Smarcel 232132332Smarceltd_err_e 233132332Smarceltd_thr_setgregs(const td_thrhandle_t *th, const prgregset_t gregs) 234132332Smarcel{ 235132332Smarcel const td_thragent_t *ta = th->th_ta; 236132332Smarcel return (ta->ta_ops->to_thr_setgregs(th, gregs)); 237132332Smarcel} 238132332Smarcel 239132332Smarceltd_err_e 240132332Smarceltd_thr_validate(const td_thrhandle_t *th) 241132332Smarcel{ 242132332Smarcel const td_thragent_t *ta = th->th_ta; 243132332Smarcel return (ta->ta_ops->to_thr_validate(th)); 244132332Smarcel} 245132332Smarcel 246133342Sdavidxutd_err_e 247180982Smarceltd_thr_tls_get_addr(const td_thrhandle_t *th, psaddr_t linkmap, size_t offset, 248180982Smarcel psaddr_t *address) 249133342Sdavidxu{ 250133342Sdavidxu const td_thragent_t *ta = th->th_ta; 251133342Sdavidxu return (ta->ta_ops->to_thr_tls_get_addr(th, linkmap, offset, address)); 252133342Sdavidxu} 253133342Sdavidxu 254132332Smarcel/* FreeBSD specific extensions. */ 255132332Smarcel 256132332Smarceltd_err_e 257132332Smarceltd_thr_sstep(const td_thrhandle_t *th, int step) 258132332Smarcel{ 259132332Smarcel const td_thragent_t *ta = th->th_ta; 260132332Smarcel return (ta->ta_ops->to_thr_sstep(th, step)); 261132332Smarcel} 262181065Smarcel 263181065Smarcel/* 264181065Smarcel * Support functions for reading from and writing to the target 265181065Smarcel * address space. 266181065Smarcel */ 267181065Smarcel 268181065Smarcelstatic int 269181065Smarcelthr_pread(struct ps_prochandle *ph, psaddr_t addr, uint64_t *val, 270181065Smarcel u_int size, u_int byteorder) 271181065Smarcel{ 272181065Smarcel uint8_t buf[sizeof(*val)]; 273181065Smarcel ps_err_e err; 274181065Smarcel 275181065Smarcel if (size > sizeof(buf)) 276181065Smarcel return (EOVERFLOW); 277181065Smarcel 278181065Smarcel err = ps_pread(ph, addr, buf, size); 279181065Smarcel if (err != PS_OK) 280181065Smarcel return (EFAULT); 281181065Smarcel 282181065Smarcel switch (byteorder) { 283181065Smarcel case BIG_ENDIAN: 284181065Smarcel switch (size) { 285181065Smarcel case 1: 286181065Smarcel *val = buf[0]; 287181065Smarcel break; 288181065Smarcel case 2: 289181065Smarcel *val = be16dec(buf); 290181065Smarcel break; 291181065Smarcel case 4: 292181065Smarcel *val = be32dec(buf); 293181065Smarcel break; 294181065Smarcel case 8: 295181065Smarcel *val = be64dec(buf); 296181065Smarcel break; 297181065Smarcel default: 298181065Smarcel return (EINVAL); 299181065Smarcel } 300181065Smarcel break; 301181065Smarcel case LITTLE_ENDIAN: 302181065Smarcel switch (size) { 303181065Smarcel case 1: 304181065Smarcel *val = buf[0]; 305181065Smarcel break; 306181065Smarcel case 2: 307181065Smarcel *val = le16dec(buf); 308181065Smarcel break; 309181065Smarcel case 4: 310181065Smarcel *val = le32dec(buf); 311181065Smarcel break; 312181065Smarcel case 8: 313181065Smarcel *val = le64dec(buf); 314181065Smarcel break; 315181065Smarcel default: 316181065Smarcel return (EINVAL); 317181065Smarcel } 318181065Smarcel break; 319181065Smarcel default: 320181065Smarcel return (EINVAL); 321181065Smarcel } 322181065Smarcel 323181065Smarcel return (0); 324181065Smarcel} 325181065Smarcel 326181065Smarcelint 327181065Smarcelthr_pread_int(struct td_thragent *ta, psaddr_t addr, uint32_t *val) 328181065Smarcel{ 329181065Smarcel uint64_t tmp; 330181065Smarcel int error; 331181065Smarcel 332181065Smarcel error = thr_pread(ta->ph, addr, &tmp, sizeof(int), BYTE_ORDER); 333181065Smarcel if (!error) 334181065Smarcel *val = tmp; 335181065Smarcel 336181065Smarcel return (error); 337181065Smarcel} 338181065Smarcel 339181065Smarcelint 340181065Smarcelthr_pread_long(struct td_thragent *ta, psaddr_t addr, uint64_t *val) 341181065Smarcel{ 342181065Smarcel 343181065Smarcel return (thr_pread(ta->ph, addr, val, sizeof(long), BYTE_ORDER)); 344181065Smarcel} 345181065Smarcel 346181065Smarcelint 347181065Smarcelthr_pread_ptr(struct td_thragent *ta, psaddr_t addr, uint64_t *val) 348181065Smarcel{ 349181065Smarcel 350181065Smarcel return (thr_pread(ta->ph, addr, val, sizeof(void *), BYTE_ORDER)); 351181065Smarcel} 352181065Smarcel 353181065Smarcelstatic int 354181065Smarcelthr_pwrite(struct ps_prochandle *ph, psaddr_t addr, uint64_t val, 355181065Smarcel u_int size, u_int byteorder) 356181065Smarcel{ 357181065Smarcel uint8_t buf[sizeof(val)]; 358181065Smarcel ps_err_e err; 359181065Smarcel 360181065Smarcel if (size > sizeof(buf)) 361181065Smarcel return (EOVERFLOW); 362181065Smarcel 363181065Smarcel switch (byteorder) { 364181065Smarcel case BIG_ENDIAN: 365181065Smarcel switch (size) { 366181065Smarcel case 1: 367181065Smarcel buf[0] = (uint8_t)val; 368181065Smarcel break; 369181065Smarcel case 2: 370181065Smarcel be16enc(buf, (uint16_t)val); 371181065Smarcel break; 372181065Smarcel case 4: 373181065Smarcel be32enc(buf, (uint32_t)val); 374181065Smarcel break; 375181065Smarcel case 8: 376181065Smarcel be64enc(buf, (uint64_t)val); 377181065Smarcel break; 378181065Smarcel default: 379181065Smarcel return (EINVAL); 380181065Smarcel } 381181065Smarcel break; 382181065Smarcel case LITTLE_ENDIAN: 383181065Smarcel switch (size) { 384181065Smarcel case 1: 385181065Smarcel buf[0] = (uint8_t)val; 386181065Smarcel break; 387181065Smarcel case 2: 388181065Smarcel le16enc(buf, (uint16_t)val); 389181065Smarcel break; 390181065Smarcel case 4: 391181065Smarcel le32enc(buf, (uint32_t)val); 392181065Smarcel break; 393181065Smarcel case 8: 394181065Smarcel le64enc(buf, (uint64_t)val); 395181065Smarcel break; 396181065Smarcel default: 397181065Smarcel return (EINVAL); 398181065Smarcel } 399181065Smarcel break; 400181065Smarcel default: 401181065Smarcel return (EINVAL); 402181065Smarcel } 403181065Smarcel 404181065Smarcel err = ps_pwrite(ph, addr, buf, size); 405181065Smarcel return ((err != PS_OK) ? EFAULT : 0); 406181065Smarcel} 407181065Smarcel 408181065Smarcelint 409181065Smarcelthr_pwrite_int(struct td_thragent *ta, psaddr_t addr, uint32_t val) 410181065Smarcel{ 411181065Smarcel 412181065Smarcel return (thr_pwrite(ta->ph, addr, val, sizeof(int), BYTE_ORDER)); 413181065Smarcel} 414181065Smarcel 415181065Smarcelint 416181065Smarcelthr_pwrite_long(struct td_thragent *ta, psaddr_t addr, uint64_t val) 417181065Smarcel{ 418181065Smarcel 419181065Smarcel return (thr_pwrite(ta->ph, addr, val, sizeof(long), BYTE_ORDER)); 420181065Smarcel} 421181065Smarcel 422181065Smarcelint 423181065Smarcelthr_pwrite_ptr(struct td_thragent *ta, psaddr_t addr, uint64_t val) 424181065Smarcel{ 425181065Smarcel 426181065Smarcel return (thr_pwrite(ta->ph, addr, val, sizeof(void *), BYTE_ORDER)); 427181065Smarcel} 428181065Smarcel 429