thread_db.c revision 330897
1/*- 2 * SPDX-License-Identifier: BSD-2-Clause-FreeBSD 3 * 4 * Copyright (c) 2004 David Xu <davidxu@freebsd.org> 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 1. Redistributions of source code must retain the above copyright 11 * notice, this list of conditions and the following disclaimer. 12 * 2. Redistributions in binary form must reproduce the above copyright 13 * notice, this list of conditions and the following disclaimer in the 14 * documentation and/or other materials provided with the distribution. 15 * 16 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 17 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 19 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 20 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 22 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 23 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 24 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26 * SUCH DAMAGE. 27 */ 28 29#include <sys/cdefs.h> 30__FBSDID("$FreeBSD: stable/11/lib/libthread_db/thread_db.c 330897 2018-03-14 03:19:51Z eadler $"); 31 32#include <proc_service.h> 33#include <stddef.h> 34#include <thread_db.h> 35#include <unistd.h> 36#include <sys/cdefs.h> 37#include <sys/endian.h> 38#include <sys/errno.h> 39#include <sys/linker_set.h> 40 41#include "thread_db_int.h" 42 43struct td_thragent 44{ 45 TD_THRAGENT_FIELDS; 46}; 47 48static TAILQ_HEAD(, td_thragent) proclist = TAILQ_HEAD_INITIALIZER(proclist); 49 50SET_DECLARE(__ta_ops, struct ta_ops); 51 52td_err_e 53td_init(void) 54{ 55 td_err_e ret, tmp; 56 struct ta_ops *ops_p, **ops_pp; 57 58 ret = 0; 59 SET_FOREACH(ops_pp, __ta_ops) { 60 ops_p = *ops_pp; 61 if (ops_p->to_init != NULL) { 62 tmp = ops_p->to_init(); 63 if (tmp != TD_OK) 64 ret = tmp; 65 } 66 } 67 return (ret); 68} 69 70td_err_e 71td_ta_clear_event(const td_thragent_t *ta, td_thr_events_t *events) 72{ 73 return (ta->ta_ops->to_ta_clear_event(ta, events)); 74} 75 76td_err_e 77td_ta_delete(td_thragent_t *ta) 78{ 79 TAILQ_REMOVE(&proclist, ta, ta_next); 80 return (ta->ta_ops->to_ta_delete(ta)); 81} 82 83td_err_e 84td_ta_event_addr(const td_thragent_t *ta, td_event_e event, td_notify_t *ptr) 85{ 86 return (ta->ta_ops->to_ta_event_addr(ta, event, ptr)); 87} 88 89td_err_e 90td_ta_event_getmsg(const td_thragent_t *ta, td_event_msg_t *msg) 91{ 92 return (ta->ta_ops->to_ta_event_getmsg(ta, msg)); 93} 94 95td_err_e 96td_ta_map_id2thr(const td_thragent_t *ta, thread_t id, td_thrhandle_t *th) 97{ 98 return (ta->ta_ops->to_ta_map_id2thr(ta, id, th)); 99} 100 101td_err_e 102td_ta_map_lwp2thr(const td_thragent_t *ta, lwpid_t lwpid, td_thrhandle_t *th) 103{ 104 return (ta->ta_ops->to_ta_map_lwp2thr(ta, lwpid, th)); 105} 106 107td_err_e 108td_ta_new(struct ps_prochandle *ph, td_thragent_t **pta) 109{ 110 struct ta_ops *ops_p, **ops_pp; 111 112 SET_FOREACH(ops_pp, __ta_ops) { 113 ops_p = *ops_pp; 114 if (ops_p->to_ta_new(ph, pta) == TD_OK) { 115 TAILQ_INSERT_HEAD(&proclist, *pta, ta_next); 116 (*pta)->ta_ops = ops_p; 117 return (TD_OK); 118 } 119 } 120 return (TD_NOLIBTHREAD); 121} 122 123td_err_e 124td_ta_set_event(const td_thragent_t *ta, td_thr_events_t *events) 125{ 126 return (ta->ta_ops->to_ta_set_event(ta, events)); 127} 128 129td_err_e 130td_ta_thr_iter(const td_thragent_t *ta, td_thr_iter_f *callback, 131 void *cbdata_p, td_thr_state_e state, int ti_pri, sigset_t *ti_sigmask_p, 132 unsigned int ti_user_flags) 133{ 134 return (ta->ta_ops->to_ta_thr_iter(ta, callback, cbdata_p, state, 135 ti_pri, ti_sigmask_p, ti_user_flags)); 136} 137 138td_err_e 139td_ta_tsd_iter(const td_thragent_t *ta, td_key_iter_f *callback, 140 void *cbdata_p) 141{ 142 return (ta->ta_ops->to_ta_tsd_iter(ta, callback, cbdata_p)); 143} 144 145td_err_e 146td_thr_clear_event(const td_thrhandle_t *th, td_thr_events_t *events) 147{ 148 const td_thragent_t *ta = th->th_ta; 149 return (ta->ta_ops->to_thr_clear_event(th, events)); 150} 151 152td_err_e 153td_thr_dbresume(const td_thrhandle_t *th) 154{ 155 const td_thragent_t *ta = th->th_ta; 156 return (ta->ta_ops->to_thr_dbresume(th)); 157} 158 159td_err_e 160td_thr_dbsuspend(const td_thrhandle_t *th) 161{ 162 const td_thragent_t *ta = th->th_ta; 163 return (ta->ta_ops->to_thr_dbsuspend(th)); 164} 165 166td_err_e 167td_thr_event_enable(const td_thrhandle_t *th, int en) 168{ 169 const td_thragent_t *ta = th->th_ta; 170 return (ta->ta_ops->to_thr_event_enable(th, en)); 171} 172 173td_err_e 174td_thr_event_getmsg(const td_thrhandle_t *th, td_event_msg_t *msg) 175{ 176 const td_thragent_t *ta = th->th_ta; 177 return (ta->ta_ops->to_thr_event_getmsg(th, msg)); 178} 179 180td_err_e 181td_thr_old_get_info(const td_thrhandle_t *th, td_old_thrinfo_t *info) 182{ 183 const td_thragent_t *ta = th->th_ta; 184 return (ta->ta_ops->to_thr_old_get_info(th, info)); 185} 186__sym_compat(td_thr_get_info, td_thr_old_get_info, FBSD_1.0); 187 188td_err_e 189td_thr_get_info(const td_thrhandle_t *th, td_thrinfo_t *info) 190{ 191 const td_thragent_t *ta = th->th_ta; 192 return (ta->ta_ops->to_thr_get_info(th, info)); 193} 194 195#ifdef __i386__ 196td_err_e 197td_thr_getxmmregs(const td_thrhandle_t *th, char *fxsave) 198{ 199 const td_thragent_t *ta = th->th_ta; 200 return (ta->ta_ops->to_thr_getxmmregs(th, fxsave)); 201} 202#endif 203 204 205td_err_e 206td_thr_getfpregs(const td_thrhandle_t *th, prfpregset_t *fpregset) 207{ 208 const td_thragent_t *ta = th->th_ta; 209 return (ta->ta_ops->to_thr_getfpregs(th, fpregset)); 210} 211 212td_err_e 213td_thr_getgregs(const td_thrhandle_t *th, prgregset_t gregs) 214{ 215 const td_thragent_t *ta = th->th_ta; 216 return (ta->ta_ops->to_thr_getgregs(th, gregs)); 217} 218 219td_err_e 220td_thr_set_event(const td_thrhandle_t *th, td_thr_events_t *events) 221{ 222 const td_thragent_t *ta = th->th_ta; 223 return (ta->ta_ops->to_thr_set_event(th, events)); 224} 225 226#ifdef __i386__ 227td_err_e 228td_thr_setxmmregs(const td_thrhandle_t *th, const char *fxsave) 229{ 230 const td_thragent_t *ta = th->th_ta; 231 return (ta->ta_ops->to_thr_setxmmregs(th, fxsave)); 232} 233#endif 234 235td_err_e 236td_thr_setfpregs(const td_thrhandle_t *th, const prfpregset_t *fpregs) 237{ 238 const td_thragent_t *ta = th->th_ta; 239 return (ta->ta_ops->to_thr_setfpregs(th, fpregs)); 240} 241 242td_err_e 243td_thr_setgregs(const td_thrhandle_t *th, const prgregset_t gregs) 244{ 245 const td_thragent_t *ta = th->th_ta; 246 return (ta->ta_ops->to_thr_setgregs(th, gregs)); 247} 248 249td_err_e 250td_thr_validate(const td_thrhandle_t *th) 251{ 252 const td_thragent_t *ta = th->th_ta; 253 return (ta->ta_ops->to_thr_validate(th)); 254} 255 256td_err_e 257td_thr_tls_get_addr(const td_thrhandle_t *th, psaddr_t linkmap, size_t offset, 258 psaddr_t *address) 259{ 260 const td_thragent_t *ta = th->th_ta; 261 return (ta->ta_ops->to_thr_tls_get_addr(th, linkmap, offset, address)); 262} 263 264/* FreeBSD specific extensions. */ 265 266td_err_e 267td_thr_sstep(const td_thrhandle_t *th, int step) 268{ 269 const td_thragent_t *ta = th->th_ta; 270 return (ta->ta_ops->to_thr_sstep(th, step)); 271} 272 273/* 274 * Support functions for reading from and writing to the target 275 * address space. 276 */ 277 278static int 279thr_pread(struct ps_prochandle *ph, psaddr_t addr, uint64_t *val, 280 u_int size, u_int byteorder) 281{ 282 uint8_t buf[sizeof(*val)]; 283 ps_err_e err; 284 285 if (size > sizeof(buf)) 286 return (EOVERFLOW); 287 288 err = ps_pread(ph, addr, buf, size); 289 if (err != PS_OK) 290 return (EFAULT); 291 292 switch (byteorder) { 293 case BIG_ENDIAN: 294 switch (size) { 295 case 1: 296 *val = buf[0]; 297 break; 298 case 2: 299 *val = be16dec(buf); 300 break; 301 case 4: 302 *val = be32dec(buf); 303 break; 304 case 8: 305 *val = be64dec(buf); 306 break; 307 default: 308 return (EINVAL); 309 } 310 break; 311 case LITTLE_ENDIAN: 312 switch (size) { 313 case 1: 314 *val = buf[0]; 315 break; 316 case 2: 317 *val = le16dec(buf); 318 break; 319 case 4: 320 *val = le32dec(buf); 321 break; 322 case 8: 323 *val = le64dec(buf); 324 break; 325 default: 326 return (EINVAL); 327 } 328 break; 329 default: 330 return (EINVAL); 331 } 332 333 return (0); 334} 335 336int 337thr_pread_int(const struct td_thragent *ta, psaddr_t addr, uint32_t *val) 338{ 339 uint64_t tmp; 340 int error; 341 342 error = thr_pread(ta->ph, addr, &tmp, sizeof(int), BYTE_ORDER); 343 if (!error) 344 *val = tmp; 345 346 return (error); 347} 348 349int 350thr_pread_long(const struct td_thragent *ta, psaddr_t addr, uint64_t *val) 351{ 352 353 return (thr_pread(ta->ph, addr, val, sizeof(long), BYTE_ORDER)); 354} 355 356int 357thr_pread_ptr(const struct td_thragent *ta, psaddr_t addr, psaddr_t *val) 358{ 359 uint64_t tmp; 360 int error; 361 362 error = thr_pread(ta->ph, addr, &tmp, sizeof(void *), BYTE_ORDER); 363 if (!error) 364 *val = tmp; 365 366 return (error); 367} 368 369static int 370thr_pwrite(struct ps_prochandle *ph, psaddr_t addr, uint64_t val, 371 u_int size, u_int byteorder) 372{ 373 uint8_t buf[sizeof(val)]; 374 ps_err_e err; 375 376 if (size > sizeof(buf)) 377 return (EOVERFLOW); 378 379 switch (byteorder) { 380 case BIG_ENDIAN: 381 switch (size) { 382 case 1: 383 buf[0] = (uint8_t)val; 384 break; 385 case 2: 386 be16enc(buf, (uint16_t)val); 387 break; 388 case 4: 389 be32enc(buf, (uint32_t)val); 390 break; 391 case 8: 392 be64enc(buf, (uint64_t)val); 393 break; 394 default: 395 return (EINVAL); 396 } 397 break; 398 case LITTLE_ENDIAN: 399 switch (size) { 400 case 1: 401 buf[0] = (uint8_t)val; 402 break; 403 case 2: 404 le16enc(buf, (uint16_t)val); 405 break; 406 case 4: 407 le32enc(buf, (uint32_t)val); 408 break; 409 case 8: 410 le64enc(buf, (uint64_t)val); 411 break; 412 default: 413 return (EINVAL); 414 } 415 break; 416 default: 417 return (EINVAL); 418 } 419 420 err = ps_pwrite(ph, addr, buf, size); 421 return ((err != PS_OK) ? EFAULT : 0); 422} 423 424int 425thr_pwrite_int(const struct td_thragent *ta, psaddr_t addr, uint32_t val) 426{ 427 428 return (thr_pwrite(ta->ph, addr, val, sizeof(int), BYTE_ORDER)); 429} 430 431int 432thr_pwrite_long(const struct td_thragent *ta, psaddr_t addr, uint64_t val) 433{ 434 435 return (thr_pwrite(ta->ph, addr, val, sizeof(long), BYTE_ORDER)); 436} 437 438int 439thr_pwrite_ptr(const struct td_thragent *ta, psaddr_t addr, psaddr_t val) 440{ 441 442 return (thr_pwrite(ta->ph, addr, val, sizeof(void *), BYTE_ORDER)); 443} 444 445