xref: /freebsd/lib/libthread_db/libpthread_db.c (revision 1d386b48)
15e53a4f9SPedro F. Giffuni /*-
24d846d26SWarner Losh  * SPDX-License-Identifier: BSD-2-Clause
35e53a4f9SPedro F. Giffuni  *
43c1e38eaSMarcel Moolenaar  * Copyright (c) 2004 David Xu <davidxu@freebsd.org>
53c1e38eaSMarcel Moolenaar  * All rights reserved.
63c1e38eaSMarcel Moolenaar  *
73c1e38eaSMarcel Moolenaar  * Redistribution and use in source and binary forms, with or without
83c1e38eaSMarcel Moolenaar  * modification, are permitted provided that the following conditions
93c1e38eaSMarcel Moolenaar  * are met:
103c1e38eaSMarcel Moolenaar  * 1. Redistributions of source code must retain the above copyright
113c1e38eaSMarcel Moolenaar  *    notice, this list of conditions and the following disclaimer.
123c1e38eaSMarcel Moolenaar  * 2. Redistributions in binary form must reproduce the above copyright
133c1e38eaSMarcel Moolenaar  *    notice, this list of conditions and the following disclaimer in the
143c1e38eaSMarcel Moolenaar  *    documentation and/or other materials provided with the distribution.
153c1e38eaSMarcel Moolenaar  *
163c1e38eaSMarcel Moolenaar  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
173c1e38eaSMarcel Moolenaar  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
183c1e38eaSMarcel Moolenaar  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
193c1e38eaSMarcel Moolenaar  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
203c1e38eaSMarcel Moolenaar  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
213c1e38eaSMarcel Moolenaar  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
223c1e38eaSMarcel Moolenaar  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
233c1e38eaSMarcel Moolenaar  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
243c1e38eaSMarcel Moolenaar  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
253c1e38eaSMarcel Moolenaar  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
263c1e38eaSMarcel Moolenaar  * SUCH DAMAGE.
273c1e38eaSMarcel Moolenaar  */
283c1e38eaSMarcel Moolenaar 
293c1e38eaSMarcel Moolenaar #include <sys/cdefs.h>
303c1e38eaSMarcel Moolenaar #include <stddef.h>
313c1e38eaSMarcel Moolenaar #include <stdlib.h>
323c1e38eaSMarcel Moolenaar #include <string.h>
333c1e38eaSMarcel Moolenaar #include <unistd.h>
343c1e38eaSMarcel Moolenaar #include <pthread.h>
353c1e38eaSMarcel Moolenaar #include <sys/types.h>
3620b94d80SDavid Xu #include <sys/linker_set.h>
373c1e38eaSMarcel Moolenaar #include <sys/ptrace.h>
383c1e38eaSMarcel Moolenaar #include <proc_service.h>
393c1e38eaSMarcel Moolenaar #include <thread_db.h>
403c1e38eaSMarcel Moolenaar 
413c1e38eaSMarcel Moolenaar #include "libpthread_db.h"
42fbb275f5SJeff Roberson #include "kse.h"
433c1e38eaSMarcel Moolenaar 
443c1e38eaSMarcel Moolenaar #define P2T(c) ps2td(c)
453c1e38eaSMarcel Moolenaar 
463c1e38eaSMarcel Moolenaar static void pt_unmap_lwp(const td_thragent_t *ta, lwpid_t lwp);
473c1e38eaSMarcel Moolenaar static int pt_validate(const td_thrhandle_t *th);
483c1e38eaSMarcel Moolenaar 
493c1e38eaSMarcel Moolenaar static int
ps2td(int c)503c1e38eaSMarcel Moolenaar ps2td(int c)
513c1e38eaSMarcel Moolenaar {
523c1e38eaSMarcel Moolenaar 	switch (c) {
533c1e38eaSMarcel Moolenaar 	case PS_OK:
543c1e38eaSMarcel Moolenaar 		return TD_OK;
553c1e38eaSMarcel Moolenaar 	case PS_ERR:
563c1e38eaSMarcel Moolenaar 		return TD_ERR;
573c1e38eaSMarcel Moolenaar 	case PS_BADPID:
583c1e38eaSMarcel Moolenaar 		return TD_BADPH;
593c1e38eaSMarcel Moolenaar 	case PS_BADLID:
603c1e38eaSMarcel Moolenaar 		return TD_NOLWP;
613c1e38eaSMarcel Moolenaar 	case PS_BADADDR:
623c1e38eaSMarcel Moolenaar 		return TD_ERR;
633c1e38eaSMarcel Moolenaar 	case PS_NOSYM:
643c1e38eaSMarcel Moolenaar 		return TD_NOLIBTHREAD;
653c1e38eaSMarcel Moolenaar 	case PS_NOFREGS:
663c1e38eaSMarcel Moolenaar 		return TD_NOFPREGS;
673c1e38eaSMarcel Moolenaar 	default:
683c1e38eaSMarcel Moolenaar 		return TD_ERR;
693c1e38eaSMarcel Moolenaar 	}
703c1e38eaSMarcel Moolenaar }
713c1e38eaSMarcel Moolenaar 
723c1e38eaSMarcel Moolenaar static long
pt_map_thread(const td_thragent_t * const_ta,psaddr_t pt,enum pt_type type)73820c1c55SMarcel Moolenaar pt_map_thread(const td_thragent_t *const_ta, psaddr_t pt, enum pt_type type)
743c1e38eaSMarcel Moolenaar {
753c1e38eaSMarcel Moolenaar 	td_thragent_t *ta = __DECONST(td_thragent_t *, const_ta);
763c1e38eaSMarcel Moolenaar 	struct pt_map *new;
771f2b051dSPedro F. Giffuni 	int first = -1;
781f2b051dSPedro F. Giffuni 	unsigned int i;
793c1e38eaSMarcel Moolenaar 
803c1e38eaSMarcel Moolenaar 	/* leave zero out */
813c1e38eaSMarcel Moolenaar 	for (i = 1; i < ta->map_len; ++i) {
823c1e38eaSMarcel Moolenaar 		if (ta->map[i].type == PT_NONE) {
833c1e38eaSMarcel Moolenaar 			if (first == -1)
843c1e38eaSMarcel Moolenaar 				first = i;
853c1e38eaSMarcel Moolenaar 		} else if (ta->map[i].type == type && ta->map[i].thr == pt) {
863c1e38eaSMarcel Moolenaar 				return (i);
873c1e38eaSMarcel Moolenaar 		}
883c1e38eaSMarcel Moolenaar 	}
893c1e38eaSMarcel Moolenaar 
903c1e38eaSMarcel Moolenaar 	if (first == -1) {
913c1e38eaSMarcel Moolenaar 		if (ta->map_len == 0) {
923c1e38eaSMarcel Moolenaar 			ta->map = calloc(20, sizeof(struct pt_map));
933c1e38eaSMarcel Moolenaar 			if (ta->map == NULL)
943c1e38eaSMarcel Moolenaar 				return (-1);
953c1e38eaSMarcel Moolenaar 			ta->map_len = 20;
963c1e38eaSMarcel Moolenaar 			first = 1;
973c1e38eaSMarcel Moolenaar 		} else {
981f2b051dSPedro F. Giffuni 			new = reallocarray(ta->map, ta->map_len,
991f2b051dSPedro F. Giffuni 			    2 * sizeof(struct pt_map));
1003c1e38eaSMarcel Moolenaar 			if (new == NULL)
1013c1e38eaSMarcel Moolenaar 				return (-1);
1021f2b051dSPedro F. Giffuni 			memset(new + ta->map_len, '\0', ta->map_len *
1033876a562SPedro F. Giffuni 			    sizeof(struct pt_map));
1043c1e38eaSMarcel Moolenaar 			first = ta->map_len;
1053c1e38eaSMarcel Moolenaar 			ta->map = new;
1063c1e38eaSMarcel Moolenaar 			ta->map_len *= 2;
1073c1e38eaSMarcel Moolenaar 		}
1083c1e38eaSMarcel Moolenaar 	}
1093c1e38eaSMarcel Moolenaar 
1103c1e38eaSMarcel Moolenaar 	ta->map[first].type = type;
1113c1e38eaSMarcel Moolenaar 	ta->map[first].thr = pt;
1123c1e38eaSMarcel Moolenaar 	return (first);
1133c1e38eaSMarcel Moolenaar }
1143c1e38eaSMarcel Moolenaar 
1153c1e38eaSMarcel Moolenaar static td_err_e
pt_init(void)1163c1e38eaSMarcel Moolenaar pt_init(void)
1173c1e38eaSMarcel Moolenaar {
1183c1e38eaSMarcel Moolenaar 	pt_md_init();
1193c1e38eaSMarcel Moolenaar 	return (0);
1203c1e38eaSMarcel Moolenaar }
1213c1e38eaSMarcel Moolenaar 
1223c1e38eaSMarcel Moolenaar static td_err_e
pt_ta_new(struct ps_prochandle * ph,td_thragent_t ** pta)1233c1e38eaSMarcel Moolenaar pt_ta_new(struct ps_prochandle *ph, td_thragent_t **pta)
1243c1e38eaSMarcel Moolenaar {
1253c1e38eaSMarcel Moolenaar #define LOOKUP_SYM(proc, sym, addr) 			\
1263c1e38eaSMarcel Moolenaar 	ret = ps_pglobal_lookup(proc, NULL, sym, addr);	\
1273c1e38eaSMarcel Moolenaar 	if (ret != 0) {					\
1283c1e38eaSMarcel Moolenaar 		TDBG("can not find symbol: %s\n", sym);	\
1293c1e38eaSMarcel Moolenaar 		ret = TD_NOLIBTHREAD;			\
1303c1e38eaSMarcel Moolenaar 		goto error;				\
1313c1e38eaSMarcel Moolenaar 	}
1323c1e38eaSMarcel Moolenaar 
133cd980d46SDavid Xu #define	LOOKUP_VAL(proc, sym, val)			\
134cd980d46SDavid Xu 	ret = ps_pglobal_lookup(proc, NULL, sym, &vaddr);\
135cd980d46SDavid Xu 	if (ret != 0) {					\
136cd980d46SDavid Xu 		TDBG("can not find symbol: %s\n", sym);	\
137cd980d46SDavid Xu 		ret = TD_NOLIBTHREAD;			\
138cd980d46SDavid Xu 		goto error;				\
139cd980d46SDavid Xu 	}						\
140cd980d46SDavid Xu 	ret = ps_pread(proc, vaddr, val, sizeof(int));	\
141cd980d46SDavid Xu 	if (ret != 0) {					\
142cd980d46SDavid Xu 		TDBG("can not read value of %s\n", sym);\
143cd980d46SDavid Xu 		ret = TD_NOLIBTHREAD;			\
144cd980d46SDavid Xu 		goto error;				\
145cd980d46SDavid Xu 	}
146cd980d46SDavid Xu 
1473c1e38eaSMarcel Moolenaar 	td_thragent_t *ta;
148cd980d46SDavid Xu 	psaddr_t vaddr;
1493c1e38eaSMarcel Moolenaar 	int dbg;
1503c1e38eaSMarcel Moolenaar 	int ret;
1513c1e38eaSMarcel Moolenaar 
1523c1e38eaSMarcel Moolenaar 	TDBG_FUNC();
1533c1e38eaSMarcel Moolenaar 
1543c1e38eaSMarcel Moolenaar 	ta = malloc(sizeof(td_thragent_t));
1553c1e38eaSMarcel Moolenaar 	if (ta == NULL)
1563c1e38eaSMarcel Moolenaar 		return (TD_MALLOC);
1573c1e38eaSMarcel Moolenaar 
1583c1e38eaSMarcel Moolenaar 	ta->ph = ph;
1593c1e38eaSMarcel Moolenaar 	ta->thread_activated = 0;
1603c1e38eaSMarcel Moolenaar 	ta->map = NULL;
1613c1e38eaSMarcel Moolenaar 	ta->map_len = 0;
1623c1e38eaSMarcel Moolenaar 
1633c1e38eaSMarcel Moolenaar 	LOOKUP_SYM(ph, "_libkse_debug",		&ta->libkse_debug_addr);
1643c1e38eaSMarcel Moolenaar 	LOOKUP_SYM(ph, "_thread_list",		&ta->thread_list_addr);
1653c1e38eaSMarcel Moolenaar 	LOOKUP_SYM(ph, "_thread_activated",	&ta->thread_activated_addr);
1663c1e38eaSMarcel Moolenaar 	LOOKUP_SYM(ph, "_thread_active_threads",&ta->thread_active_threads_addr);
1673c1e38eaSMarcel Moolenaar 	LOOKUP_SYM(ph, "_thread_keytable",	&ta->thread_keytable_addr);
168cd980d46SDavid Xu 	LOOKUP_VAL(ph, "_thread_off_dtv",	&ta->thread_off_dtv);
169cd980d46SDavid Xu 	LOOKUP_VAL(ph, "_thread_off_kse_locklevel", &ta->thread_off_kse_locklevel);
170cd980d46SDavid Xu 	LOOKUP_VAL(ph, "_thread_off_kse",	&ta->thread_off_kse);
171cd980d46SDavid Xu 	LOOKUP_VAL(ph, "_thread_off_tlsindex",	&ta->thread_off_tlsindex);
172cd980d46SDavid Xu 	LOOKUP_VAL(ph, "_thread_off_attr_flags",	&ta->thread_off_attr_flags);
173cd980d46SDavid Xu 	LOOKUP_VAL(ph, "_thread_size_key",	&ta->thread_size_key);
174cd980d46SDavid Xu 	LOOKUP_VAL(ph, "_thread_off_tcb",	&ta->thread_off_tcb);
175cd980d46SDavid Xu 	LOOKUP_VAL(ph, "_thread_off_linkmap",	&ta->thread_off_linkmap);
176cd980d46SDavid Xu 	LOOKUP_VAL(ph, "_thread_off_tmbx",	&ta->thread_off_tmbx);
177cd980d46SDavid Xu 	LOOKUP_VAL(ph, "_thread_off_thr_locklevel",	&ta->thread_off_thr_locklevel);
178cd980d46SDavid Xu 	LOOKUP_VAL(ph, "_thread_off_next",	&ta->thread_off_next);
179cd980d46SDavid Xu 	LOOKUP_VAL(ph, "_thread_off_state",	&ta->thread_off_state);
180cd980d46SDavid Xu 	LOOKUP_VAL(ph, "_thread_max_keys",	&ta->thread_max_keys);
181cd980d46SDavid Xu 	LOOKUP_VAL(ph, "_thread_off_key_allocated", &ta->thread_off_key_allocated);
182cd980d46SDavid Xu 	LOOKUP_VAL(ph, "_thread_off_key_destructor", &ta->thread_off_key_destructor);
183cd980d46SDavid Xu 	LOOKUP_VAL(ph, "_thread_state_running", &ta->thread_state_running);
184cd980d46SDavid Xu 	LOOKUP_VAL(ph, "_thread_state_zoombie", &ta->thread_state_zoombie);
1852ed66c93SDavid Xu 	LOOKUP_VAL(ph, "_thread_off_sigmask",	&ta->thread_off_sigmask);
1862ed66c93SDavid Xu 	LOOKUP_VAL(ph, "_thread_off_sigpend",	&ta->thread_off_sigpend);
1873c1e38eaSMarcel Moolenaar 	dbg = getpid();
1883c1e38eaSMarcel Moolenaar 	/*
1893c1e38eaSMarcel Moolenaar 	 * If this fails it probably means we're debugging a core file and
1903c1e38eaSMarcel Moolenaar 	 * can't write to it.
1913c1e38eaSMarcel Moolenaar 	 */
1923c1e38eaSMarcel Moolenaar 	ps_pwrite(ph, ta->libkse_debug_addr, &dbg, sizeof(int));
1933c1e38eaSMarcel Moolenaar 	*pta = ta;
1943c1e38eaSMarcel Moolenaar 	return (0);
1953c1e38eaSMarcel Moolenaar 
1963c1e38eaSMarcel Moolenaar error:
1973c1e38eaSMarcel Moolenaar 	free(ta);
1983c1e38eaSMarcel Moolenaar 	return (ret);
1993c1e38eaSMarcel Moolenaar }
2003c1e38eaSMarcel Moolenaar 
2013c1e38eaSMarcel Moolenaar static td_err_e
pt_ta_delete(td_thragent_t * ta)2023c1e38eaSMarcel Moolenaar pt_ta_delete(td_thragent_t *ta)
2033c1e38eaSMarcel Moolenaar {
2043c1e38eaSMarcel Moolenaar 	int dbg;
2053c1e38eaSMarcel Moolenaar 
2063c1e38eaSMarcel Moolenaar 	TDBG_FUNC();
2073c1e38eaSMarcel Moolenaar 
2083c1e38eaSMarcel Moolenaar 	dbg = 0;
2093c1e38eaSMarcel Moolenaar 	/*
2103c1e38eaSMarcel Moolenaar 	 * Error returns from this write are not really a problem;
2113c1e38eaSMarcel Moolenaar 	 * the process doesn't exist any more.
2123c1e38eaSMarcel Moolenaar 	 */
2133c1e38eaSMarcel Moolenaar 	ps_pwrite(ta->ph, ta->libkse_debug_addr, &dbg, sizeof(int));
2143c1e38eaSMarcel Moolenaar 	if (ta->map)
2153c1e38eaSMarcel Moolenaar 		free(ta->map);
2163c1e38eaSMarcel Moolenaar 	free(ta);
2173c1e38eaSMarcel Moolenaar 	return (TD_OK);
2183c1e38eaSMarcel Moolenaar }
2193c1e38eaSMarcel Moolenaar 
2203c1e38eaSMarcel Moolenaar static td_err_e
pt_ta_map_id2thr(const td_thragent_t * ta,thread_t id,td_thrhandle_t * th)2213c1e38eaSMarcel Moolenaar pt_ta_map_id2thr(const td_thragent_t *ta, thread_t id, td_thrhandle_t *th)
2223c1e38eaSMarcel Moolenaar {
2233c1e38eaSMarcel Moolenaar 	prgregset_t gregs;
2243c1e38eaSMarcel Moolenaar 	psaddr_t pt, tcb_addr;
2253c1e38eaSMarcel Moolenaar 	lwpid_t lwp;
2263c1e38eaSMarcel Moolenaar 	int ret;
2273c1e38eaSMarcel Moolenaar 
2283c1e38eaSMarcel Moolenaar 	TDBG_FUNC();
2293c1e38eaSMarcel Moolenaar 
2308413ef57SPedro F. Giffuni 	if (id < 0 || id >= (long)ta->map_len || ta->map[id].type == PT_NONE)
2313c1e38eaSMarcel Moolenaar 		return (TD_NOTHR);
23203fad2adSMarcel Moolenaar 
23303fad2adSMarcel Moolenaar 	ret = thr_pread_ptr(ta, ta->thread_list_addr, &pt);
2343c1e38eaSMarcel Moolenaar 	if (ret != 0)
23503fad2adSMarcel Moolenaar 		return (TD_ERR);
2363c1e38eaSMarcel Moolenaar 	if (ta->map[id].type == PT_LWP) {
2373c1e38eaSMarcel Moolenaar 		/*
2383c1e38eaSMarcel Moolenaar 		 * if we are referencing a lwp, make sure it was not already
2393c1e38eaSMarcel Moolenaar 		 * mapped to user thread.
2403c1e38eaSMarcel Moolenaar 		 */
2413c1e38eaSMarcel Moolenaar 		while (pt != 0) {
24203fad2adSMarcel Moolenaar 			ret = thr_pread_ptr(ta, pt + ta->thread_off_tcb,
24303fad2adSMarcel Moolenaar 			    &tcb_addr);
2443c1e38eaSMarcel Moolenaar 			if (ret != 0)
24503fad2adSMarcel Moolenaar 				return (TD_ERR);
24603fad2adSMarcel Moolenaar 			ret = thr_pread_int(ta, tcb_addr + ta->thread_off_tmbx +
24703fad2adSMarcel Moolenaar 			    offsetof(struct kse_thr_mailbox, tm_lwp), &lwp);
2483c1e38eaSMarcel Moolenaar 			if (ret != 0)
24903fad2adSMarcel Moolenaar 				return (TD_ERR);
2503c1e38eaSMarcel Moolenaar 			/*
2513c1e38eaSMarcel Moolenaar 			 * If the lwp was already mapped to userland thread,
2523c1e38eaSMarcel Moolenaar 			 * we shouldn't reference it directly in future.
2533c1e38eaSMarcel Moolenaar 			 */
2543c1e38eaSMarcel Moolenaar 			if (lwp == ta->map[id].lwp) {
2553c1e38eaSMarcel Moolenaar 				ta->map[id].type = PT_NONE;
2563c1e38eaSMarcel Moolenaar 				return (TD_NOTHR);
2573c1e38eaSMarcel Moolenaar 			}
2583c1e38eaSMarcel Moolenaar 			/* get next thread */
25903fad2adSMarcel Moolenaar 			ret = thr_pread_ptr(ta, pt + ta->thread_off_next, &pt);
2603c1e38eaSMarcel Moolenaar 			if (ret != 0)
26103fad2adSMarcel Moolenaar 				return (TD_ERR);
2623c1e38eaSMarcel Moolenaar 		}
2633c1e38eaSMarcel Moolenaar 		/* check lwp */
2644db106a9SDavid Xu 		ret = ps_lgetregs(ta->ph, ta->map[id].lwp, gregs);
2654db106a9SDavid Xu 		if (ret != PS_OK) {
2663c1e38eaSMarcel Moolenaar 			/* no longer exists */
2673c1e38eaSMarcel Moolenaar 			ta->map[id].type = PT_NONE;
2683c1e38eaSMarcel Moolenaar 			return (TD_NOTHR);
2693c1e38eaSMarcel Moolenaar 		}
2703c1e38eaSMarcel Moolenaar 	} else {
2713c1e38eaSMarcel Moolenaar 		while (pt != 0 && ta->map[id].thr != pt) {
27203fad2adSMarcel Moolenaar 			ret = thr_pread_ptr(ta, pt + ta->thread_off_tcb,
27303fad2adSMarcel Moolenaar 			    &tcb_addr);
2743c1e38eaSMarcel Moolenaar 			if (ret != 0)
27503fad2adSMarcel Moolenaar 				return (TD_ERR);
2763c1e38eaSMarcel Moolenaar 			/* get next thread */
27703fad2adSMarcel Moolenaar 			ret = thr_pread_ptr(ta, pt + ta->thread_off_next, &pt);
2783c1e38eaSMarcel Moolenaar 			if (ret != 0)
27903fad2adSMarcel Moolenaar 				return (TD_ERR);
2803c1e38eaSMarcel Moolenaar 		}
2813c1e38eaSMarcel Moolenaar 
2823c1e38eaSMarcel Moolenaar 		if (pt == 0) {
2833c1e38eaSMarcel Moolenaar 			/* no longer exists */
2843c1e38eaSMarcel Moolenaar 			ta->map[id].type = PT_NONE;
2853c1e38eaSMarcel Moolenaar 			return (TD_NOTHR);
2863c1e38eaSMarcel Moolenaar 		}
2873c1e38eaSMarcel Moolenaar 	}
2883c1e38eaSMarcel Moolenaar 	th->th_ta = ta;
2893c1e38eaSMarcel Moolenaar 	th->th_tid = id;
2902ec2da86SDavid Xu 	th->th_thread = pt;
2913c1e38eaSMarcel Moolenaar 	return (TD_OK);
2923c1e38eaSMarcel Moolenaar }
2933c1e38eaSMarcel Moolenaar 
2943c1e38eaSMarcel Moolenaar static td_err_e
pt_ta_map_lwp2thr(const td_thragent_t * ta,lwpid_t lwp,td_thrhandle_t * th)2953c1e38eaSMarcel Moolenaar pt_ta_map_lwp2thr(const td_thragent_t *ta, lwpid_t lwp, td_thrhandle_t *th)
2963c1e38eaSMarcel Moolenaar {
29703fad2adSMarcel Moolenaar 	psaddr_t pt, tcb_addr;
29803fad2adSMarcel Moolenaar 	lwpid_t lwp1;
2993c1e38eaSMarcel Moolenaar 	int ret;
3003c1e38eaSMarcel Moolenaar 
3013c1e38eaSMarcel Moolenaar 	TDBG_FUNC();
3023c1e38eaSMarcel Moolenaar 
30303fad2adSMarcel Moolenaar 	ret = thr_pread_ptr(ta, ta->thread_list_addr, &pt);
3043c1e38eaSMarcel Moolenaar 	if (ret != 0)
30503fad2adSMarcel Moolenaar 		return (TD_ERR);
3063c1e38eaSMarcel Moolenaar 	while (pt != 0) {
30703fad2adSMarcel Moolenaar 		ret = thr_pread_ptr(ta, pt + ta->thread_off_tcb, &tcb_addr);
3083c1e38eaSMarcel Moolenaar 		if (ret != 0)
30903fad2adSMarcel Moolenaar 			return (TD_ERR);
31003fad2adSMarcel Moolenaar 		ret = thr_pread_int(ta, tcb_addr + ta->thread_off_tmbx +
31103fad2adSMarcel Moolenaar 		    offsetof(struct kse_thr_mailbox, tm_lwp), &lwp1);
3123c1e38eaSMarcel Moolenaar 		if (ret != 0)
31303fad2adSMarcel Moolenaar 			return (TD_ERR);
31403fad2adSMarcel Moolenaar 		if (lwp1 == lwp) {
3153c1e38eaSMarcel Moolenaar 			th->th_ta = ta;
3163c1e38eaSMarcel Moolenaar 			th->th_tid = pt_map_thread(ta, pt, PT_USER);
3173c1e38eaSMarcel Moolenaar 			if (th->th_tid == -1)
3183c1e38eaSMarcel Moolenaar 				return (TD_MALLOC);
3193c1e38eaSMarcel Moolenaar 			pt_unmap_lwp(ta, lwp);
3202ec2da86SDavid Xu 			th->th_thread = pt;
3213c1e38eaSMarcel Moolenaar 			return (TD_OK);
3223c1e38eaSMarcel Moolenaar 		}
3233c1e38eaSMarcel Moolenaar 
3243c1e38eaSMarcel Moolenaar 		/* get next thread */
32503fad2adSMarcel Moolenaar 		ret = thr_pread_ptr(ta, pt + ta->thread_off_next, &pt);
3263c1e38eaSMarcel Moolenaar 		if (ret != 0)
32703fad2adSMarcel Moolenaar 			return (TD_ERR);
3283c1e38eaSMarcel Moolenaar 	}
3293c1e38eaSMarcel Moolenaar 
3303c1e38eaSMarcel Moolenaar 	return (TD_NOTHR);
3313c1e38eaSMarcel Moolenaar }
3323c1e38eaSMarcel Moolenaar 
3333c1e38eaSMarcel Moolenaar static td_err_e
pt_ta_thr_iter(const td_thragent_t * ta,td_thr_iter_f * callback,void * cbdata_p,td_thr_state_e state __unused,int ti_pri __unused,sigset_t * ti_sigmask_p __unused,unsigned int ti_user_flags __unused)334f60a5b31SMarcel Moolenaar pt_ta_thr_iter(const td_thragent_t *ta, td_thr_iter_f *callback,
335f60a5b31SMarcel Moolenaar     void *cbdata_p, td_thr_state_e state __unused, int ti_pri __unused,
336f60a5b31SMarcel Moolenaar     sigset_t *ti_sigmask_p __unused, unsigned int ti_user_flags __unused)
3373c1e38eaSMarcel Moolenaar {
3383c1e38eaSMarcel Moolenaar 	td_thrhandle_t th;
3393c1e38eaSMarcel Moolenaar 	psaddr_t pt;
3403c1e38eaSMarcel Moolenaar 	ps_err_e pserr;
34103fad2adSMarcel Moolenaar 	int activated, ret;
3423c1e38eaSMarcel Moolenaar 
3433c1e38eaSMarcel Moolenaar 	TDBG_FUNC();
3443c1e38eaSMarcel Moolenaar 
3453c1e38eaSMarcel Moolenaar 	pserr = ps_pread(ta->ph, ta->thread_activated_addr, &activated,
3463c1e38eaSMarcel Moolenaar 	    sizeof(int));
3473c1e38eaSMarcel Moolenaar 	if (pserr != PS_OK)
3483c1e38eaSMarcel Moolenaar 		return (P2T(pserr));
3493c1e38eaSMarcel Moolenaar 	if (!activated)
3503c1e38eaSMarcel Moolenaar 		return (TD_OK);
3513c1e38eaSMarcel Moolenaar 
35203fad2adSMarcel Moolenaar 	ret = thr_pread_ptr(ta, ta->thread_list_addr, &pt);
35303fad2adSMarcel Moolenaar 	if (ret != 0)
35403fad2adSMarcel Moolenaar 		return (TD_ERR);
3553c1e38eaSMarcel Moolenaar 	while (pt != 0) {
3563c1e38eaSMarcel Moolenaar 		th.th_ta = ta;
3573c1e38eaSMarcel Moolenaar 		th.th_tid = pt_map_thread(ta, pt, PT_USER);
3582ec2da86SDavid Xu 		th.th_thread = pt;
3593c1e38eaSMarcel Moolenaar 		/* should we unmap lwp here ? */
3603c1e38eaSMarcel Moolenaar 		if (th.th_tid == -1)
3613c1e38eaSMarcel Moolenaar 			return (TD_MALLOC);
3623c1e38eaSMarcel Moolenaar 		if ((*callback)(&th, cbdata_p))
3633c1e38eaSMarcel Moolenaar 			return (TD_DBERR);
3643c1e38eaSMarcel Moolenaar 		/* get next thread */
36503fad2adSMarcel Moolenaar 		ret = thr_pread_ptr(ta, pt + ta->thread_off_next, &pt);
36603fad2adSMarcel Moolenaar 		if (ret != 0)
36703fad2adSMarcel Moolenaar 			return (TD_ERR);
3683c1e38eaSMarcel Moolenaar 	}
3693c1e38eaSMarcel Moolenaar 	return (TD_OK);
3703c1e38eaSMarcel Moolenaar }
3713c1e38eaSMarcel Moolenaar 
3723c1e38eaSMarcel Moolenaar static td_err_e
pt_ta_tsd_iter(const td_thragent_t * ta,td_key_iter_f * ki,void * arg)3733c1e38eaSMarcel Moolenaar pt_ta_tsd_iter(const td_thragent_t *ta, td_key_iter_f *ki, void *arg)
3743c1e38eaSMarcel Moolenaar {
375f60a5b31SMarcel Moolenaar 	void *keytable;
376cd980d46SDavid Xu 	void *destructor;
377cd980d46SDavid Xu 	int i, ret, allocated;
3783c1e38eaSMarcel Moolenaar 
3793c1e38eaSMarcel Moolenaar 	TDBG_FUNC();
3803c1e38eaSMarcel Moolenaar 
381cd980d46SDavid Xu 	keytable = malloc(ta->thread_max_keys * ta->thread_size_key);
382cd980d46SDavid Xu 	if (keytable == NULL)
383cd980d46SDavid Xu 		return (TD_MALLOC);
3843c1e38eaSMarcel Moolenaar 	ret = ps_pread(ta->ph, (psaddr_t)ta->thread_keytable_addr, keytable,
385cd980d46SDavid Xu 	               ta->thread_max_keys * ta->thread_size_key);
3862eb43a64SDavid Xu 	if (ret != 0) {
3872eb43a64SDavid Xu 		free(keytable);
3883c1e38eaSMarcel Moolenaar 		return (P2T(ret));
3892eb43a64SDavid Xu 	}
390cd980d46SDavid Xu 	for (i = 0; i < ta->thread_max_keys; i++) {
391f60a5b31SMarcel Moolenaar 		allocated = *(int *)(void *)((uintptr_t)keytable +
392f60a5b31SMarcel Moolenaar 		    i * ta->thread_size_key + ta->thread_off_key_allocated);
393f60a5b31SMarcel Moolenaar 		destructor = *(void **)(void *)((uintptr_t)keytable +
394f60a5b31SMarcel Moolenaar 		    i * ta->thread_size_key + ta->thread_off_key_destructor);
395cd980d46SDavid Xu 		if (allocated) {
396cd980d46SDavid Xu 			ret = (ki)(i, destructor, arg);
397cd980d46SDavid Xu 			if (ret != 0) {
398cd980d46SDavid Xu 				free(keytable);
3993c1e38eaSMarcel Moolenaar 				return (TD_DBERR);
4003c1e38eaSMarcel Moolenaar 			}
4013c1e38eaSMarcel Moolenaar 		}
402cd980d46SDavid Xu 	}
403cd980d46SDavid Xu 	free(keytable);
4043c1e38eaSMarcel Moolenaar 	return (TD_OK);
4053c1e38eaSMarcel Moolenaar }
4063c1e38eaSMarcel Moolenaar 
4073c1e38eaSMarcel Moolenaar static td_err_e
pt_ta_event_addr(const td_thragent_t * ta __unused,td_event_e event __unused,td_notify_t * ptr __unused)408f60a5b31SMarcel Moolenaar pt_ta_event_addr(const td_thragent_t *ta __unused, td_event_e event __unused,
409f60a5b31SMarcel Moolenaar     td_notify_t *ptr __unused)
4103c1e38eaSMarcel Moolenaar {
4113c1e38eaSMarcel Moolenaar 	TDBG_FUNC();
412a80845eaSDavid Xu 	return (TD_ERR);
4133c1e38eaSMarcel Moolenaar }
4143c1e38eaSMarcel Moolenaar 
4153c1e38eaSMarcel Moolenaar static td_err_e
pt_ta_set_event(const td_thragent_t * ta __unused,td_thr_events_t * events __unused)416f60a5b31SMarcel Moolenaar pt_ta_set_event(const td_thragent_t *ta __unused,
417f60a5b31SMarcel Moolenaar     td_thr_events_t *events __unused)
4183c1e38eaSMarcel Moolenaar {
4193c1e38eaSMarcel Moolenaar 	TDBG_FUNC();
420a80845eaSDavid Xu 	return (0);
4213c1e38eaSMarcel Moolenaar }
4223c1e38eaSMarcel Moolenaar 
4233c1e38eaSMarcel Moolenaar static td_err_e
pt_ta_clear_event(const td_thragent_t * ta __unused,td_thr_events_t * events __unused)424f60a5b31SMarcel Moolenaar pt_ta_clear_event(const td_thragent_t *ta __unused,
425f60a5b31SMarcel Moolenaar     td_thr_events_t *events __unused)
4263c1e38eaSMarcel Moolenaar {
4273c1e38eaSMarcel Moolenaar 	TDBG_FUNC();
428a80845eaSDavid Xu 	return (0);
4293c1e38eaSMarcel Moolenaar }
4303c1e38eaSMarcel Moolenaar 
4313c1e38eaSMarcel Moolenaar static td_err_e
pt_ta_event_getmsg(const td_thragent_t * ta __unused,td_event_msg_t * msg __unused)432f60a5b31SMarcel Moolenaar pt_ta_event_getmsg(const td_thragent_t *ta __unused,
433f60a5b31SMarcel Moolenaar     td_event_msg_t *msg __unused)
4343c1e38eaSMarcel Moolenaar {
4353c1e38eaSMarcel Moolenaar 	TDBG_FUNC();
4363c1e38eaSMarcel Moolenaar 	return (TD_NOMSG);
4373c1e38eaSMarcel Moolenaar }
4383c1e38eaSMarcel Moolenaar 
4393c1e38eaSMarcel Moolenaar static td_err_e
pt_dbsuspend(const td_thrhandle_t * th,int suspend)440447d36ecSDavid Xu pt_dbsuspend(const td_thrhandle_t *th, int suspend)
441447d36ecSDavid Xu {
442f60a5b31SMarcel Moolenaar 	const td_thragent_t *ta = th->th_ta;
443447d36ecSDavid Xu 	psaddr_t tcb_addr, tmbx_addr, ptr;
444447d36ecSDavid Xu 	lwpid_t lwp;
445447d36ecSDavid Xu 	uint32_t dflags;
4463e93cc3aSDavid Xu 	int attrflags, locklevel, ret;
447447d36ecSDavid Xu 
448447d36ecSDavid Xu 	TDBG_FUNC();
449447d36ecSDavid Xu 
450447d36ecSDavid Xu 	ret = pt_validate(th);
451447d36ecSDavid Xu 	if (ret)
452447d36ecSDavid Xu 		return (ret);
453447d36ecSDavid Xu 
454447d36ecSDavid Xu 	if (ta->map[th->th_tid].type == PT_LWP) {
455447d36ecSDavid Xu 		if (suspend)
456447d36ecSDavid Xu 			ret = ps_lstop(ta->ph, ta->map[th->th_tid].lwp);
457447d36ecSDavid Xu 		else
458447d36ecSDavid Xu 			ret = ps_lcontinue(ta->ph, ta->map[th->th_tid].lwp);
459447d36ecSDavid Xu 		return (P2T(ret));
460447d36ecSDavid Xu 	}
461447d36ecSDavid Xu 
462447d36ecSDavid Xu 	ret = ps_pread(ta->ph, ta->map[th->th_tid].thr +
463cd980d46SDavid Xu 		ta->thread_off_attr_flags,
464447d36ecSDavid Xu 		&attrflags, sizeof(attrflags));
465447d36ecSDavid Xu 	if (ret != 0)
466447d36ecSDavid Xu 		return (P2T(ret));
467447d36ecSDavid Xu 	ret = ps_pread(ta->ph, ta->map[th->th_tid].thr +
468cd980d46SDavid Xu 	               ta->thread_off_tcb,
469447d36ecSDavid Xu 	               &tcb_addr, sizeof(tcb_addr));
470447d36ecSDavid Xu 	if (ret != 0)
471447d36ecSDavid Xu 		return (P2T(ret));
472cd980d46SDavid Xu 	tmbx_addr = tcb_addr + ta->thread_off_tmbx;
473447d36ecSDavid Xu 	ptr = tmbx_addr + offsetof(struct kse_thr_mailbox, tm_lwp);
474447d36ecSDavid Xu 	ret = ps_pread(ta->ph, ptr, &lwp, sizeof(lwpid_t));
475447d36ecSDavid Xu 	if (ret != 0)
476447d36ecSDavid Xu 		return (P2T(ret));
4773e93cc3aSDavid Xu 
4783e93cc3aSDavid Xu 	if (lwp != 0) {
4793e93cc3aSDavid Xu 		/* don't suspend signal thread */
480cd980d46SDavid Xu 		if (attrflags & 0x200)
4813e93cc3aSDavid Xu 			return (0);
4823e93cc3aSDavid Xu 		if (attrflags & PTHREAD_SCOPE_SYSTEM) {
4833e93cc3aSDavid Xu 			/*
4843e93cc3aSDavid Xu 			 * don't suspend system scope thread if it is holding
4853e93cc3aSDavid Xu 			 * some low level locks
4863e93cc3aSDavid Xu 			 */
487cd980d46SDavid Xu 			ptr = ta->map[th->th_tid].thr + ta->thread_off_kse;
488447d36ecSDavid Xu 			ret = ps_pread(ta->ph, ptr, &ptr, sizeof(ptr));
489447d36ecSDavid Xu 			if (ret != 0)
490447d36ecSDavid Xu 				return (P2T(ret));
491cd980d46SDavid Xu 			ret = ps_pread(ta->ph, ptr + ta->thread_off_kse_locklevel,
492cd980d46SDavid Xu 				&locklevel, sizeof(int));
493447d36ecSDavid Xu 			if (ret != 0)
494447d36ecSDavid Xu 				return (P2T(ret));
4953e93cc3aSDavid Xu 			if (locklevel <= 0) {
4963e93cc3aSDavid Xu 				ptr = ta->map[th->th_tid].thr +
497cd980d46SDavid Xu 					ta->thread_off_thr_locklevel;
4983e93cc3aSDavid Xu 				ret = ps_pread(ta->ph, ptr, &locklevel,
4993e93cc3aSDavid Xu 					sizeof(int));
500447d36ecSDavid Xu 				if (ret != 0)
501447d36ecSDavid Xu 					return (P2T(ret));
502447d36ecSDavid Xu 			}
5033e93cc3aSDavid Xu 			if (suspend) {
5043e93cc3aSDavid Xu 				if (locklevel <= 0)
5053e93cc3aSDavid Xu 					ret = ps_lstop(ta->ph, lwp);
5063e93cc3aSDavid Xu 			} else {
5073e93cc3aSDavid Xu 				ret = ps_lcontinue(ta->ph, lwp);
5083e93cc3aSDavid Xu 			}
5093e93cc3aSDavid Xu 			if (ret != 0)
5103e93cc3aSDavid Xu 				return (P2T(ret));
511447d36ecSDavid Xu 			/* FALLTHROUGH */
5123e93cc3aSDavid Xu 		} else {
5133e93cc3aSDavid Xu 			struct ptrace_lwpinfo pl;
5143e93cc3aSDavid Xu 
5156ff81bf5SDavid Xu 			if (ps_linfo(ta->ph, lwp, (caddr_t)&pl))
5163e93cc3aSDavid Xu 				return (TD_ERR);
5173e93cc3aSDavid Xu 			if (suspend) {
5183e93cc3aSDavid Xu 				if (!(pl.pl_flags & PL_FLAG_BOUND))
5193e93cc3aSDavid Xu 					ret = ps_lstop(ta->ph, lwp);
5203e93cc3aSDavid Xu 			} else {
5213e93cc3aSDavid Xu 				ret = ps_lcontinue(ta->ph, lwp);
5223e93cc3aSDavid Xu 			}
5233e93cc3aSDavid Xu 			if (ret != 0)
5243e93cc3aSDavid Xu 				return (P2T(ret));
5253e93cc3aSDavid Xu 			/* FALLTHROUGH */
5263e93cc3aSDavid Xu 		}
527447d36ecSDavid Xu 	}
528447d36ecSDavid Xu 	/* read tm_dflags */
529447d36ecSDavid Xu 	ret = ps_pread(ta->ph,
530447d36ecSDavid Xu 		tmbx_addr + offsetof(struct kse_thr_mailbox, tm_dflags),
531447d36ecSDavid Xu 		&dflags, sizeof(dflags));
532447d36ecSDavid Xu 	if (ret != 0)
533447d36ecSDavid Xu 		return (P2T(ret));
534447d36ecSDavid Xu 	if (suspend)
5354513fb36SDavid Xu 		dflags |= TMDF_SUSPEND;
536447d36ecSDavid Xu 	else
5374513fb36SDavid Xu 		dflags &= ~TMDF_SUSPEND;
538447d36ecSDavid Xu 	ret = ps_pwrite(ta->ph,
539447d36ecSDavid Xu 	       tmbx_addr + offsetof(struct kse_thr_mailbox, tm_dflags),
540447d36ecSDavid Xu 	       &dflags, sizeof(dflags));
541447d36ecSDavid Xu 	return (P2T(ret));
542447d36ecSDavid Xu }
543447d36ecSDavid Xu 
544447d36ecSDavid Xu static td_err_e
pt_thr_dbresume(const td_thrhandle_t * th)5453c1e38eaSMarcel Moolenaar pt_thr_dbresume(const td_thrhandle_t *th)
5463c1e38eaSMarcel Moolenaar {
5473c1e38eaSMarcel Moolenaar 	TDBG_FUNC();
548447d36ecSDavid Xu 
549447d36ecSDavid Xu 	return pt_dbsuspend(th, 0);
5503c1e38eaSMarcel Moolenaar }
5513c1e38eaSMarcel Moolenaar 
5523c1e38eaSMarcel Moolenaar static td_err_e
pt_thr_dbsuspend(const td_thrhandle_t * th)5533c1e38eaSMarcel Moolenaar pt_thr_dbsuspend(const td_thrhandle_t *th)
5543c1e38eaSMarcel Moolenaar {
5553c1e38eaSMarcel Moolenaar 	TDBG_FUNC();
556447d36ecSDavid Xu 
557447d36ecSDavid Xu 	return pt_dbsuspend(th, 1);
5583c1e38eaSMarcel Moolenaar }
5593c1e38eaSMarcel Moolenaar 
5603c1e38eaSMarcel Moolenaar static td_err_e
pt_thr_validate(const td_thrhandle_t * th)5613c1e38eaSMarcel Moolenaar pt_thr_validate(const td_thrhandle_t *th)
5623c1e38eaSMarcel Moolenaar {
5633c1e38eaSMarcel Moolenaar 	td_thrhandle_t temp;
5643c1e38eaSMarcel Moolenaar 	int ret;
5653c1e38eaSMarcel Moolenaar 
5663c1e38eaSMarcel Moolenaar 	TDBG_FUNC();
5673c1e38eaSMarcel Moolenaar 
5683c1e38eaSMarcel Moolenaar 	ret = pt_ta_map_id2thr(th->th_ta, th->th_tid,
5693c1e38eaSMarcel Moolenaar 	                       &temp);
570447d36ecSDavid Xu 	return (ret);
5713c1e38eaSMarcel Moolenaar }
5723c1e38eaSMarcel Moolenaar 
5733c1e38eaSMarcel Moolenaar static td_err_e
pt_thr_old_get_info(const td_thrhandle_t * th,td_old_thrinfo_t * info)574098d0537SKonstantin Belousov pt_thr_old_get_info(const td_thrhandle_t *th, td_old_thrinfo_t *info)
5753c1e38eaSMarcel Moolenaar {
5763c1e38eaSMarcel Moolenaar 	const td_thragent_t *ta = th->th_ta;
5772ed66c93SDavid Xu 	struct ptrace_lwpinfo linfo;
578cd980d46SDavid Xu 	psaddr_t tcb_addr;
579447d36ecSDavid Xu 	uint32_t dflags;
5802ed66c93SDavid Xu 	lwpid_t lwp;
581cd980d46SDavid Xu 	int state;
582cd980d46SDavid Xu 	int ret;
5832ed66c93SDavid Xu 	int attrflags;
5843c1e38eaSMarcel Moolenaar 
5853c1e38eaSMarcel Moolenaar 	TDBG_FUNC();
5863c1e38eaSMarcel Moolenaar 
58783154c48SDavid Xu 	bzero(info, sizeof(*info));
5883c1e38eaSMarcel Moolenaar 	ret = pt_validate(th);
5893c1e38eaSMarcel Moolenaar 	if (ret)
5903c1e38eaSMarcel Moolenaar 		return (ret);
5913c1e38eaSMarcel Moolenaar 
5923c1e38eaSMarcel Moolenaar 	memset(info, 0, sizeof(*info));
5933c1e38eaSMarcel Moolenaar 	if (ta->map[th->th_tid].type == PT_LWP) {
5943c1e38eaSMarcel Moolenaar 		info->ti_type = TD_THR_SYSTEM;
5953c1e38eaSMarcel Moolenaar 		info->ti_lid = ta->map[th->th_tid].lwp;
5963c1e38eaSMarcel Moolenaar 		info->ti_tid = th->th_tid;
5973c1e38eaSMarcel Moolenaar 		info->ti_state = TD_THR_RUN;
5983c1e38eaSMarcel Moolenaar 		info->ti_type = TD_THR_SYSTEM;
5993c1e38eaSMarcel Moolenaar 		return (TD_OK);
6003c1e38eaSMarcel Moolenaar 	}
6012ed66c93SDavid Xu 
6022ed66c93SDavid Xu 	ret = ps_pread(ta->ph, ta->map[th->th_tid].thr +
6032ed66c93SDavid Xu 		ta->thread_off_attr_flags,
6042ed66c93SDavid Xu 		&attrflags, sizeof(attrflags));
6052ed66c93SDavid Xu 	if (ret != 0)
6062ed66c93SDavid Xu 		return (P2T(ret));
607cd980d46SDavid Xu 	ret = ps_pread(ta->ph, ta->map[th->th_tid].thr + ta->thread_off_tcb,
608cd980d46SDavid Xu 	               &tcb_addr, sizeof(tcb_addr));
6093c1e38eaSMarcel Moolenaar 	if (ret != 0)
6103c1e38eaSMarcel Moolenaar 		return (P2T(ret));
611cd980d46SDavid Xu 	ret = ps_pread(ta->ph, ta->map[th->th_tid].thr + ta->thread_off_state,
612cd980d46SDavid Xu 	               &state, sizeof(state));
6133c1e38eaSMarcel Moolenaar 	ret = ps_pread(ta->ph,
614cd980d46SDavid Xu 	        tcb_addr + ta->thread_off_tmbx +
615cd980d46SDavid Xu 		 offsetof(struct kse_thr_mailbox, tm_lwp),
6163c1e38eaSMarcel Moolenaar 	        &info->ti_lid, sizeof(lwpid_t));
6173c1e38eaSMarcel Moolenaar 	if (ret != 0)
6183c1e38eaSMarcel Moolenaar 		return (P2T(ret));
619447d36ecSDavid Xu 	ret = ps_pread(ta->ph,
620cd980d46SDavid Xu 		tcb_addr + ta->thread_off_tmbx +
621cd980d46SDavid Xu 		 offsetof(struct kse_thr_mailbox, tm_dflags),
622447d36ecSDavid Xu 		&dflags, sizeof(dflags));
623447d36ecSDavid Xu 	if (ret != 0)
624447d36ecSDavid Xu 		return (P2T(ret));
6252ed66c93SDavid Xu 	ret = ps_pread(ta->ph, tcb_addr + ta->thread_off_tmbx +
6262ed66c93SDavid Xu 		offsetof(struct kse_thr_mailbox, tm_lwp), &lwp, sizeof(lwpid_t));
6272ed66c93SDavid Xu 	if (ret != 0)
6282ed66c93SDavid Xu 		return (P2T(ret));
6293c1e38eaSMarcel Moolenaar 	info->ti_ta_p = th->th_ta;
6303c1e38eaSMarcel Moolenaar 	info->ti_tid = th->th_tid;
6312ed66c93SDavid Xu 
6322ed66c93SDavid Xu 	if (attrflags & PTHREAD_SCOPE_SYSTEM) {
6332ed66c93SDavid Xu 		ret = ps_linfo(ta->ph, lwp, &linfo);
6342ed66c93SDavid Xu 		if (ret == PS_OK) {
6352ed66c93SDavid Xu 			info->ti_sigmask = linfo.pl_sigmask;
6362ed66c93SDavid Xu 			info->ti_pending = linfo.pl_siglist;
6372ed66c93SDavid Xu 		} else
6382ed66c93SDavid Xu 			return (ret);
6392ed66c93SDavid Xu 	} else {
6402ed66c93SDavid Xu 		ret = ps_pread(ta->ph,
6412ed66c93SDavid Xu 			ta->map[th->th_tid].thr + ta->thread_off_sigmask,
6422ed66c93SDavid Xu 			&info->ti_sigmask, sizeof(sigset_t));
6432ed66c93SDavid Xu 		if (ret)
6442ed66c93SDavid Xu 			return (ret);
6452ed66c93SDavid Xu 		ret = ps_pread(ta->ph,
6462ed66c93SDavid Xu 			ta->map[th->th_tid].thr + ta->thread_off_sigpend,
6472ed66c93SDavid Xu 			&info->ti_pending, sizeof(sigset_t));
6482ed66c93SDavid Xu 		if (ret)
6492ed66c93SDavid Xu 			return (ret);
6502ed66c93SDavid Xu 	}
6512ed66c93SDavid Xu 
652cd980d46SDavid Xu 	if (state == ta->thread_state_running)
6533c1e38eaSMarcel Moolenaar 		info->ti_state = TD_THR_RUN;
654cd980d46SDavid Xu 	else if (state == ta->thread_state_zoombie)
6553c1e38eaSMarcel Moolenaar 		info->ti_state = TD_THR_ZOMBIE;
656cd980d46SDavid Xu 	else
657cd980d46SDavid Xu 		info->ti_state = TD_THR_SLEEP;
6584513fb36SDavid Xu 	info->ti_db_suspended = ((dflags & TMDF_SUSPEND) != 0);
6593c1e38eaSMarcel Moolenaar 	info->ti_type = TD_THR_USER;
6603c1e38eaSMarcel Moolenaar 	return (0);
6613c1e38eaSMarcel Moolenaar }
6623c1e38eaSMarcel Moolenaar 
663098d0537SKonstantin Belousov static td_err_e
pt_thr_get_info(const td_thrhandle_t * th,td_thrinfo_t * info)664098d0537SKonstantin Belousov pt_thr_get_info(const td_thrhandle_t *th, td_thrinfo_t *info)
665098d0537SKonstantin Belousov {
666098d0537SKonstantin Belousov 	td_err_e e;
667098d0537SKonstantin Belousov 
668098d0537SKonstantin Belousov 	e = pt_thr_old_get_info(th, (td_old_thrinfo_t *)info);
669098d0537SKonstantin Belousov 	bzero(&info->ti_siginfo, sizeof(info->ti_siginfo));
670098d0537SKonstantin Belousov 	return (e);
671098d0537SKonstantin Belousov }
672098d0537SKonstantin Belousov 
6738d7681bbSDoug Rabson #ifdef __i386__
6748d7681bbSDoug Rabson static td_err_e
pt_thr_getxmmregs(const td_thrhandle_t * th,char * fxsave)6758d7681bbSDoug Rabson pt_thr_getxmmregs(const td_thrhandle_t *th, char *fxsave)
6768d7681bbSDoug Rabson {
6778d7681bbSDoug Rabson 	const td_thragent_t *ta = th->th_ta;
6788d7681bbSDoug Rabson 	struct kse_thr_mailbox tmbx;
6798d7681bbSDoug Rabson 	psaddr_t tcb_addr, tmbx_addr, ptr;
6808d7681bbSDoug Rabson 	lwpid_t lwp;
6818d7681bbSDoug Rabson 	int ret;
6828d7681bbSDoug Rabson 
6838d7681bbSDoug Rabson 	return TD_ERR;
6848d7681bbSDoug Rabson 
6858d7681bbSDoug Rabson 	TDBG_FUNC();
6868d7681bbSDoug Rabson 
6878d7681bbSDoug Rabson 	ret = pt_validate(th);
6888d7681bbSDoug Rabson 	if (ret)
6898d7681bbSDoug Rabson 		return (ret);
6908d7681bbSDoug Rabson 
6918d7681bbSDoug Rabson 	if (ta->map[th->th_tid].type == PT_LWP) {
6928d7681bbSDoug Rabson 		ret = ps_lgetxmmregs(ta->ph, ta->map[th->th_tid].lwp, fxsave);
6938d7681bbSDoug Rabson 		return (P2T(ret));
6948d7681bbSDoug Rabson 	}
6958d7681bbSDoug Rabson 
6968d7681bbSDoug Rabson 	ret = ps_pread(ta->ph, ta->map[th->th_tid].thr + ta->thread_off_tcb,
6978d7681bbSDoug Rabson 	               &tcb_addr, sizeof(tcb_addr));
6988d7681bbSDoug Rabson 	if (ret != 0)
6998d7681bbSDoug Rabson 		return (P2T(ret));
7008d7681bbSDoug Rabson 	tmbx_addr = tcb_addr + ta->thread_off_tmbx;
7018d7681bbSDoug Rabson 	ptr = tmbx_addr + offsetof(struct kse_thr_mailbox, tm_lwp);
7028d7681bbSDoug Rabson 	ret = ps_pread(ta->ph, ptr, &lwp, sizeof(lwpid_t));
7038d7681bbSDoug Rabson 	if (ret != 0)
7048d7681bbSDoug Rabson 		return (P2T(ret));
7058d7681bbSDoug Rabson 	if (lwp != 0) {
7068d7681bbSDoug Rabson 		ret = ps_lgetxmmregs(ta->ph, lwp, fxsave);
7078d7681bbSDoug Rabson 		return (P2T(ret));
7088d7681bbSDoug Rabson 	}
7098d7681bbSDoug Rabson 
7108d7681bbSDoug Rabson 	ret = ps_pread(ta->ph, tmbx_addr, &tmbx, sizeof(tmbx));
7118d7681bbSDoug Rabson 	if (ret != 0)
7128d7681bbSDoug Rabson 		return (P2T(ret));
7138d7681bbSDoug Rabson 	pt_ucontext_to_fxsave(&tmbx.tm_context, fxsave);
7148d7681bbSDoug Rabson 	return (0);
7158d7681bbSDoug Rabson }
7168d7681bbSDoug Rabson #endif
7178d7681bbSDoug Rabson 
7183c1e38eaSMarcel Moolenaar static td_err_e
pt_thr_getfpregs(const td_thrhandle_t * th,prfpregset_t * fpregs)7193c1e38eaSMarcel Moolenaar pt_thr_getfpregs(const td_thrhandle_t *th, prfpregset_t *fpregs)
7203c1e38eaSMarcel Moolenaar {
7213c1e38eaSMarcel Moolenaar 	const td_thragent_t *ta = th->th_ta;
7223c1e38eaSMarcel Moolenaar 	struct kse_thr_mailbox tmbx;
7233c1e38eaSMarcel Moolenaar 	psaddr_t tcb_addr, tmbx_addr, ptr;
7243c1e38eaSMarcel Moolenaar 	lwpid_t lwp;
7253c1e38eaSMarcel Moolenaar 	int ret;
7263c1e38eaSMarcel Moolenaar 
7273c1e38eaSMarcel Moolenaar 	TDBG_FUNC();
7283c1e38eaSMarcel Moolenaar 
7293c1e38eaSMarcel Moolenaar 	ret = pt_validate(th);
7303c1e38eaSMarcel Moolenaar 	if (ret)
7313c1e38eaSMarcel Moolenaar 		return (ret);
7323c1e38eaSMarcel Moolenaar 
7333c1e38eaSMarcel Moolenaar 	if (ta->map[th->th_tid].type == PT_LWP) {
7343c1e38eaSMarcel Moolenaar 		ret = ps_lgetfpregs(ta->ph, ta->map[th->th_tid].lwp, fpregs);
7353c1e38eaSMarcel Moolenaar 		return (P2T(ret));
7363c1e38eaSMarcel Moolenaar 	}
7373c1e38eaSMarcel Moolenaar 
738cd980d46SDavid Xu 	ret = ps_pread(ta->ph, ta->map[th->th_tid].thr + ta->thread_off_tcb,
7393c1e38eaSMarcel Moolenaar 	               &tcb_addr, sizeof(tcb_addr));
7403c1e38eaSMarcel Moolenaar 	if (ret != 0)
7413c1e38eaSMarcel Moolenaar 		return (P2T(ret));
742cd980d46SDavid Xu 	tmbx_addr = tcb_addr + ta->thread_off_tmbx;
7433c1e38eaSMarcel Moolenaar 	ptr = tmbx_addr + offsetof(struct kse_thr_mailbox, tm_lwp);
7443c1e38eaSMarcel Moolenaar 	ret = ps_pread(ta->ph, ptr, &lwp, sizeof(lwpid_t));
7453c1e38eaSMarcel Moolenaar 	if (ret != 0)
7463c1e38eaSMarcel Moolenaar 		return (P2T(ret));
7473c1e38eaSMarcel Moolenaar 	if (lwp != 0) {
7483c1e38eaSMarcel Moolenaar 		ret = ps_lgetfpregs(ta->ph, lwp, fpregs);
7493c1e38eaSMarcel Moolenaar 		return (P2T(ret));
7503c1e38eaSMarcel Moolenaar 	}
7513c1e38eaSMarcel Moolenaar 
7523c1e38eaSMarcel Moolenaar 	ret = ps_pread(ta->ph, tmbx_addr, &tmbx, sizeof(tmbx));
7533c1e38eaSMarcel Moolenaar 	if (ret != 0)
7543c1e38eaSMarcel Moolenaar 		return (P2T(ret));
7553c1e38eaSMarcel Moolenaar 	pt_ucontext_to_fpreg(&tmbx.tm_context, fpregs);
7563c1e38eaSMarcel Moolenaar 	return (0);
7573c1e38eaSMarcel Moolenaar }
7583c1e38eaSMarcel Moolenaar 
7593c1e38eaSMarcel Moolenaar static td_err_e
pt_thr_getgregs(const td_thrhandle_t * th,prgregset_t gregs)7603c1e38eaSMarcel Moolenaar pt_thr_getgregs(const td_thrhandle_t *th, prgregset_t gregs)
7613c1e38eaSMarcel Moolenaar {
7623c1e38eaSMarcel Moolenaar 	const td_thragent_t *ta = th->th_ta;
7633c1e38eaSMarcel Moolenaar 	struct kse_thr_mailbox tmbx;
7643c1e38eaSMarcel Moolenaar 	psaddr_t tcb_addr, tmbx_addr, ptr;
7653c1e38eaSMarcel Moolenaar 	lwpid_t lwp;
7663c1e38eaSMarcel Moolenaar 	int ret;
7673c1e38eaSMarcel Moolenaar 
7683c1e38eaSMarcel Moolenaar 	TDBG_FUNC();
7693c1e38eaSMarcel Moolenaar 
7703c1e38eaSMarcel Moolenaar 	ret = pt_validate(th);
7713c1e38eaSMarcel Moolenaar 	if (ret)
7723c1e38eaSMarcel Moolenaar 		return (ret);
7733c1e38eaSMarcel Moolenaar 
7743c1e38eaSMarcel Moolenaar 	if (ta->map[th->th_tid].type == PT_LWP) {
7753c1e38eaSMarcel Moolenaar 		ret = ps_lgetregs(ta->ph,
7763c1e38eaSMarcel Moolenaar 		                  ta->map[th->th_tid].lwp, gregs);
7773c1e38eaSMarcel Moolenaar 		return (P2T(ret));
7783c1e38eaSMarcel Moolenaar 	}
7793c1e38eaSMarcel Moolenaar 
780cd980d46SDavid Xu 	ret = ps_pread(ta->ph, ta->map[th->th_tid].thr + ta->thread_off_tcb,
7813c1e38eaSMarcel Moolenaar 			&tcb_addr, sizeof(tcb_addr));
7823c1e38eaSMarcel Moolenaar 	if (ret != 0)
7833c1e38eaSMarcel Moolenaar 		return (P2T(ret));
784cd980d46SDavid Xu 	tmbx_addr = tcb_addr + ta->thread_off_tmbx;
7853c1e38eaSMarcel Moolenaar 	ptr = tmbx_addr + offsetof(struct kse_thr_mailbox, tm_lwp);
7863c1e38eaSMarcel Moolenaar 	ret = ps_pread(ta->ph, ptr, &lwp, sizeof(lwpid_t));
7873c1e38eaSMarcel Moolenaar 	if (ret != 0)
7883c1e38eaSMarcel Moolenaar 		return (P2T(ret));
7893c1e38eaSMarcel Moolenaar 	if (lwp != 0) {
7903c1e38eaSMarcel Moolenaar 		ret = ps_lgetregs(ta->ph, lwp, gregs);
7913c1e38eaSMarcel Moolenaar 		return (P2T(ret));
7923c1e38eaSMarcel Moolenaar 	}
7933c1e38eaSMarcel Moolenaar 	ret = ps_pread(ta->ph, tmbx_addr, &tmbx, sizeof(tmbx));
7943c1e38eaSMarcel Moolenaar 	if (ret != 0)
7953c1e38eaSMarcel Moolenaar 		return (P2T(ret));
7963c1e38eaSMarcel Moolenaar 	pt_ucontext_to_reg(&tmbx.tm_context, gregs);
7973c1e38eaSMarcel Moolenaar 	return (0);
7983c1e38eaSMarcel Moolenaar }
7993c1e38eaSMarcel Moolenaar 
8008d7681bbSDoug Rabson #ifdef __i386__
8018d7681bbSDoug Rabson static td_err_e
pt_thr_setxmmregs(const td_thrhandle_t * th,const char * fxsave)8028d7681bbSDoug Rabson pt_thr_setxmmregs(const td_thrhandle_t *th, const char *fxsave)
8038d7681bbSDoug Rabson {
8048d7681bbSDoug Rabson 	const td_thragent_t *ta = th->th_ta;
8058d7681bbSDoug Rabson 	struct kse_thr_mailbox tmbx;
8068d7681bbSDoug Rabson 	psaddr_t tcb_addr, tmbx_addr, ptr;
8078d7681bbSDoug Rabson 	lwpid_t lwp;
8088d7681bbSDoug Rabson 	int ret;
8098d7681bbSDoug Rabson 
8108d7681bbSDoug Rabson 	return TD_ERR;
8118d7681bbSDoug Rabson 
8128d7681bbSDoug Rabson 	TDBG_FUNC();
8138d7681bbSDoug Rabson 
8148d7681bbSDoug Rabson 	ret = pt_validate(th);
8158d7681bbSDoug Rabson 	if (ret)
8168d7681bbSDoug Rabson 		return (ret);
8178d7681bbSDoug Rabson 
8188d7681bbSDoug Rabson 	if (ta->map[th->th_tid].type == PT_LWP) {
8198d7681bbSDoug Rabson 		ret = ps_lsetxmmregs(ta->ph, ta->map[th->th_tid].lwp, fxsave);
8208d7681bbSDoug Rabson 		return (P2T(ret));
8218d7681bbSDoug Rabson 	}
8228d7681bbSDoug Rabson 
8238d7681bbSDoug Rabson 	ret = ps_pread(ta->ph, ta->map[th->th_tid].thr +
8248d7681bbSDoug Rabson 	                ta->thread_off_tcb,
8258d7681bbSDoug Rabson                         &tcb_addr, sizeof(tcb_addr));
8268d7681bbSDoug Rabson 	if (ret != 0)
8278d7681bbSDoug Rabson 		return (P2T(ret));
8288d7681bbSDoug Rabson 	tmbx_addr = tcb_addr + ta->thread_off_tmbx;
8298d7681bbSDoug Rabson 	ptr = tmbx_addr + offsetof(struct kse_thr_mailbox, tm_lwp);
8308d7681bbSDoug Rabson 	ret = ps_pread(ta->ph, ptr, &lwp, sizeof(lwpid_t));
8318d7681bbSDoug Rabson 	if (ret != 0)
8328d7681bbSDoug Rabson 		return (P2T(ret));
8338d7681bbSDoug Rabson 	if (lwp != 0) {
8348d7681bbSDoug Rabson 		ret = ps_lsetxmmregs(ta->ph, lwp, fxsave);
8358d7681bbSDoug Rabson 		return (P2T(ret));
8368d7681bbSDoug Rabson 	}
8378d7681bbSDoug Rabson 	/*
8388d7681bbSDoug Rabson 	 * Read a copy of context, this makes sure that registers
8398d7681bbSDoug Rabson 	 * not covered by structure reg won't be clobbered
8408d7681bbSDoug Rabson 	 */
8418d7681bbSDoug Rabson 	ret = ps_pread(ta->ph, tmbx_addr, &tmbx, sizeof(tmbx));
8428d7681bbSDoug Rabson 	if (ret != 0)
8438d7681bbSDoug Rabson 		return (P2T(ret));
8448d7681bbSDoug Rabson 
8458d7681bbSDoug Rabson 	pt_fxsave_to_ucontext(fxsave, &tmbx.tm_context);
8468d7681bbSDoug Rabson 	ret = ps_pwrite(ta->ph, tmbx_addr, &tmbx, sizeof(tmbx));
8478d7681bbSDoug Rabson 	return (P2T(ret));
8488d7681bbSDoug Rabson }
8498d7681bbSDoug Rabson #endif
8508d7681bbSDoug Rabson 
8513c1e38eaSMarcel Moolenaar static td_err_e
pt_thr_setfpregs(const td_thrhandle_t * th,const prfpregset_t * fpregs)8523c1e38eaSMarcel Moolenaar pt_thr_setfpregs(const td_thrhandle_t *th, const prfpregset_t *fpregs)
8533c1e38eaSMarcel Moolenaar {
8543c1e38eaSMarcel Moolenaar 	const td_thragent_t *ta = th->th_ta;
8553c1e38eaSMarcel Moolenaar 	struct kse_thr_mailbox tmbx;
8563c1e38eaSMarcel Moolenaar 	psaddr_t tcb_addr, tmbx_addr, ptr;
8573c1e38eaSMarcel Moolenaar 	lwpid_t lwp;
8583c1e38eaSMarcel Moolenaar 	int ret;
8593c1e38eaSMarcel Moolenaar 
8603c1e38eaSMarcel Moolenaar 	TDBG_FUNC();
8613c1e38eaSMarcel Moolenaar 
8623c1e38eaSMarcel Moolenaar 	ret = pt_validate(th);
8633c1e38eaSMarcel Moolenaar 	if (ret)
8643c1e38eaSMarcel Moolenaar 		return (ret);
8653c1e38eaSMarcel Moolenaar 
8663c1e38eaSMarcel Moolenaar 	if (ta->map[th->th_tid].type == PT_LWP) {
8673c1e38eaSMarcel Moolenaar 		ret = ps_lsetfpregs(ta->ph, ta->map[th->th_tid].lwp, fpregs);
8683c1e38eaSMarcel Moolenaar 		return (P2T(ret));
8693c1e38eaSMarcel Moolenaar 	}
8703c1e38eaSMarcel Moolenaar 
8713c1e38eaSMarcel Moolenaar 	ret = ps_pread(ta->ph, ta->map[th->th_tid].thr +
872cd980d46SDavid Xu 	                ta->thread_off_tcb,
8733c1e38eaSMarcel Moolenaar                         &tcb_addr, sizeof(tcb_addr));
8743c1e38eaSMarcel Moolenaar 	if (ret != 0)
8753c1e38eaSMarcel Moolenaar 		return (P2T(ret));
876cd980d46SDavid Xu 	tmbx_addr = tcb_addr + ta->thread_off_tmbx;
8773c1e38eaSMarcel Moolenaar 	ptr = tmbx_addr + offsetof(struct kse_thr_mailbox, tm_lwp);
8783c1e38eaSMarcel Moolenaar 	ret = ps_pread(ta->ph, ptr, &lwp, sizeof(lwpid_t));
8793c1e38eaSMarcel Moolenaar 	if (ret != 0)
8803c1e38eaSMarcel Moolenaar 		return (P2T(ret));
8813c1e38eaSMarcel Moolenaar 	if (lwp != 0) {
8823c1e38eaSMarcel Moolenaar 		ret = ps_lsetfpregs(ta->ph, lwp, fpregs);
8833c1e38eaSMarcel Moolenaar 		return (P2T(ret));
8843c1e38eaSMarcel Moolenaar 	}
8853c1e38eaSMarcel Moolenaar 	/*
8863c1e38eaSMarcel Moolenaar 	 * Read a copy of context, this makes sure that registers
8873c1e38eaSMarcel Moolenaar 	 * not covered by structure reg won't be clobbered
8883c1e38eaSMarcel Moolenaar 	 */
8893c1e38eaSMarcel Moolenaar 	ret = ps_pread(ta->ph, tmbx_addr, &tmbx, sizeof(tmbx));
8903c1e38eaSMarcel Moolenaar 	if (ret != 0)
8913c1e38eaSMarcel Moolenaar 		return (P2T(ret));
8923c1e38eaSMarcel Moolenaar 
8933c1e38eaSMarcel Moolenaar 	pt_fpreg_to_ucontext(fpregs, &tmbx.tm_context);
8943c1e38eaSMarcel Moolenaar 	ret = ps_pwrite(ta->ph, tmbx_addr, &tmbx, sizeof(tmbx));
8953c1e38eaSMarcel Moolenaar 	return (P2T(ret));
8963c1e38eaSMarcel Moolenaar }
8973c1e38eaSMarcel Moolenaar 
8983c1e38eaSMarcel Moolenaar static td_err_e
pt_thr_setgregs(const td_thrhandle_t * th,const prgregset_t gregs)8993c1e38eaSMarcel Moolenaar pt_thr_setgregs(const td_thrhandle_t *th, const prgregset_t gregs)
9003c1e38eaSMarcel Moolenaar {
9013c1e38eaSMarcel Moolenaar 	const td_thragent_t *ta = th->th_ta;
9023c1e38eaSMarcel Moolenaar 	struct kse_thr_mailbox tmbx;
9033c1e38eaSMarcel Moolenaar 	psaddr_t tcb_addr, tmbx_addr, ptr;
9043c1e38eaSMarcel Moolenaar 	lwpid_t lwp;
9053c1e38eaSMarcel Moolenaar 	int ret;
9063c1e38eaSMarcel Moolenaar 
9073c1e38eaSMarcel Moolenaar 	TDBG_FUNC();
9083c1e38eaSMarcel Moolenaar 
9093c1e38eaSMarcel Moolenaar 	ret = pt_validate(th);
9103c1e38eaSMarcel Moolenaar 	if (ret)
9113c1e38eaSMarcel Moolenaar 		return (ret);
9123c1e38eaSMarcel Moolenaar 
9133c1e38eaSMarcel Moolenaar 	if (ta->map[th->th_tid].type == PT_LWP) {
9143c1e38eaSMarcel Moolenaar 		ret = ps_lsetregs(ta->ph, ta->map[th->th_tid].lwp, gregs);
9153c1e38eaSMarcel Moolenaar 		return (P2T(ret));
9163c1e38eaSMarcel Moolenaar 	}
9173c1e38eaSMarcel Moolenaar 
9183c1e38eaSMarcel Moolenaar 	ret = ps_pread(ta->ph, ta->map[th->th_tid].thr +
919cd980d46SDavid Xu 	                ta->thread_off_tcb,
9203c1e38eaSMarcel Moolenaar 	                &tcb_addr, sizeof(tcb_addr));
9213c1e38eaSMarcel Moolenaar 	if (ret != 0)
9223c1e38eaSMarcel Moolenaar 		return (P2T(ret));
923cd980d46SDavid Xu 	tmbx_addr = tcb_addr + ta->thread_off_tmbx;
9243c1e38eaSMarcel Moolenaar 	ptr = tmbx_addr + offsetof(struct kse_thr_mailbox, tm_lwp);
9253c1e38eaSMarcel Moolenaar 	ret = ps_pread(ta->ph, ptr, &lwp, sizeof(lwpid_t));
9263c1e38eaSMarcel Moolenaar 	if (ret != 0)
9273c1e38eaSMarcel Moolenaar 		return (P2T(ret));
9283c1e38eaSMarcel Moolenaar 	if (lwp != 0) {
9293c1e38eaSMarcel Moolenaar 		ret = ps_lsetregs(ta->ph, lwp, gregs);
9303c1e38eaSMarcel Moolenaar 		return (P2T(ret));
9313c1e38eaSMarcel Moolenaar 	}
9323c1e38eaSMarcel Moolenaar 
9333c1e38eaSMarcel Moolenaar 	/*
9343c1e38eaSMarcel Moolenaar 	 * Read a copy of context, make sure that registers
9353c1e38eaSMarcel Moolenaar 	 * not covered by structure reg won't be clobbered
9363c1e38eaSMarcel Moolenaar 	 */
9373c1e38eaSMarcel Moolenaar 	ret = ps_pread(ta->ph, tmbx_addr, &tmbx, sizeof(tmbx));
9383c1e38eaSMarcel Moolenaar 	if (ret != 0)
9393c1e38eaSMarcel Moolenaar 		return (P2T(ret));
9403c1e38eaSMarcel Moolenaar 	pt_reg_to_ucontext(gregs, &tmbx.tm_context);
9413c1e38eaSMarcel Moolenaar 	ret = ps_pwrite(ta->ph, tmbx_addr, &tmbx, sizeof(tmbx));
9423c1e38eaSMarcel Moolenaar 	return (P2T(ret));
9433c1e38eaSMarcel Moolenaar }
9443c1e38eaSMarcel Moolenaar 
9453c1e38eaSMarcel Moolenaar static td_err_e
pt_thr_event_enable(const td_thrhandle_t * th __unused,int en __unused)946f60a5b31SMarcel Moolenaar pt_thr_event_enable(const td_thrhandle_t *th __unused, int en __unused)
9473c1e38eaSMarcel Moolenaar {
9483c1e38eaSMarcel Moolenaar 	TDBG_FUNC();
949a80845eaSDavid Xu 	return (0);
9503c1e38eaSMarcel Moolenaar }
9513c1e38eaSMarcel Moolenaar 
9523c1e38eaSMarcel Moolenaar static td_err_e
pt_thr_set_event(const td_thrhandle_t * th __unused,td_thr_events_t * setp __unused)953f60a5b31SMarcel Moolenaar pt_thr_set_event(const td_thrhandle_t *th __unused,
954f60a5b31SMarcel Moolenaar     td_thr_events_t *setp __unused)
9553c1e38eaSMarcel Moolenaar {
9563c1e38eaSMarcel Moolenaar 	TDBG_FUNC();
957a80845eaSDavid Xu 	return (0);
9583c1e38eaSMarcel Moolenaar }
9593c1e38eaSMarcel Moolenaar 
9603c1e38eaSMarcel Moolenaar static td_err_e
pt_thr_clear_event(const td_thrhandle_t * th __unused,td_thr_events_t * setp __unused)961f60a5b31SMarcel Moolenaar pt_thr_clear_event(const td_thrhandle_t *th __unused,
962f60a5b31SMarcel Moolenaar     td_thr_events_t *setp __unused)
9633c1e38eaSMarcel Moolenaar {
9643c1e38eaSMarcel Moolenaar 	TDBG_FUNC();
965a80845eaSDavid Xu 	return (0);
9663c1e38eaSMarcel Moolenaar }
9673c1e38eaSMarcel Moolenaar 
9683c1e38eaSMarcel Moolenaar static td_err_e
pt_thr_event_getmsg(const td_thrhandle_t * th __unused,td_event_msg_t * msg __unused)969f60a5b31SMarcel Moolenaar pt_thr_event_getmsg(const td_thrhandle_t *th __unused,
970f60a5b31SMarcel Moolenaar     td_event_msg_t *msg __unused)
9713c1e38eaSMarcel Moolenaar {
9723c1e38eaSMarcel Moolenaar 	TDBG_FUNC();
9733c1e38eaSMarcel Moolenaar 	return (TD_NOMSG);
9743c1e38eaSMarcel Moolenaar }
9753c1e38eaSMarcel Moolenaar 
9763c1e38eaSMarcel Moolenaar static td_err_e
pt_thr_sstep(const td_thrhandle_t * th,int step)9773c1e38eaSMarcel Moolenaar pt_thr_sstep(const td_thrhandle_t *th, int step)
9783c1e38eaSMarcel Moolenaar {
9793c1e38eaSMarcel Moolenaar 	const td_thragent_t *ta = th->th_ta;
9803c1e38eaSMarcel Moolenaar 	struct kse_thr_mailbox tmbx;
9813c1e38eaSMarcel Moolenaar 	struct reg regs;
9823c1e38eaSMarcel Moolenaar 	psaddr_t tcb_addr, tmbx_addr;
983447d36ecSDavid Xu 	uint32_t dflags;
9843c1e38eaSMarcel Moolenaar 	lwpid_t lwp;
9853c1e38eaSMarcel Moolenaar 	int ret;
9863c1e38eaSMarcel Moolenaar 
9873c1e38eaSMarcel Moolenaar 	TDBG_FUNC();
9883c1e38eaSMarcel Moolenaar 
9893c1e38eaSMarcel Moolenaar 	ret = pt_validate(th);
9903c1e38eaSMarcel Moolenaar 	if (ret)
9913c1e38eaSMarcel Moolenaar 		return (ret);
9923c1e38eaSMarcel Moolenaar 
9933c1e38eaSMarcel Moolenaar 	if (ta->map[th->th_tid].type == PT_LWP)
9943c1e38eaSMarcel Moolenaar 		return (TD_BADTH);
9953c1e38eaSMarcel Moolenaar 
9963c1e38eaSMarcel Moolenaar 	ret = ps_pread(ta->ph, ta->map[th->th_tid].thr +
997cd980d46SDavid Xu 	                ta->thread_off_tcb,
9983c1e38eaSMarcel Moolenaar 	                &tcb_addr, sizeof(tcb_addr));
9993c1e38eaSMarcel Moolenaar 	if (ret != 0)
10003c1e38eaSMarcel Moolenaar 		return (P2T(ret));
10013c1e38eaSMarcel Moolenaar 
10023c1e38eaSMarcel Moolenaar 	/* Clear or set single step flag in thread mailbox */
1003cd980d46SDavid Xu 	ret = ps_pread(ta->ph,
1004cd980d46SDavid Xu 		tcb_addr + ta->thread_off_tmbx +
1005cd980d46SDavid Xu 		 offsetof(struct kse_thr_mailbox, tm_dflags),
1006cd980d46SDavid Xu 		&dflags, sizeof(uint32_t));
1007447d36ecSDavid Xu 	if (ret != 0)
1008447d36ecSDavid Xu 		return (P2T(ret));
1009447d36ecSDavid Xu 	if (step != 0)
1010447d36ecSDavid Xu 		dflags |= TMDF_SSTEP;
1011447d36ecSDavid Xu 	else
1012447d36ecSDavid Xu 		dflags &= ~TMDF_SSTEP;
1013cd980d46SDavid Xu 	ret = ps_pwrite(ta->ph,
1014cd980d46SDavid Xu 		tcb_addr + ta->thread_off_tmbx +
1015cd980d46SDavid Xu 		 offsetof(struct kse_thr_mailbox, tm_dflags),
1016cd980d46SDavid Xu 	        &dflags, sizeof(uint32_t));
10173c1e38eaSMarcel Moolenaar 	if (ret != 0)
10183c1e38eaSMarcel Moolenaar 		return (P2T(ret));
10193c1e38eaSMarcel Moolenaar 	/* Get lwp */
1020cd980d46SDavid Xu 	ret = ps_pread(ta->ph,
1021cd980d46SDavid Xu 		tcb_addr + ta->thread_off_tmbx +
1022cd980d46SDavid Xu 		 offsetof(struct kse_thr_mailbox, tm_lwp),
1023cd980d46SDavid Xu 		&lwp, sizeof(lwpid_t));
10243c1e38eaSMarcel Moolenaar 	if (ret != 0)
10253c1e38eaSMarcel Moolenaar 		return (P2T(ret));
10263c1e38eaSMarcel Moolenaar 	if (lwp != 0)
1027447d36ecSDavid Xu 		return (0);
10283c1e38eaSMarcel Moolenaar 
1029cd980d46SDavid Xu 	tmbx_addr = tcb_addr + ta->thread_off_tmbx;
10303c1e38eaSMarcel Moolenaar 	/*
10313c1e38eaSMarcel Moolenaar 	 * context is in userland, some architectures store
10323c1e38eaSMarcel Moolenaar 	 * single step status in registers, we should change
10333c1e38eaSMarcel Moolenaar 	 * these registers.
10343c1e38eaSMarcel Moolenaar 	 */
10353c1e38eaSMarcel Moolenaar 	ret = ps_pread(ta->ph, tmbx_addr, &tmbx, sizeof(tmbx));
10363c1e38eaSMarcel Moolenaar 	if (ret == 0) {
10373c1e38eaSMarcel Moolenaar 		pt_ucontext_to_reg(&tmbx.tm_context, &regs);
10383c1e38eaSMarcel Moolenaar 		/* only write out if it is really changed. */
10393c1e38eaSMarcel Moolenaar 		if (pt_reg_sstep(&regs, step) != 0) {
10403c1e38eaSMarcel Moolenaar 			pt_reg_to_ucontext(&regs, &tmbx.tm_context);
10413c1e38eaSMarcel Moolenaar 			ret = ps_pwrite(ta->ph, tmbx_addr, &tmbx,
10423c1e38eaSMarcel Moolenaar 			                 sizeof(tmbx));
10433c1e38eaSMarcel Moolenaar 		}
10443c1e38eaSMarcel Moolenaar 	}
10453c1e38eaSMarcel Moolenaar 	return (P2T(ret));
10463c1e38eaSMarcel Moolenaar }
10473c1e38eaSMarcel Moolenaar 
10483c1e38eaSMarcel Moolenaar static void
pt_unmap_lwp(const td_thragent_t * ta,lwpid_t lwp)10493c1e38eaSMarcel Moolenaar pt_unmap_lwp(const td_thragent_t *ta, lwpid_t lwp)
10503c1e38eaSMarcel Moolenaar {
10511f2b051dSPedro F. Giffuni 	unsigned int i;
10523c1e38eaSMarcel Moolenaar 
10533c1e38eaSMarcel Moolenaar 	for (i = 0; i < ta->map_len; ++i) {
10543c1e38eaSMarcel Moolenaar 		if (ta->map[i].type == PT_LWP && ta->map[i].lwp == lwp) {
10553c1e38eaSMarcel Moolenaar 			ta->map[i].type = PT_NONE;
10563c1e38eaSMarcel Moolenaar 			return;
10573c1e38eaSMarcel Moolenaar 		}
10583c1e38eaSMarcel Moolenaar 	}
10593c1e38eaSMarcel Moolenaar }
10603c1e38eaSMarcel Moolenaar 
10613c1e38eaSMarcel Moolenaar static int
pt_validate(const td_thrhandle_t * th)10623c1e38eaSMarcel Moolenaar pt_validate(const td_thrhandle_t *th)
10633c1e38eaSMarcel Moolenaar {
10643c1e38eaSMarcel Moolenaar 
10658413ef57SPedro F. Giffuni 	if (th->th_tid < 0 || th->th_tid >= (long)th->th_ta->map_len ||
10663c1e38eaSMarcel Moolenaar 	    th->th_ta->map[th->th_tid].type == PT_NONE)
10673c1e38eaSMarcel Moolenaar 		return (TD_NOTHR);
10683c1e38eaSMarcel Moolenaar 	return (TD_OK);
10693c1e38eaSMarcel Moolenaar }
10703c1e38eaSMarcel Moolenaar 
1071820c1c55SMarcel Moolenaar static td_err_e
pt_thr_tls_get_addr(const td_thrhandle_t * th,psaddr_t _linkmap,size_t offset,psaddr_t * address)107216b0c20cSMarcel Moolenaar pt_thr_tls_get_addr(const td_thrhandle_t *th, psaddr_t _linkmap, size_t offset,
107316b0c20cSMarcel Moolenaar     psaddr_t *address)
10743e93cc3aSDavid Xu {
10753e93cc3aSDavid Xu 	const td_thragent_t *ta = th->th_ta;
107616b0c20cSMarcel Moolenaar 	psaddr_t dtv_addr, obj_entry, tcb_addr;
10773e93cc3aSDavid Xu 	int tls_index, ret;
10783e93cc3aSDavid Xu 
10793e93cc3aSDavid Xu 	/* linkmap is a member of Obj_Entry */
108016b0c20cSMarcel Moolenaar 	obj_entry = _linkmap - ta->thread_off_linkmap;
10813e93cc3aSDavid Xu 
10823e93cc3aSDavid Xu 	/* get tlsindex of the object file */
10833e93cc3aSDavid Xu 	ret = ps_pread(ta->ph,
1084cd980d46SDavid Xu 		obj_entry + ta->thread_off_tlsindex,
10853e93cc3aSDavid Xu 		&tls_index, sizeof(tls_index));
10863e93cc3aSDavid Xu 	if (ret != 0)
10873e93cc3aSDavid Xu 		return (P2T(ret));
10883e93cc3aSDavid Xu 
10893e93cc3aSDavid Xu 	/* get thread tcb */
10903e93cc3aSDavid Xu 	ret = ps_pread(ta->ph, ta->map[th->th_tid].thr +
1091cd980d46SDavid Xu 		ta->thread_off_tcb,
10923e93cc3aSDavid Xu 		&tcb_addr, sizeof(tcb_addr));
10933e93cc3aSDavid Xu 	if (ret != 0)
10943e93cc3aSDavid Xu 		return (P2T(ret));
10953e93cc3aSDavid Xu 
10963e93cc3aSDavid Xu 	/* get dtv array address */
1097cd980d46SDavid Xu 	ret = ps_pread(ta->ph, tcb_addr + ta->thread_off_dtv,
10983e93cc3aSDavid Xu 		&dtv_addr, sizeof(dtv_addr));
10993e93cc3aSDavid Xu 	if (ret != 0)
11003e93cc3aSDavid Xu 		return (P2T(ret));
11013e93cc3aSDavid Xu 	/* now get the object's tls block base address */
110216b0c20cSMarcel Moolenaar 	ret = ps_pread(ta->ph, dtv_addr + sizeof(void *) * (tls_index + 1),
110316b0c20cSMarcel Moolenaar 	    address, sizeof(*address));
11043e93cc3aSDavid Xu 	if (ret != 0)
11053e93cc3aSDavid Xu 		return (P2T(ret));
11063e93cc3aSDavid Xu 
11073e93cc3aSDavid Xu 	*address += offset;
11083e93cc3aSDavid Xu 	return (TD_OK);
11093e93cc3aSDavid Xu }
11103e93cc3aSDavid Xu 
1111ae824d80SEd Schouten static struct ta_ops libpthread_db_ops = {
11123c1e38eaSMarcel Moolenaar 	.to_init		= pt_init,
11133c1e38eaSMarcel Moolenaar 	.to_ta_clear_event	= pt_ta_clear_event,
11143c1e38eaSMarcel Moolenaar 	.to_ta_delete		= pt_ta_delete,
11153c1e38eaSMarcel Moolenaar 	.to_ta_event_addr	= pt_ta_event_addr,
11163c1e38eaSMarcel Moolenaar 	.to_ta_event_getmsg	= pt_ta_event_getmsg,
11173c1e38eaSMarcel Moolenaar 	.to_ta_map_id2thr	= pt_ta_map_id2thr,
11183c1e38eaSMarcel Moolenaar 	.to_ta_map_lwp2thr	= pt_ta_map_lwp2thr,
11193c1e38eaSMarcel Moolenaar 	.to_ta_new		= pt_ta_new,
11203c1e38eaSMarcel Moolenaar 	.to_ta_set_event	= pt_ta_set_event,
11213c1e38eaSMarcel Moolenaar 	.to_ta_thr_iter		= pt_ta_thr_iter,
11223c1e38eaSMarcel Moolenaar 	.to_ta_tsd_iter		= pt_ta_tsd_iter,
11233c1e38eaSMarcel Moolenaar 	.to_thr_clear_event	= pt_thr_clear_event,
11243c1e38eaSMarcel Moolenaar 	.to_thr_dbresume	= pt_thr_dbresume,
11253c1e38eaSMarcel Moolenaar 	.to_thr_dbsuspend	= pt_thr_dbsuspend,
11263c1e38eaSMarcel Moolenaar 	.to_thr_event_enable	= pt_thr_event_enable,
11273c1e38eaSMarcel Moolenaar 	.to_thr_event_getmsg	= pt_thr_event_getmsg,
1128098d0537SKonstantin Belousov 	.to_thr_old_get_info	= pt_thr_old_get_info,
11293c1e38eaSMarcel Moolenaar 	.to_thr_get_info	= pt_thr_get_info,
11303c1e38eaSMarcel Moolenaar 	.to_thr_getfpregs	= pt_thr_getfpregs,
11313c1e38eaSMarcel Moolenaar 	.to_thr_getgregs	= pt_thr_getgregs,
11323c1e38eaSMarcel Moolenaar 	.to_thr_set_event	= pt_thr_set_event,
11333c1e38eaSMarcel Moolenaar 	.to_thr_setfpregs	= pt_thr_setfpregs,
11343c1e38eaSMarcel Moolenaar 	.to_thr_setgregs	= pt_thr_setgregs,
11353c1e38eaSMarcel Moolenaar 	.to_thr_validate	= pt_thr_validate,
11363e93cc3aSDavid Xu 	.to_thr_tls_get_addr	= pt_thr_tls_get_addr,
11373c1e38eaSMarcel Moolenaar 
11383c1e38eaSMarcel Moolenaar 	/* FreeBSD specific extensions. */
11393c1e38eaSMarcel Moolenaar 	.to_thr_sstep		= pt_thr_sstep,
11408d7681bbSDoug Rabson #ifdef __i386__
11418d7681bbSDoug Rabson 	.to_thr_getxmmregs	= pt_thr_getxmmregs,
11428d7681bbSDoug Rabson 	.to_thr_setxmmregs	= pt_thr_setxmmregs,
11438d7681bbSDoug Rabson #endif
11443c1e38eaSMarcel Moolenaar };
114520b94d80SDavid Xu 
114620b94d80SDavid Xu DATA_SET(__ta_ops, libpthread_db_ops);
1147