1 /*- 2 * SPDX-License-Identifier: BSD-2-Clause 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$"); 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 43 struct td_thragent 44 { 45 TD_THRAGENT_FIELDS; 46 }; 47 48 static TAILQ_HEAD(, td_thragent) proclist = TAILQ_HEAD_INITIALIZER(proclist); 49 50 SET_DECLARE(__ta_ops, struct ta_ops); 51 52 td_err_e 53 td_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 70 td_err_e 71 td_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 76 td_err_e 77 td_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 83 td_err_e 84 td_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 89 td_err_e 90 td_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 95 td_err_e 96 td_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 101 td_err_e 102 td_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 107 td_err_e 108 td_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 123 td_err_e 124 td_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 129 td_err_e 130 td_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 138 td_err_e 139 td_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 145 td_err_e 146 td_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 152 td_err_e 153 td_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 159 td_err_e 160 td_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 166 td_err_e 167 td_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 173 td_err_e 174 td_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 180 td_err_e 181 td_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 188 td_err_e 189 td_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__ 196 td_err_e 197 td_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 205 td_err_e 206 td_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 212 td_err_e 213 td_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 219 td_err_e 220 td_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__ 227 td_err_e 228 td_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 235 td_err_e 236 td_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 242 td_err_e 243 td_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 249 td_err_e 250 td_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 256 td_err_e 257 td_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 266 td_err_e 267 td_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 278 static int 279 thr_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 336 int 337 thr_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 349 int 350 thr_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 356 int 357 thr_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 369 static int 370 thr_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 424 int 425 thr_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 431 int 432 thr_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 438 int 439 thr_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