xref: /freebsd/lib/libthread_db/thread_db.c (revision 16b0c20c82c73d7ff49d7d9604fba64eff0c9c45)
13c1e38eaSMarcel Moolenaar /*
23c1e38eaSMarcel Moolenaar  * Copyright (c) 2004 David Xu <davidxu@freebsd.org>
33c1e38eaSMarcel Moolenaar  * All rights reserved.
43c1e38eaSMarcel Moolenaar  *
53c1e38eaSMarcel Moolenaar  * Redistribution and use in source and binary forms, with or without
63c1e38eaSMarcel Moolenaar  * modification, are permitted provided that the following conditions
73c1e38eaSMarcel Moolenaar  * are met:
83c1e38eaSMarcel Moolenaar  * 1. Redistributions of source code must retain the above copyright
93c1e38eaSMarcel Moolenaar  *    notice, this list of conditions and the following disclaimer.
103c1e38eaSMarcel Moolenaar  * 2. Redistributions in binary form must reproduce the above copyright
113c1e38eaSMarcel Moolenaar  *    notice, this list of conditions and the following disclaimer in the
123c1e38eaSMarcel Moolenaar  *    documentation and/or other materials provided with the distribution.
133c1e38eaSMarcel Moolenaar  *
143c1e38eaSMarcel Moolenaar  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
153c1e38eaSMarcel Moolenaar  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
163c1e38eaSMarcel Moolenaar  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
173c1e38eaSMarcel Moolenaar  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
183c1e38eaSMarcel Moolenaar  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
193c1e38eaSMarcel Moolenaar  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
203c1e38eaSMarcel Moolenaar  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
213c1e38eaSMarcel Moolenaar  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
223c1e38eaSMarcel Moolenaar  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
233c1e38eaSMarcel Moolenaar  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
243c1e38eaSMarcel Moolenaar  * SUCH DAMAGE.
253c1e38eaSMarcel Moolenaar  */
263c1e38eaSMarcel Moolenaar 
273c1e38eaSMarcel Moolenaar #include <sys/cdefs.h>
283c1e38eaSMarcel Moolenaar __FBSDID("$FreeBSD$");
293c1e38eaSMarcel Moolenaar 
303c1e38eaSMarcel Moolenaar #include <proc_service.h>
313c1e38eaSMarcel Moolenaar #include <stddef.h>
323c1e38eaSMarcel Moolenaar #include <thread_db.h>
333c1e38eaSMarcel Moolenaar #include <unistd.h>
3420b94d80SDavid Xu #include <sys/cdefs.h>
3520b94d80SDavid Xu #include <sys/linker_set.h>
363c1e38eaSMarcel Moolenaar 
373c1e38eaSMarcel Moolenaar #include "thread_db_int.h"
383c1e38eaSMarcel Moolenaar 
393c1e38eaSMarcel Moolenaar struct td_thragent
403c1e38eaSMarcel Moolenaar {
413c1e38eaSMarcel Moolenaar 	TD_THRAGENT_FIELDS;
423c1e38eaSMarcel Moolenaar };
433c1e38eaSMarcel Moolenaar 
443c1e38eaSMarcel Moolenaar static TAILQ_HEAD(, td_thragent) proclist = TAILQ_HEAD_INITIALIZER(proclist);
453c1e38eaSMarcel Moolenaar 
4620b94d80SDavid Xu SET_DECLARE(__ta_ops, struct ta_ops);
473c1e38eaSMarcel Moolenaar 
483c1e38eaSMarcel Moolenaar td_err_e
493c1e38eaSMarcel Moolenaar td_init(void)
503c1e38eaSMarcel Moolenaar {
513c1e38eaSMarcel Moolenaar 	td_err_e ret, tmp;
5220b94d80SDavid Xu 	struct ta_ops *ops_p, **ops_pp;
533c1e38eaSMarcel Moolenaar 	size_t i;
543c1e38eaSMarcel Moolenaar 
553c1e38eaSMarcel Moolenaar 	ret = 0;
5620b94d80SDavid Xu 	SET_FOREACH(ops_pp, __ta_ops) {
5720b94d80SDavid Xu 		ops_p = *ops_pp;
5820b94d80SDavid Xu 		if (ops_p->to_init != NULL) {
5920b94d80SDavid Xu 			tmp = ops_p->to_init();
603c1e38eaSMarcel Moolenaar 			if (tmp != TD_OK)
613c1e38eaSMarcel Moolenaar 				ret = tmp;
623c1e38eaSMarcel Moolenaar 		}
633c1e38eaSMarcel Moolenaar 	}
643c1e38eaSMarcel Moolenaar 	return (ret);
653c1e38eaSMarcel Moolenaar }
663c1e38eaSMarcel Moolenaar 
673c1e38eaSMarcel Moolenaar td_err_e
683c1e38eaSMarcel Moolenaar td_ta_clear_event(const td_thragent_t *ta, td_thr_events_t *events)
693c1e38eaSMarcel Moolenaar {
703c1e38eaSMarcel Moolenaar 	return (ta->ta_ops->to_ta_clear_event(ta, events));
713c1e38eaSMarcel Moolenaar }
723c1e38eaSMarcel Moolenaar 
733c1e38eaSMarcel Moolenaar td_err_e
743c1e38eaSMarcel Moolenaar td_ta_delete(td_thragent_t *ta)
753c1e38eaSMarcel Moolenaar {
763c1e38eaSMarcel Moolenaar 	TAILQ_REMOVE(&proclist, ta, ta_next);
773c1e38eaSMarcel Moolenaar 	return (ta->ta_ops->to_ta_delete(ta));
783c1e38eaSMarcel Moolenaar }
793c1e38eaSMarcel Moolenaar 
803c1e38eaSMarcel Moolenaar td_err_e
813c1e38eaSMarcel Moolenaar td_ta_event_addr(const td_thragent_t *ta, td_event_e event, td_notify_t *ptr)
823c1e38eaSMarcel Moolenaar {
833c1e38eaSMarcel Moolenaar 	return (ta->ta_ops->to_ta_event_addr(ta, event, ptr));
843c1e38eaSMarcel Moolenaar }
853c1e38eaSMarcel Moolenaar 
863c1e38eaSMarcel Moolenaar td_err_e
873c1e38eaSMarcel Moolenaar td_ta_event_getmsg(const td_thragent_t *ta, td_event_msg_t *msg)
883c1e38eaSMarcel Moolenaar {
893c1e38eaSMarcel Moolenaar 	return (ta->ta_ops->to_ta_event_getmsg(ta, msg));
903c1e38eaSMarcel Moolenaar }
913c1e38eaSMarcel Moolenaar 
923c1e38eaSMarcel Moolenaar td_err_e
933c1e38eaSMarcel Moolenaar td_ta_map_id2thr(const td_thragent_t *ta, thread_t id, td_thrhandle_t *th)
943c1e38eaSMarcel Moolenaar {
953c1e38eaSMarcel Moolenaar 	return (ta->ta_ops->to_ta_map_id2thr(ta, id, th));
963c1e38eaSMarcel Moolenaar }
973c1e38eaSMarcel Moolenaar 
983c1e38eaSMarcel Moolenaar td_err_e
993c1e38eaSMarcel Moolenaar td_ta_map_lwp2thr(const td_thragent_t *ta, lwpid_t lwpid, td_thrhandle_t *th)
1003c1e38eaSMarcel Moolenaar {
1013c1e38eaSMarcel Moolenaar 	return (ta->ta_ops->to_ta_map_lwp2thr(ta, lwpid, th));
1023c1e38eaSMarcel Moolenaar }
1033c1e38eaSMarcel Moolenaar 
1043c1e38eaSMarcel Moolenaar td_err_e
1053c1e38eaSMarcel Moolenaar td_ta_new(struct ps_prochandle *ph, td_thragent_t **pta)
1063c1e38eaSMarcel Moolenaar {
1073c1e38eaSMarcel Moolenaar 	size_t i;
10820b94d80SDavid Xu 	struct ta_ops *ops_p, **ops_pp;
1093c1e38eaSMarcel Moolenaar 
11020b94d80SDavid Xu 	SET_FOREACH(ops_pp, __ta_ops) {
11120b94d80SDavid Xu 		ops_p = *ops_pp;
11220b94d80SDavid Xu 		if (ops_p->to_ta_new(ph, pta) == TD_OK) {
1133c1e38eaSMarcel Moolenaar 			TAILQ_INSERT_HEAD(&proclist, *pta, ta_next);
11420b94d80SDavid Xu 			(*pta)->ta_ops = ops_p;
1153c1e38eaSMarcel Moolenaar 			return (TD_OK);
1163c1e38eaSMarcel Moolenaar 		}
1173c1e38eaSMarcel Moolenaar 	}
1183c1e38eaSMarcel Moolenaar 	return (TD_NOLIBTHREAD);
1193c1e38eaSMarcel Moolenaar }
1203c1e38eaSMarcel Moolenaar 
1213c1e38eaSMarcel Moolenaar td_err_e
1223c1e38eaSMarcel Moolenaar td_ta_set_event(const td_thragent_t *ta, td_thr_events_t *events)
1233c1e38eaSMarcel Moolenaar {
1243c1e38eaSMarcel Moolenaar 	return (ta->ta_ops->to_ta_set_event(ta, events));
1253c1e38eaSMarcel Moolenaar }
1263c1e38eaSMarcel Moolenaar 
1273c1e38eaSMarcel Moolenaar td_err_e
1283c1e38eaSMarcel Moolenaar td_ta_thr_iter(const td_thragent_t *ta, td_thr_iter_f *callback,
1293c1e38eaSMarcel Moolenaar     void *cbdata_p, td_thr_state_e state, int ti_pri, sigset_t *ti_sigmask_p,
1303c1e38eaSMarcel Moolenaar     unsigned int ti_user_flags)
1313c1e38eaSMarcel Moolenaar {
1323c1e38eaSMarcel Moolenaar 	return (ta->ta_ops->to_ta_thr_iter(ta, callback, cbdata_p, state,
1333c1e38eaSMarcel Moolenaar 		    ti_pri, ti_sigmask_p, ti_user_flags));
1343c1e38eaSMarcel Moolenaar }
1353c1e38eaSMarcel Moolenaar 
1363c1e38eaSMarcel Moolenaar td_err_e
1373c1e38eaSMarcel Moolenaar td_ta_tsd_iter(const td_thragent_t *ta, td_key_iter_f *callback,
1383c1e38eaSMarcel Moolenaar     void *cbdata_p)
1393c1e38eaSMarcel Moolenaar {
1403c1e38eaSMarcel Moolenaar 	return (ta->ta_ops->to_ta_tsd_iter(ta, callback, cbdata_p));
1413c1e38eaSMarcel Moolenaar }
1423c1e38eaSMarcel Moolenaar 
1433c1e38eaSMarcel Moolenaar td_err_e
1443c1e38eaSMarcel Moolenaar td_thr_clear_event(const td_thrhandle_t *th, td_thr_events_t *events)
1453c1e38eaSMarcel Moolenaar {
1463c1e38eaSMarcel Moolenaar 	const td_thragent_t *ta = th->th_ta;
1473c1e38eaSMarcel Moolenaar 	return (ta->ta_ops->to_thr_clear_event(th, events));
1483c1e38eaSMarcel Moolenaar }
1493c1e38eaSMarcel Moolenaar 
1503c1e38eaSMarcel Moolenaar td_err_e
1513c1e38eaSMarcel Moolenaar td_thr_dbresume(const td_thrhandle_t *th)
1523c1e38eaSMarcel Moolenaar {
1533c1e38eaSMarcel Moolenaar 	const td_thragent_t *ta = th->th_ta;
1543c1e38eaSMarcel Moolenaar 	return (ta->ta_ops->to_thr_dbresume(th));
1553c1e38eaSMarcel Moolenaar }
1563c1e38eaSMarcel Moolenaar 
1573c1e38eaSMarcel Moolenaar td_err_e
1583c1e38eaSMarcel Moolenaar td_thr_dbsuspend(const td_thrhandle_t *th)
1593c1e38eaSMarcel Moolenaar {
1603c1e38eaSMarcel Moolenaar 	const td_thragent_t *ta = th->th_ta;
1613c1e38eaSMarcel Moolenaar 	return (ta->ta_ops->to_thr_dbsuspend(th));
1623c1e38eaSMarcel Moolenaar }
1633c1e38eaSMarcel Moolenaar 
1643c1e38eaSMarcel Moolenaar td_err_e
1653c1e38eaSMarcel Moolenaar td_thr_event_enable(const td_thrhandle_t *th, int en)
1663c1e38eaSMarcel Moolenaar {
1673c1e38eaSMarcel Moolenaar 	const td_thragent_t *ta = th->th_ta;
1683c1e38eaSMarcel Moolenaar 	return (ta->ta_ops->to_thr_event_enable(th, en));
1693c1e38eaSMarcel Moolenaar }
1703c1e38eaSMarcel Moolenaar 
1713c1e38eaSMarcel Moolenaar td_err_e
1723c1e38eaSMarcel Moolenaar td_thr_event_getmsg(const td_thrhandle_t *th, td_event_msg_t *msg)
1733c1e38eaSMarcel Moolenaar {
1743c1e38eaSMarcel Moolenaar 	const td_thragent_t *ta = th->th_ta;
1753c1e38eaSMarcel Moolenaar 	return (ta->ta_ops->to_thr_event_getmsg(th, msg));
1763c1e38eaSMarcel Moolenaar }
1773c1e38eaSMarcel Moolenaar 
1783c1e38eaSMarcel Moolenaar td_err_e
1793c1e38eaSMarcel Moolenaar td_thr_get_info(const td_thrhandle_t *th, td_thrinfo_t *info)
1803c1e38eaSMarcel Moolenaar {
1813c1e38eaSMarcel Moolenaar 	const td_thragent_t *ta = th->th_ta;
1823c1e38eaSMarcel Moolenaar 	return (ta->ta_ops->to_thr_get_info(th, info));
1833c1e38eaSMarcel Moolenaar }
1843c1e38eaSMarcel Moolenaar 
1858d7681bbSDoug Rabson #ifdef __i386__
1868d7681bbSDoug Rabson td_err_e
1878d7681bbSDoug Rabson td_thr_getxmmregs(const td_thrhandle_t *th, char *fxsave)
1888d7681bbSDoug Rabson {
1898d7681bbSDoug Rabson 	const td_thragent_t *ta = th->th_ta;
1908d7681bbSDoug Rabson 	return (ta->ta_ops->to_thr_getxmmregs(th, fxsave));
1918d7681bbSDoug Rabson }
1928d7681bbSDoug Rabson #endif
1938d7681bbSDoug Rabson 
1948d7681bbSDoug Rabson 
1953c1e38eaSMarcel Moolenaar td_err_e
1963c1e38eaSMarcel Moolenaar td_thr_getfpregs(const td_thrhandle_t *th, prfpregset_t *fpregset)
1973c1e38eaSMarcel Moolenaar {
1983c1e38eaSMarcel Moolenaar 	const td_thragent_t *ta = th->th_ta;
1993c1e38eaSMarcel Moolenaar 	return (ta->ta_ops->to_thr_getfpregs(th, fpregset));
2003c1e38eaSMarcel Moolenaar }
2013c1e38eaSMarcel Moolenaar 
2023c1e38eaSMarcel Moolenaar td_err_e
2033c1e38eaSMarcel Moolenaar td_thr_getgregs(const td_thrhandle_t *th, prgregset_t gregs)
2043c1e38eaSMarcel Moolenaar {
2053c1e38eaSMarcel Moolenaar 	const td_thragent_t *ta = th->th_ta;
2063c1e38eaSMarcel Moolenaar 	return (ta->ta_ops->to_thr_getgregs(th, gregs));
2073c1e38eaSMarcel Moolenaar }
2083c1e38eaSMarcel Moolenaar 
2093c1e38eaSMarcel Moolenaar td_err_e
2103c1e38eaSMarcel Moolenaar td_thr_set_event(const td_thrhandle_t *th, td_thr_events_t *events)
2113c1e38eaSMarcel Moolenaar {
2123c1e38eaSMarcel Moolenaar 	const td_thragent_t *ta = th->th_ta;
2133c1e38eaSMarcel Moolenaar 	return (ta->ta_ops->to_thr_set_event(th, events));
2143c1e38eaSMarcel Moolenaar }
2153c1e38eaSMarcel Moolenaar 
2168d7681bbSDoug Rabson #ifdef __i386__
2178d7681bbSDoug Rabson td_err_e
2188d7681bbSDoug Rabson td_thr_setxmmregs(const td_thrhandle_t *th, const char *fxsave)
2198d7681bbSDoug Rabson {
2208d7681bbSDoug Rabson 	const td_thragent_t *ta = th->th_ta;
2218d7681bbSDoug Rabson 	return (ta->ta_ops->to_thr_setxmmregs(th, fxsave));
2228d7681bbSDoug Rabson }
2238d7681bbSDoug Rabson #endif
2248d7681bbSDoug Rabson 
2253c1e38eaSMarcel Moolenaar td_err_e
2263c1e38eaSMarcel Moolenaar td_thr_setfpregs(const td_thrhandle_t *th, const prfpregset_t *fpregs)
2273c1e38eaSMarcel Moolenaar {
2283c1e38eaSMarcel Moolenaar 	const td_thragent_t *ta = th->th_ta;
2293c1e38eaSMarcel Moolenaar 	return (ta->ta_ops->to_thr_setfpregs(th, fpregs));
2303c1e38eaSMarcel Moolenaar }
2313c1e38eaSMarcel Moolenaar 
2323c1e38eaSMarcel Moolenaar td_err_e
2333c1e38eaSMarcel Moolenaar td_thr_setgregs(const td_thrhandle_t *th, const prgregset_t gregs)
2343c1e38eaSMarcel Moolenaar {
2353c1e38eaSMarcel Moolenaar 	const td_thragent_t *ta = th->th_ta;
2363c1e38eaSMarcel Moolenaar 	return (ta->ta_ops->to_thr_setgregs(th, gregs));
2373c1e38eaSMarcel Moolenaar }
2383c1e38eaSMarcel Moolenaar 
2393c1e38eaSMarcel Moolenaar td_err_e
2403c1e38eaSMarcel Moolenaar td_thr_validate(const td_thrhandle_t *th)
2413c1e38eaSMarcel Moolenaar {
2423c1e38eaSMarcel Moolenaar 	const td_thragent_t *ta = th->th_ta;
2433c1e38eaSMarcel Moolenaar 	return (ta->ta_ops->to_thr_validate(th));
2443c1e38eaSMarcel Moolenaar }
2453c1e38eaSMarcel Moolenaar 
2463e93cc3aSDavid Xu td_err_e
24716b0c20cSMarcel Moolenaar td_thr_tls_get_addr(const td_thrhandle_t *th, psaddr_t linkmap, size_t offset,
24816b0c20cSMarcel Moolenaar     psaddr_t *address)
2493e93cc3aSDavid Xu {
2503e93cc3aSDavid Xu 	const td_thragent_t *ta = th->th_ta;
2513e93cc3aSDavid Xu 	return (ta->ta_ops->to_thr_tls_get_addr(th, linkmap, offset, address));
2523e93cc3aSDavid Xu }
2533e93cc3aSDavid Xu 
2543c1e38eaSMarcel Moolenaar /* FreeBSD specific extensions. */
2553c1e38eaSMarcel Moolenaar 
2563c1e38eaSMarcel Moolenaar td_err_e
2573c1e38eaSMarcel Moolenaar td_thr_sstep(const td_thrhandle_t *th, int step)
2583c1e38eaSMarcel Moolenaar {
2593c1e38eaSMarcel Moolenaar 	const td_thragent_t *ta = th->th_ta;
2603c1e38eaSMarcel Moolenaar 	return (ta->ta_ops->to_thr_sstep(th, step));
2613c1e38eaSMarcel Moolenaar }
262