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 41 struct td_thragent 42 { 43 TD_THRAGENT_FIELDS; 44 }; 45 46 static TAILQ_HEAD(, td_thragent) proclist = TAILQ_HEAD_INITIALIZER(proclist); 47 48 SET_DECLARE(__ta_ops, struct ta_ops); 49 50 td_err_e 51 td_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 68 td_err_e 69 td_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 74 td_err_e 75 td_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 81 td_err_e 82 td_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 87 td_err_e 88 td_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 93 td_err_e 94 td_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 99 td_err_e 100 td_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 105 td_err_e 106 td_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 121 td_err_e 122 td_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 127 td_err_e 128 td_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 136 td_err_e 137 td_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 143 td_err_e 144 td_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 150 td_err_e 151 td_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 157 td_err_e 158 td_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 164 td_err_e 165 td_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 171 td_err_e 172 td_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 178 td_err_e 179 td_thr_get_info(const td_thrhandle_t *th, td_thrinfo_t *info) 180 { 181 const td_thragent_t *ta = th->th_ta; 182 return (ta->ta_ops->to_thr_get_info(th, info)); 183 } 184 185 #ifdef __i386__ 186 td_err_e 187 td_thr_getxmmregs(const td_thrhandle_t *th, char *fxsave) 188 { 189 const td_thragent_t *ta = th->th_ta; 190 return (ta->ta_ops->to_thr_getxmmregs(th, fxsave)); 191 } 192 #endif 193 194 195 td_err_e 196 td_thr_getfpregs(const td_thrhandle_t *th, prfpregset_t *fpregset) 197 { 198 const td_thragent_t *ta = th->th_ta; 199 return (ta->ta_ops->to_thr_getfpregs(th, fpregset)); 200 } 201 202 td_err_e 203 td_thr_getgregs(const td_thrhandle_t *th, prgregset_t gregs) 204 { 205 const td_thragent_t *ta = th->th_ta; 206 return (ta->ta_ops->to_thr_getgregs(th, gregs)); 207 } 208 209 td_err_e 210 td_thr_set_event(const td_thrhandle_t *th, td_thr_events_t *events) 211 { 212 const td_thragent_t *ta = th->th_ta; 213 return (ta->ta_ops->to_thr_set_event(th, events)); 214 } 215 216 #ifdef __i386__ 217 td_err_e 218 td_thr_setxmmregs(const td_thrhandle_t *th, const char *fxsave) 219 { 220 const td_thragent_t *ta = th->th_ta; 221 return (ta->ta_ops->to_thr_setxmmregs(th, fxsave)); 222 } 223 #endif 224 225 td_err_e 226 td_thr_setfpregs(const td_thrhandle_t *th, const prfpregset_t *fpregs) 227 { 228 const td_thragent_t *ta = th->th_ta; 229 return (ta->ta_ops->to_thr_setfpregs(th, fpregs)); 230 } 231 232 td_err_e 233 td_thr_setgregs(const td_thrhandle_t *th, const prgregset_t gregs) 234 { 235 const td_thragent_t *ta = th->th_ta; 236 return (ta->ta_ops->to_thr_setgregs(th, gregs)); 237 } 238 239 td_err_e 240 td_thr_validate(const td_thrhandle_t *th) 241 { 242 const td_thragent_t *ta = th->th_ta; 243 return (ta->ta_ops->to_thr_validate(th)); 244 } 245 246 td_err_e 247 td_thr_tls_get_addr(const td_thrhandle_t *th, psaddr_t linkmap, size_t offset, 248 psaddr_t *address) 249 { 250 const td_thragent_t *ta = th->th_ta; 251 return (ta->ta_ops->to_thr_tls_get_addr(th, linkmap, offset, address)); 252 } 253 254 /* FreeBSD specific extensions. */ 255 256 td_err_e 257 td_thr_sstep(const td_thrhandle_t *th, int step) 258 { 259 const td_thragent_t *ta = th->th_ta; 260 return (ta->ta_ops->to_thr_sstep(th, step)); 261 } 262 263 /* 264 * Support functions for reading from and writing to the target 265 * address space. 266 */ 267 268 static int 269 thr_pread(struct ps_prochandle *ph, psaddr_t addr, uint64_t *val, 270 u_int size, u_int byteorder) 271 { 272 uint8_t buf[sizeof(*val)]; 273 ps_err_e err; 274 275 if (size > sizeof(buf)) 276 return (EOVERFLOW); 277 278 err = ps_pread(ph, addr, buf, size); 279 if (err != PS_OK) 280 return (EFAULT); 281 282 switch (byteorder) { 283 case BIG_ENDIAN: 284 switch (size) { 285 case 1: 286 *val = buf[0]; 287 break; 288 case 2: 289 *val = be16dec(buf); 290 break; 291 case 4: 292 *val = be32dec(buf); 293 break; 294 case 8: 295 *val = be64dec(buf); 296 break; 297 default: 298 return (EINVAL); 299 } 300 break; 301 case LITTLE_ENDIAN: 302 switch (size) { 303 case 1: 304 *val = buf[0]; 305 break; 306 case 2: 307 *val = le16dec(buf); 308 break; 309 case 4: 310 *val = le32dec(buf); 311 break; 312 case 8: 313 *val = le64dec(buf); 314 break; 315 default: 316 return (EINVAL); 317 } 318 break; 319 default: 320 return (EINVAL); 321 } 322 323 return (0); 324 } 325 326 int 327 thr_pread_int(const struct td_thragent *ta, psaddr_t addr, uint32_t *val) 328 { 329 uint64_t tmp; 330 int error; 331 332 error = thr_pread(ta->ph, addr, &tmp, sizeof(int), BYTE_ORDER); 333 if (!error) 334 *val = tmp; 335 336 return (error); 337 } 338 339 int 340 thr_pread_long(const struct td_thragent *ta, psaddr_t addr, uint64_t *val) 341 { 342 343 return (thr_pread(ta->ph, addr, val, sizeof(long), BYTE_ORDER)); 344 } 345 346 int 347 thr_pread_ptr(const struct td_thragent *ta, psaddr_t addr, psaddr_t *val) 348 { 349 uint64_t tmp; 350 int error; 351 352 error = thr_pread(ta->ph, addr, &tmp, sizeof(void *), BYTE_ORDER); 353 if (!error) 354 *val = tmp; 355 356 return (error); 357 } 358 359 static int 360 thr_pwrite(struct ps_prochandle *ph, psaddr_t addr, uint64_t val, 361 u_int size, u_int byteorder) 362 { 363 uint8_t buf[sizeof(val)]; 364 ps_err_e err; 365 366 if (size > sizeof(buf)) 367 return (EOVERFLOW); 368 369 switch (byteorder) { 370 case BIG_ENDIAN: 371 switch (size) { 372 case 1: 373 buf[0] = (uint8_t)val; 374 break; 375 case 2: 376 be16enc(buf, (uint16_t)val); 377 break; 378 case 4: 379 be32enc(buf, (uint32_t)val); 380 break; 381 case 8: 382 be64enc(buf, (uint64_t)val); 383 break; 384 default: 385 return (EINVAL); 386 } 387 break; 388 case LITTLE_ENDIAN: 389 switch (size) { 390 case 1: 391 buf[0] = (uint8_t)val; 392 break; 393 case 2: 394 le16enc(buf, (uint16_t)val); 395 break; 396 case 4: 397 le32enc(buf, (uint32_t)val); 398 break; 399 case 8: 400 le64enc(buf, (uint64_t)val); 401 break; 402 default: 403 return (EINVAL); 404 } 405 break; 406 default: 407 return (EINVAL); 408 } 409 410 err = ps_pwrite(ph, addr, buf, size); 411 return ((err != PS_OK) ? EFAULT : 0); 412 } 413 414 int 415 thr_pwrite_int(const struct td_thragent *ta, psaddr_t addr, uint32_t val) 416 { 417 418 return (thr_pwrite(ta->ph, addr, val, sizeof(int), BYTE_ORDER)); 419 } 420 421 int 422 thr_pwrite_long(const struct td_thragent *ta, psaddr_t addr, uint64_t val) 423 { 424 425 return (thr_pwrite(ta->ph, addr, val, sizeof(long), BYTE_ORDER)); 426 } 427 428 int 429 thr_pwrite_ptr(const struct td_thragent *ta, psaddr_t addr, psaddr_t val) 430 { 431 432 return (thr_pwrite(ta->ph, addr, val, sizeof(void *), BYTE_ORDER)); 433 } 434 435