xref: /freebsd/lib/libthread_db/thread_db.c (revision 8d7681bb7fc40b6681f759c2f6051e84cfc6d087)
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>
343c1e38eaSMarcel Moolenaar 
353c1e38eaSMarcel Moolenaar #include "thread_db_int.h"
363c1e38eaSMarcel Moolenaar 
373c1e38eaSMarcel Moolenaar struct td_thragent
383c1e38eaSMarcel Moolenaar {
393c1e38eaSMarcel Moolenaar 	TD_THRAGENT_FIELDS;
403c1e38eaSMarcel Moolenaar };
413c1e38eaSMarcel Moolenaar 
423c1e38eaSMarcel Moolenaar static TAILQ_HEAD(, td_thragent) proclist = TAILQ_HEAD_INITIALIZER(proclist);
433c1e38eaSMarcel Moolenaar 
443c1e38eaSMarcel Moolenaar extern struct ta_ops libc_r_db_ops;
453c1e38eaSMarcel Moolenaar extern struct ta_ops libpthread_db_ops;
463c1e38eaSMarcel Moolenaar extern struct ta_ops libthr_db_ops;
473c1e38eaSMarcel Moolenaar 
483c1e38eaSMarcel Moolenaar static struct ta_ops *ops[] = {
493c1e38eaSMarcel Moolenaar 	&libpthread_db_ops,
503c1e38eaSMarcel Moolenaar 	&libthr_db_ops,
513c1e38eaSMarcel Moolenaar 	&libc_r_db_ops
523c1e38eaSMarcel Moolenaar };
533c1e38eaSMarcel Moolenaar 
543c1e38eaSMarcel Moolenaar td_err_e
553c1e38eaSMarcel Moolenaar td_init(void)
563c1e38eaSMarcel Moolenaar {
573c1e38eaSMarcel Moolenaar 	td_err_e ret, tmp;
583c1e38eaSMarcel Moolenaar 	size_t i;
593c1e38eaSMarcel Moolenaar 
603c1e38eaSMarcel Moolenaar 	ret = 0;
613c1e38eaSMarcel Moolenaar 	for (i = 0; i < sizeof(ops)/sizeof(ops[0]); i++) {
623c1e38eaSMarcel Moolenaar 		if (ops[i]->to_init != NULL) {
633c1e38eaSMarcel Moolenaar 			tmp = ops[i]->to_init();
643c1e38eaSMarcel Moolenaar 			if (tmp != TD_OK)
653c1e38eaSMarcel Moolenaar 				ret = tmp;
663c1e38eaSMarcel Moolenaar 		}
673c1e38eaSMarcel Moolenaar 	}
683c1e38eaSMarcel Moolenaar 	return (ret);
693c1e38eaSMarcel Moolenaar }
703c1e38eaSMarcel Moolenaar 
713c1e38eaSMarcel Moolenaar td_err_e
723c1e38eaSMarcel Moolenaar td_ta_clear_event(const td_thragent_t *ta, td_thr_events_t *events)
733c1e38eaSMarcel Moolenaar {
743c1e38eaSMarcel Moolenaar 	return (ta->ta_ops->to_ta_clear_event(ta, events));
753c1e38eaSMarcel Moolenaar }
763c1e38eaSMarcel Moolenaar 
773c1e38eaSMarcel Moolenaar td_err_e
783c1e38eaSMarcel Moolenaar td_ta_delete(td_thragent_t *ta)
793c1e38eaSMarcel Moolenaar {
803c1e38eaSMarcel Moolenaar 	TAILQ_REMOVE(&proclist, ta, ta_next);
813c1e38eaSMarcel Moolenaar 	return (ta->ta_ops->to_ta_delete(ta));
823c1e38eaSMarcel Moolenaar }
833c1e38eaSMarcel Moolenaar 
843c1e38eaSMarcel Moolenaar td_err_e
853c1e38eaSMarcel Moolenaar td_ta_event_addr(const td_thragent_t *ta, td_event_e event, td_notify_t *ptr)
863c1e38eaSMarcel Moolenaar {
873c1e38eaSMarcel Moolenaar 	return (ta->ta_ops->to_ta_event_addr(ta, event, ptr));
883c1e38eaSMarcel Moolenaar }
893c1e38eaSMarcel Moolenaar 
903c1e38eaSMarcel Moolenaar td_err_e
913c1e38eaSMarcel Moolenaar td_ta_event_getmsg(const td_thragent_t *ta, td_event_msg_t *msg)
923c1e38eaSMarcel Moolenaar {
933c1e38eaSMarcel Moolenaar 	return (ta->ta_ops->to_ta_event_getmsg(ta, msg));
943c1e38eaSMarcel Moolenaar }
953c1e38eaSMarcel Moolenaar 
963c1e38eaSMarcel Moolenaar td_err_e
973c1e38eaSMarcel Moolenaar td_ta_map_id2thr(const td_thragent_t *ta, thread_t id, td_thrhandle_t *th)
983c1e38eaSMarcel Moolenaar {
993c1e38eaSMarcel Moolenaar 	return (ta->ta_ops->to_ta_map_id2thr(ta, id, th));
1003c1e38eaSMarcel Moolenaar }
1013c1e38eaSMarcel Moolenaar 
1023c1e38eaSMarcel Moolenaar td_err_e
1033c1e38eaSMarcel Moolenaar td_ta_map_lwp2thr(const td_thragent_t *ta, lwpid_t lwpid, td_thrhandle_t *th)
1043c1e38eaSMarcel Moolenaar {
1053c1e38eaSMarcel Moolenaar 	return (ta->ta_ops->to_ta_map_lwp2thr(ta, lwpid, th));
1063c1e38eaSMarcel Moolenaar }
1073c1e38eaSMarcel Moolenaar 
1083c1e38eaSMarcel Moolenaar td_err_e
1093c1e38eaSMarcel Moolenaar td_ta_new(struct ps_prochandle *ph, td_thragent_t **pta)
1103c1e38eaSMarcel Moolenaar {
1113c1e38eaSMarcel Moolenaar 	size_t i;
1123c1e38eaSMarcel Moolenaar 
1133c1e38eaSMarcel Moolenaar 	for (i = 0; i < sizeof(ops)/sizeof(ops[0]); ++i) {
1143c1e38eaSMarcel Moolenaar 		if (ops[i]->to_ta_new(ph, pta) == TD_OK) {
1153c1e38eaSMarcel Moolenaar 			TAILQ_INSERT_HEAD(&proclist, *pta, ta_next);
1163c1e38eaSMarcel Moolenaar 			(*pta)->ta_ops = ops[i];
1173c1e38eaSMarcel Moolenaar 			return (TD_OK);
1183c1e38eaSMarcel Moolenaar 		}
1193c1e38eaSMarcel Moolenaar 	}
1203c1e38eaSMarcel Moolenaar 	return (TD_NOLIBTHREAD);
1213c1e38eaSMarcel Moolenaar }
1223c1e38eaSMarcel Moolenaar 
1233c1e38eaSMarcel Moolenaar td_err_e
1243c1e38eaSMarcel Moolenaar td_ta_set_event(const td_thragent_t *ta, td_thr_events_t *events)
1253c1e38eaSMarcel Moolenaar {
1263c1e38eaSMarcel Moolenaar 	return (ta->ta_ops->to_ta_set_event(ta, events));
1273c1e38eaSMarcel Moolenaar }
1283c1e38eaSMarcel Moolenaar 
1293c1e38eaSMarcel Moolenaar td_err_e
1303c1e38eaSMarcel Moolenaar td_ta_thr_iter(const td_thragent_t *ta, td_thr_iter_f *callback,
1313c1e38eaSMarcel Moolenaar     void *cbdata_p, td_thr_state_e state, int ti_pri, sigset_t *ti_sigmask_p,
1323c1e38eaSMarcel Moolenaar     unsigned int ti_user_flags)
1333c1e38eaSMarcel Moolenaar {
1343c1e38eaSMarcel Moolenaar 	return (ta->ta_ops->to_ta_thr_iter(ta, callback, cbdata_p, state,
1353c1e38eaSMarcel Moolenaar 		    ti_pri, ti_sigmask_p, ti_user_flags));
1363c1e38eaSMarcel Moolenaar }
1373c1e38eaSMarcel Moolenaar 
1383c1e38eaSMarcel Moolenaar td_err_e
1393c1e38eaSMarcel Moolenaar td_ta_tsd_iter(const td_thragent_t *ta, td_key_iter_f *callback,
1403c1e38eaSMarcel Moolenaar     void *cbdata_p)
1413c1e38eaSMarcel Moolenaar {
1423c1e38eaSMarcel Moolenaar 	return (ta->ta_ops->to_ta_tsd_iter(ta, callback, cbdata_p));
1433c1e38eaSMarcel Moolenaar }
1443c1e38eaSMarcel Moolenaar 
1453c1e38eaSMarcel Moolenaar td_err_e
1463c1e38eaSMarcel Moolenaar td_thr_clear_event(const td_thrhandle_t *th, td_thr_events_t *events)
1473c1e38eaSMarcel Moolenaar {
1483c1e38eaSMarcel Moolenaar 	const td_thragent_t *ta = th->th_ta;
1493c1e38eaSMarcel Moolenaar 	return (ta->ta_ops->to_thr_clear_event(th, events));
1503c1e38eaSMarcel Moolenaar }
1513c1e38eaSMarcel Moolenaar 
1523c1e38eaSMarcel Moolenaar td_err_e
1533c1e38eaSMarcel Moolenaar td_thr_dbresume(const td_thrhandle_t *th)
1543c1e38eaSMarcel Moolenaar {
1553c1e38eaSMarcel Moolenaar 	const td_thragent_t *ta = th->th_ta;
1563c1e38eaSMarcel Moolenaar 	return (ta->ta_ops->to_thr_dbresume(th));
1573c1e38eaSMarcel Moolenaar }
1583c1e38eaSMarcel Moolenaar 
1593c1e38eaSMarcel Moolenaar td_err_e
1603c1e38eaSMarcel Moolenaar td_thr_dbsuspend(const td_thrhandle_t *th)
1613c1e38eaSMarcel Moolenaar {
1623c1e38eaSMarcel Moolenaar 	const td_thragent_t *ta = th->th_ta;
1633c1e38eaSMarcel Moolenaar 	return (ta->ta_ops->to_thr_dbsuspend(th));
1643c1e38eaSMarcel Moolenaar }
1653c1e38eaSMarcel Moolenaar 
1663c1e38eaSMarcel Moolenaar td_err_e
1673c1e38eaSMarcel Moolenaar td_thr_event_enable(const td_thrhandle_t *th, int en)
1683c1e38eaSMarcel Moolenaar {
1693c1e38eaSMarcel Moolenaar 	const td_thragent_t *ta = th->th_ta;
1703c1e38eaSMarcel Moolenaar 	return (ta->ta_ops->to_thr_event_enable(th, en));
1713c1e38eaSMarcel Moolenaar }
1723c1e38eaSMarcel Moolenaar 
1733c1e38eaSMarcel Moolenaar td_err_e
1743c1e38eaSMarcel Moolenaar td_thr_event_getmsg(const td_thrhandle_t *th, td_event_msg_t *msg)
1753c1e38eaSMarcel Moolenaar {
1763c1e38eaSMarcel Moolenaar 	const td_thragent_t *ta = th->th_ta;
1773c1e38eaSMarcel Moolenaar 	return (ta->ta_ops->to_thr_event_getmsg(th, msg));
1783c1e38eaSMarcel Moolenaar }
1793c1e38eaSMarcel Moolenaar 
1803c1e38eaSMarcel Moolenaar td_err_e
1813c1e38eaSMarcel Moolenaar td_thr_get_info(const td_thrhandle_t *th, td_thrinfo_t *info)
1823c1e38eaSMarcel Moolenaar {
1833c1e38eaSMarcel Moolenaar 	const td_thragent_t *ta = th->th_ta;
1843c1e38eaSMarcel Moolenaar 	return (ta->ta_ops->to_thr_get_info(th, info));
1853c1e38eaSMarcel Moolenaar }
1863c1e38eaSMarcel Moolenaar 
1878d7681bbSDoug Rabson #ifdef __i386__
1888d7681bbSDoug Rabson td_err_e
1898d7681bbSDoug Rabson td_thr_getxmmregs(const td_thrhandle_t *th, char *fxsave)
1908d7681bbSDoug Rabson {
1918d7681bbSDoug Rabson 	const td_thragent_t *ta = th->th_ta;
1928d7681bbSDoug Rabson 	return (ta->ta_ops->to_thr_getxmmregs(th, fxsave));
1938d7681bbSDoug Rabson }
1948d7681bbSDoug Rabson #endif
1958d7681bbSDoug Rabson 
1968d7681bbSDoug Rabson 
1973c1e38eaSMarcel Moolenaar td_err_e
1983c1e38eaSMarcel Moolenaar td_thr_getfpregs(const td_thrhandle_t *th, prfpregset_t *fpregset)
1993c1e38eaSMarcel Moolenaar {
2003c1e38eaSMarcel Moolenaar 	const td_thragent_t *ta = th->th_ta;
2013c1e38eaSMarcel Moolenaar 	return (ta->ta_ops->to_thr_getfpregs(th, fpregset));
2023c1e38eaSMarcel Moolenaar }
2033c1e38eaSMarcel Moolenaar 
2043c1e38eaSMarcel Moolenaar td_err_e
2053c1e38eaSMarcel Moolenaar td_thr_getgregs(const td_thrhandle_t *th, prgregset_t gregs)
2063c1e38eaSMarcel Moolenaar {
2073c1e38eaSMarcel Moolenaar 	const td_thragent_t *ta = th->th_ta;
2083c1e38eaSMarcel Moolenaar 	return (ta->ta_ops->to_thr_getgregs(th, gregs));
2093c1e38eaSMarcel Moolenaar }
2103c1e38eaSMarcel Moolenaar 
2113c1e38eaSMarcel Moolenaar td_err_e
2123c1e38eaSMarcel Moolenaar td_thr_set_event(const td_thrhandle_t *th, td_thr_events_t *events)
2133c1e38eaSMarcel Moolenaar {
2143c1e38eaSMarcel Moolenaar 	const td_thragent_t *ta = th->th_ta;
2153c1e38eaSMarcel Moolenaar 	return (ta->ta_ops->to_thr_set_event(th, events));
2163c1e38eaSMarcel Moolenaar }
2173c1e38eaSMarcel Moolenaar 
2188d7681bbSDoug Rabson #ifdef __i386__
2198d7681bbSDoug Rabson td_err_e
2208d7681bbSDoug Rabson td_thr_setxmmregs(const td_thrhandle_t *th, const char *fxsave)
2218d7681bbSDoug Rabson {
2228d7681bbSDoug Rabson 	const td_thragent_t *ta = th->th_ta;
2238d7681bbSDoug Rabson 	return (ta->ta_ops->to_thr_setxmmregs(th, fxsave));
2248d7681bbSDoug Rabson }
2258d7681bbSDoug Rabson #endif
2268d7681bbSDoug Rabson 
2273c1e38eaSMarcel Moolenaar td_err_e
2283c1e38eaSMarcel Moolenaar td_thr_setfpregs(const td_thrhandle_t *th, const prfpregset_t *fpregs)
2293c1e38eaSMarcel Moolenaar {
2303c1e38eaSMarcel Moolenaar 	const td_thragent_t *ta = th->th_ta;
2313c1e38eaSMarcel Moolenaar 	return (ta->ta_ops->to_thr_setfpregs(th, fpregs));
2323c1e38eaSMarcel Moolenaar }
2333c1e38eaSMarcel Moolenaar 
2343c1e38eaSMarcel Moolenaar td_err_e
2353c1e38eaSMarcel Moolenaar td_thr_setgregs(const td_thrhandle_t *th, const prgregset_t gregs)
2363c1e38eaSMarcel Moolenaar {
2373c1e38eaSMarcel Moolenaar 	const td_thragent_t *ta = th->th_ta;
2383c1e38eaSMarcel Moolenaar 	return (ta->ta_ops->to_thr_setgregs(th, gregs));
2393c1e38eaSMarcel Moolenaar }
2403c1e38eaSMarcel Moolenaar 
2413c1e38eaSMarcel Moolenaar td_err_e
2423c1e38eaSMarcel Moolenaar td_thr_validate(const td_thrhandle_t *th)
2433c1e38eaSMarcel Moolenaar {
2443c1e38eaSMarcel Moolenaar 	const td_thragent_t *ta = th->th_ta;
2453c1e38eaSMarcel Moolenaar 	return (ta->ta_ops->to_thr_validate(th));
2463c1e38eaSMarcel Moolenaar }
2473c1e38eaSMarcel Moolenaar 
2483e93cc3aSDavid Xu td_err_e
2493e93cc3aSDavid Xu td_thr_tls_get_addr(const td_thrhandle_t *th, void *linkmap, size_t offset,
2503e93cc3aSDavid Xu 		    void **address)
2513e93cc3aSDavid Xu {
2523e93cc3aSDavid Xu 	const td_thragent_t *ta = th->th_ta;
2533e93cc3aSDavid Xu 	return (ta->ta_ops->to_thr_tls_get_addr(th, linkmap, offset, address));
2543e93cc3aSDavid Xu }
2553e93cc3aSDavid Xu 
2563c1e38eaSMarcel Moolenaar /* FreeBSD specific extensions. */
2573c1e38eaSMarcel Moolenaar 
2583c1e38eaSMarcel Moolenaar td_err_e
2593c1e38eaSMarcel Moolenaar td_thr_sstep(const td_thrhandle_t *th, int step)
2603c1e38eaSMarcel Moolenaar {
2613c1e38eaSMarcel Moolenaar 	const td_thragent_t *ta = th->th_ta;
2623c1e38eaSMarcel Moolenaar 	return (ta->ta_ops->to_thr_sstep(th, step));
2633c1e38eaSMarcel Moolenaar }
264