1*3c1e38eaSMarcel Moolenaar /*
2*3c1e38eaSMarcel Moolenaar  * Copyright (c) 2004 David Xu <[email protected]>
3*3c1e38eaSMarcel Moolenaar  * All rights reserved.
4*3c1e38eaSMarcel Moolenaar  *
5*3c1e38eaSMarcel Moolenaar  * Redistribution and use in source and binary forms, with or without
6*3c1e38eaSMarcel Moolenaar  * modification, are permitted provided that the following conditions
7*3c1e38eaSMarcel Moolenaar  * are met:
8*3c1e38eaSMarcel Moolenaar  * 1. Redistributions of source code must retain the above copyright
9*3c1e38eaSMarcel Moolenaar  *    notice, this list of conditions and the following disclaimer.
10*3c1e38eaSMarcel Moolenaar  * 2. Redistributions in binary form must reproduce the above copyright
11*3c1e38eaSMarcel Moolenaar  *    notice, this list of conditions and the following disclaimer in the
12*3c1e38eaSMarcel Moolenaar  *    documentation and/or other materials provided with the distribution.
13*3c1e38eaSMarcel Moolenaar  *
14*3c1e38eaSMarcel Moolenaar  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15*3c1e38eaSMarcel Moolenaar  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16*3c1e38eaSMarcel Moolenaar  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17*3c1e38eaSMarcel Moolenaar  * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18*3c1e38eaSMarcel Moolenaar  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19*3c1e38eaSMarcel Moolenaar  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20*3c1e38eaSMarcel Moolenaar  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21*3c1e38eaSMarcel Moolenaar  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22*3c1e38eaSMarcel Moolenaar  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23*3c1e38eaSMarcel Moolenaar  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24*3c1e38eaSMarcel Moolenaar  * SUCH DAMAGE.
25*3c1e38eaSMarcel Moolenaar  */
26*3c1e38eaSMarcel Moolenaar 
27*3c1e38eaSMarcel Moolenaar #include <sys/cdefs.h>
28*3c1e38eaSMarcel Moolenaar __FBSDID("$FreeBSD$");
29*3c1e38eaSMarcel Moolenaar 
30*3c1e38eaSMarcel Moolenaar #include <stddef.h>
31*3c1e38eaSMarcel Moolenaar #include <stdlib.h>
32*3c1e38eaSMarcel Moolenaar #include <string.h>
33*3c1e38eaSMarcel Moolenaar #include <unistd.h>
34*3c1e38eaSMarcel Moolenaar #include <pthread.h>
35*3c1e38eaSMarcel Moolenaar #include <sys/types.h>
36*3c1e38eaSMarcel Moolenaar #include <sys/kse.h>
37*3c1e38eaSMarcel Moolenaar #include <sys/ptrace.h>
38*3c1e38eaSMarcel Moolenaar #include <proc_service.h>
39*3c1e38eaSMarcel Moolenaar #include <thread_db.h>
40*3c1e38eaSMarcel Moolenaar 
41*3c1e38eaSMarcel Moolenaar #include "libpthread.h"
42*3c1e38eaSMarcel Moolenaar #include "libpthread_db.h"
43*3c1e38eaSMarcel Moolenaar 
44*3c1e38eaSMarcel Moolenaar #define P2T(c) ps2td(c)
45*3c1e38eaSMarcel Moolenaar 
46*3c1e38eaSMarcel Moolenaar static void pt_unmap_lwp(const td_thragent_t *ta, lwpid_t lwp);
47*3c1e38eaSMarcel Moolenaar static int pt_validate(const td_thrhandle_t *th);
48*3c1e38eaSMarcel Moolenaar 
49*3c1e38eaSMarcel Moolenaar static int
50*3c1e38eaSMarcel Moolenaar ps2td(int c)
51*3c1e38eaSMarcel Moolenaar {
52*3c1e38eaSMarcel Moolenaar 	switch (c) {
53*3c1e38eaSMarcel Moolenaar 	case PS_OK:
54*3c1e38eaSMarcel Moolenaar 		return TD_OK;
55*3c1e38eaSMarcel Moolenaar 	case PS_ERR:
56*3c1e38eaSMarcel Moolenaar 		return TD_ERR;
57*3c1e38eaSMarcel Moolenaar 	case PS_BADPID:
58*3c1e38eaSMarcel Moolenaar 		return TD_BADPH;
59*3c1e38eaSMarcel Moolenaar 	case PS_BADLID:
60*3c1e38eaSMarcel Moolenaar 		return TD_NOLWP;
61*3c1e38eaSMarcel Moolenaar 	case PS_BADADDR:
62*3c1e38eaSMarcel Moolenaar 		return TD_ERR;
63*3c1e38eaSMarcel Moolenaar 	case PS_NOSYM:
64*3c1e38eaSMarcel Moolenaar 		return TD_NOLIBTHREAD;
65*3c1e38eaSMarcel Moolenaar 	case PS_NOFREGS:
66*3c1e38eaSMarcel Moolenaar 		return TD_NOFPREGS;
67*3c1e38eaSMarcel Moolenaar 	default:
68*3c1e38eaSMarcel Moolenaar 		return TD_ERR;
69*3c1e38eaSMarcel Moolenaar 	}
70*3c1e38eaSMarcel Moolenaar }
71*3c1e38eaSMarcel Moolenaar 
72*3c1e38eaSMarcel Moolenaar static long
73*3c1e38eaSMarcel Moolenaar pt_map_thread(const td_thragent_t *const_ta, psaddr_t pt, int type)
74*3c1e38eaSMarcel Moolenaar {
75*3c1e38eaSMarcel Moolenaar 	td_thragent_t *ta = __DECONST(td_thragent_t *, const_ta);
76*3c1e38eaSMarcel Moolenaar 	struct pt_map *new;
77*3c1e38eaSMarcel Moolenaar 	int i, first = -1;
78*3c1e38eaSMarcel Moolenaar 
79*3c1e38eaSMarcel Moolenaar 	/* leave zero out */
80*3c1e38eaSMarcel Moolenaar 	for (i = 1; i < ta->map_len; ++i) {
81*3c1e38eaSMarcel Moolenaar 		if (ta->map[i].type == PT_NONE) {
82*3c1e38eaSMarcel Moolenaar 			if (first == -1)
83*3c1e38eaSMarcel Moolenaar 				first = i;
84*3c1e38eaSMarcel Moolenaar 		} else if (ta->map[i].type == type && ta->map[i].thr == pt) {
85*3c1e38eaSMarcel Moolenaar 				return (i);
86*3c1e38eaSMarcel Moolenaar 		}
87*3c1e38eaSMarcel Moolenaar 	}
88*3c1e38eaSMarcel Moolenaar 
89*3c1e38eaSMarcel Moolenaar 	if (first == -1) {
90*3c1e38eaSMarcel Moolenaar 		if (ta->map_len == 0) {
91*3c1e38eaSMarcel Moolenaar 			ta->map = calloc(20, sizeof(struct pt_map));
92*3c1e38eaSMarcel Moolenaar 			if (ta->map == NULL)
93*3c1e38eaSMarcel Moolenaar 				return (-1);
94*3c1e38eaSMarcel Moolenaar 			ta->map_len = 20;
95*3c1e38eaSMarcel Moolenaar 			first = 1;
96*3c1e38eaSMarcel Moolenaar 		} else {
97*3c1e38eaSMarcel Moolenaar 			new = realloc(ta->map,
98*3c1e38eaSMarcel Moolenaar 			              sizeof(struct pt_map) * ta->map_len * 2);
99*3c1e38eaSMarcel Moolenaar 			if (new == NULL)
100*3c1e38eaSMarcel Moolenaar 				return (-1);
101*3c1e38eaSMarcel Moolenaar 			memset(new + ta->map_len, '\0', sizeof(struct pt_map) *
102*3c1e38eaSMarcel Moolenaar 			       ta->map_len);
103*3c1e38eaSMarcel Moolenaar 			first = ta->map_len;
104*3c1e38eaSMarcel Moolenaar 			ta->map = new;
105*3c1e38eaSMarcel Moolenaar 			ta->map_len *= 2;
106*3c1e38eaSMarcel Moolenaar 		}
107*3c1e38eaSMarcel Moolenaar 	}
108*3c1e38eaSMarcel Moolenaar 
109*3c1e38eaSMarcel Moolenaar 	ta->map[first].type = type;
110*3c1e38eaSMarcel Moolenaar 	ta->map[first].thr = pt;
111*3c1e38eaSMarcel Moolenaar 	return (first);
112*3c1e38eaSMarcel Moolenaar }
113*3c1e38eaSMarcel Moolenaar 
114*3c1e38eaSMarcel Moolenaar static td_err_e
115*3c1e38eaSMarcel Moolenaar pt_init(void)
116*3c1e38eaSMarcel Moolenaar {
117*3c1e38eaSMarcel Moolenaar 	pt_md_init();
118*3c1e38eaSMarcel Moolenaar 	return (0);
119*3c1e38eaSMarcel Moolenaar }
120*3c1e38eaSMarcel Moolenaar 
121*3c1e38eaSMarcel Moolenaar static td_err_e
122*3c1e38eaSMarcel Moolenaar pt_ta_new(struct ps_prochandle *ph, td_thragent_t **pta)
123*3c1e38eaSMarcel Moolenaar {
124*3c1e38eaSMarcel Moolenaar #define LOOKUP_SYM(proc, sym, addr) 			\
125*3c1e38eaSMarcel Moolenaar 	ret = ps_pglobal_lookup(proc, NULL, sym, addr);	\
126*3c1e38eaSMarcel Moolenaar 	if (ret != 0) {					\
127*3c1e38eaSMarcel Moolenaar 		TDBG("can not find symbol: %s\n", sym);	\
128*3c1e38eaSMarcel Moolenaar 		ret = TD_NOLIBTHREAD;			\
129*3c1e38eaSMarcel Moolenaar 		goto error;				\
130*3c1e38eaSMarcel Moolenaar 	}
131*3c1e38eaSMarcel Moolenaar 
132*3c1e38eaSMarcel Moolenaar 	td_thragent_t *ta;
133*3c1e38eaSMarcel Moolenaar 	int dbg;
134*3c1e38eaSMarcel Moolenaar 	int ret;
135*3c1e38eaSMarcel Moolenaar 
136*3c1e38eaSMarcel Moolenaar 	TDBG_FUNC();
137*3c1e38eaSMarcel Moolenaar 
138*3c1e38eaSMarcel Moolenaar 	ta = malloc(sizeof(td_thragent_t));
139*3c1e38eaSMarcel Moolenaar 	if (ta == NULL)
140*3c1e38eaSMarcel Moolenaar 		return (TD_MALLOC);
141*3c1e38eaSMarcel Moolenaar 
142*3c1e38eaSMarcel Moolenaar 	ta->ph = ph;
143*3c1e38eaSMarcel Moolenaar 	ta->thread_activated = 0;
144*3c1e38eaSMarcel Moolenaar 	ta->map = NULL;
145*3c1e38eaSMarcel Moolenaar 	ta->map_len = 0;
146*3c1e38eaSMarcel Moolenaar 
147*3c1e38eaSMarcel Moolenaar 	LOOKUP_SYM(ph, "_libkse_debug",		&ta->libkse_debug_addr);
148*3c1e38eaSMarcel Moolenaar 	LOOKUP_SYM(ph, "_thread_list",		&ta->thread_list_addr);
149*3c1e38eaSMarcel Moolenaar 	LOOKUP_SYM(ph, "_thread_activated",	&ta->thread_activated_addr);
150*3c1e38eaSMarcel Moolenaar 	LOOKUP_SYM(ph, "_thread_active_threads",&ta->thread_active_threads_addr);
151*3c1e38eaSMarcel Moolenaar 	LOOKUP_SYM(ph, "_thread_keytable",	&ta->thread_keytable_addr);
152*3c1e38eaSMarcel Moolenaar 
153*3c1e38eaSMarcel Moolenaar 	dbg = getpid();
154*3c1e38eaSMarcel Moolenaar 	/*
155*3c1e38eaSMarcel Moolenaar 	 * If this fails it probably means we're debugging a core file and
156*3c1e38eaSMarcel Moolenaar 	 * can't write to it.
157*3c1e38eaSMarcel Moolenaar 	 */
158*3c1e38eaSMarcel Moolenaar 	ps_pwrite(ph, ta->libkse_debug_addr, &dbg, sizeof(int));
159*3c1e38eaSMarcel Moolenaar 	*pta = ta;
160*3c1e38eaSMarcel Moolenaar 	return (0);
161*3c1e38eaSMarcel Moolenaar 
162*3c1e38eaSMarcel Moolenaar error:
163*3c1e38eaSMarcel Moolenaar 	free(ta);
164*3c1e38eaSMarcel Moolenaar 	return (ret);
165*3c1e38eaSMarcel Moolenaar }
166*3c1e38eaSMarcel Moolenaar 
167*3c1e38eaSMarcel Moolenaar static td_err_e
168*3c1e38eaSMarcel Moolenaar pt_ta_delete(td_thragent_t *ta)
169*3c1e38eaSMarcel Moolenaar {
170*3c1e38eaSMarcel Moolenaar 	int dbg;
171*3c1e38eaSMarcel Moolenaar 
172*3c1e38eaSMarcel Moolenaar 	TDBG_FUNC();
173*3c1e38eaSMarcel Moolenaar 
174*3c1e38eaSMarcel Moolenaar 	dbg = 0;
175*3c1e38eaSMarcel Moolenaar 	/*
176*3c1e38eaSMarcel Moolenaar 	 * Error returns from this write are not really a problem;
177*3c1e38eaSMarcel Moolenaar 	 * the process doesn't exist any more.
178*3c1e38eaSMarcel Moolenaar 	 */
179*3c1e38eaSMarcel Moolenaar 	ps_pwrite(ta->ph, ta->libkse_debug_addr, &dbg, sizeof(int));
180*3c1e38eaSMarcel Moolenaar 	if (ta->map)
181*3c1e38eaSMarcel Moolenaar 		free(ta->map);
182*3c1e38eaSMarcel Moolenaar 	free(ta);
183*3c1e38eaSMarcel Moolenaar 	return (TD_OK);
184*3c1e38eaSMarcel Moolenaar }
185*3c1e38eaSMarcel Moolenaar 
186*3c1e38eaSMarcel Moolenaar static td_err_e
187*3c1e38eaSMarcel Moolenaar pt_ta_map_id2thr(const td_thragent_t *ta, thread_t id, td_thrhandle_t *th)
188*3c1e38eaSMarcel Moolenaar {
189*3c1e38eaSMarcel Moolenaar 	prgregset_t gregs;
190*3c1e38eaSMarcel Moolenaar 	TAILQ_HEAD(, pthread) thread_list;
191*3c1e38eaSMarcel Moolenaar 	psaddr_t pt, tcb_addr;
192*3c1e38eaSMarcel Moolenaar 	lwpid_t lwp;
193*3c1e38eaSMarcel Moolenaar 	int ret;
194*3c1e38eaSMarcel Moolenaar 
195*3c1e38eaSMarcel Moolenaar 	TDBG_FUNC();
196*3c1e38eaSMarcel Moolenaar 
197*3c1e38eaSMarcel Moolenaar 	if (id < 0 || id >= ta->map_len || ta->map[id].type == PT_NONE)
198*3c1e38eaSMarcel Moolenaar 		return (TD_NOTHR);
199*3c1e38eaSMarcel Moolenaar 	ret = ps_pread(ta->ph, ta->thread_list_addr, &thread_list,
200*3c1e38eaSMarcel Moolenaar 			sizeof(thread_list));
201*3c1e38eaSMarcel Moolenaar 	if (ret != 0)
202*3c1e38eaSMarcel Moolenaar 		return (P2T(ret));
203*3c1e38eaSMarcel Moolenaar 	pt = (psaddr_t)thread_list.tqh_first;
204*3c1e38eaSMarcel Moolenaar 	if (ta->map[id].type == PT_LWP) {
205*3c1e38eaSMarcel Moolenaar 		/*
206*3c1e38eaSMarcel Moolenaar 		 * if we are referencing a lwp, make sure it was not already
207*3c1e38eaSMarcel Moolenaar 		 * mapped to user thread.
208*3c1e38eaSMarcel Moolenaar 		 */
209*3c1e38eaSMarcel Moolenaar 		while (pt != 0) {
210*3c1e38eaSMarcel Moolenaar 			ret = ps_pread(ta->ph,
211*3c1e38eaSMarcel Moolenaar 			        pt + offsetof(struct pthread, tcb),
212*3c1e38eaSMarcel Moolenaar 			        &tcb_addr, sizeof(tcb_addr));
213*3c1e38eaSMarcel Moolenaar 			if (ret != 0)
214*3c1e38eaSMarcel Moolenaar 				return (P2T(ret));
215*3c1e38eaSMarcel Moolenaar 			ret = ps_pread(ta->ph,
216*3c1e38eaSMarcel Moolenaar 			        tcb_addr + offsetof(struct tcb,
217*3c1e38eaSMarcel Moolenaar 				  tcb_tmbx.tm_lwp),
218*3c1e38eaSMarcel Moolenaar 				&lwp, sizeof(lwp));
219*3c1e38eaSMarcel Moolenaar 			if (ret != 0)
220*3c1e38eaSMarcel Moolenaar 				return (P2T(ret));
221*3c1e38eaSMarcel Moolenaar 			/*
222*3c1e38eaSMarcel Moolenaar 			 * If the lwp was already mapped to userland thread,
223*3c1e38eaSMarcel Moolenaar 			 * we shouldn't reference it directly in future.
224*3c1e38eaSMarcel Moolenaar 			 */
225*3c1e38eaSMarcel Moolenaar 			if (lwp == ta->map[id].lwp) {
226*3c1e38eaSMarcel Moolenaar 				ta->map[id].type = PT_NONE;
227*3c1e38eaSMarcel Moolenaar 				return (TD_NOTHR);
228*3c1e38eaSMarcel Moolenaar 			}
229*3c1e38eaSMarcel Moolenaar 			/* get next thread */
230*3c1e38eaSMarcel Moolenaar 			ret = ps_pread(ta->ph,
231*3c1e38eaSMarcel Moolenaar 			        pt + offsetof(struct pthread, tle.tqe_next),
232*3c1e38eaSMarcel Moolenaar 			        &pt, sizeof(pt));
233*3c1e38eaSMarcel Moolenaar 			if (ret != 0)
234*3c1e38eaSMarcel Moolenaar 				return (P2T(ret));
235*3c1e38eaSMarcel Moolenaar 		}
236*3c1e38eaSMarcel Moolenaar 		/* check lwp */
237*3c1e38eaSMarcel Moolenaar 		ret = ptrace(PT_GETREGS, ta->map[id].lwp, (caddr_t)&gregs, 0);
238*3c1e38eaSMarcel Moolenaar 		if (ret != 0) {
239*3c1e38eaSMarcel Moolenaar 			/* no longer exists */
240*3c1e38eaSMarcel Moolenaar 			ta->map[id].type = PT_NONE;
241*3c1e38eaSMarcel Moolenaar 			return (TD_NOTHR);
242*3c1e38eaSMarcel Moolenaar 		}
243*3c1e38eaSMarcel Moolenaar 	} else {
244*3c1e38eaSMarcel Moolenaar 		while (pt != 0 && ta->map[id].thr != pt) {
245*3c1e38eaSMarcel Moolenaar 			ret = ps_pread(ta->ph,
246*3c1e38eaSMarcel Moolenaar 				pt + offsetof(struct pthread, tcb),
247*3c1e38eaSMarcel Moolenaar 				&tcb_addr, sizeof(tcb_addr));
248*3c1e38eaSMarcel Moolenaar 			if (ret != 0)
249*3c1e38eaSMarcel Moolenaar 				return (P2T(ret));
250*3c1e38eaSMarcel Moolenaar 			/* get next thread */
251*3c1e38eaSMarcel Moolenaar 			ret = ps_pread(ta->ph,
252*3c1e38eaSMarcel Moolenaar 				pt + offsetof(struct pthread, tle.tqe_next),
253*3c1e38eaSMarcel Moolenaar 				&pt, sizeof(pt));
254*3c1e38eaSMarcel Moolenaar 			if (ret != 0)
255*3c1e38eaSMarcel Moolenaar 				return (P2T(ret));
256*3c1e38eaSMarcel Moolenaar 		}
257*3c1e38eaSMarcel Moolenaar 
258*3c1e38eaSMarcel Moolenaar 		if (pt == 0) {
259*3c1e38eaSMarcel Moolenaar 			/* no longer exists */
260*3c1e38eaSMarcel Moolenaar 			ta->map[id].type = PT_NONE;
261*3c1e38eaSMarcel Moolenaar 			return (TD_NOTHR);
262*3c1e38eaSMarcel Moolenaar 		}
263*3c1e38eaSMarcel Moolenaar 	}
264*3c1e38eaSMarcel Moolenaar 	th->th_ta = ta;
265*3c1e38eaSMarcel Moolenaar 	th->th_tid = id;
266*3c1e38eaSMarcel Moolenaar 	return (TD_OK);
267*3c1e38eaSMarcel Moolenaar }
268*3c1e38eaSMarcel Moolenaar 
269*3c1e38eaSMarcel Moolenaar static td_err_e
270*3c1e38eaSMarcel Moolenaar pt_ta_map_lwp2thr(const td_thragent_t *ta, lwpid_t lwp, td_thrhandle_t *th)
271*3c1e38eaSMarcel Moolenaar {
272*3c1e38eaSMarcel Moolenaar 	TAILQ_HEAD(, pthread) thread_list;
273*3c1e38eaSMarcel Moolenaar 	psaddr_t pt, ptr;
274*3c1e38eaSMarcel Moolenaar 	lwpid_t tmp_lwp;
275*3c1e38eaSMarcel Moolenaar 	int ret;
276*3c1e38eaSMarcel Moolenaar 
277*3c1e38eaSMarcel Moolenaar 	TDBG_FUNC();
278*3c1e38eaSMarcel Moolenaar 
279*3c1e38eaSMarcel Moolenaar 	ret = ps_pread(ta->ph, ta->thread_list_addr, &thread_list,
280*3c1e38eaSMarcel Moolenaar 	                sizeof(thread_list));
281*3c1e38eaSMarcel Moolenaar 	if (ret != 0)
282*3c1e38eaSMarcel Moolenaar 		return (P2T(ret));
283*3c1e38eaSMarcel Moolenaar 	pt = (psaddr_t)thread_list.tqh_first;
284*3c1e38eaSMarcel Moolenaar 	while (pt != 0) {
285*3c1e38eaSMarcel Moolenaar 		ret = ps_pread(ta->ph, pt + offsetof(struct pthread, tcb),
286*3c1e38eaSMarcel Moolenaar 				&ptr, sizeof(ptr));
287*3c1e38eaSMarcel Moolenaar 		if (ret != 0)
288*3c1e38eaSMarcel Moolenaar 			return (P2T(ret));
289*3c1e38eaSMarcel Moolenaar 		ptr += offsetof(struct tcb, tcb_tmbx.tm_lwp);
290*3c1e38eaSMarcel Moolenaar 		ret = ps_pread(ta->ph, ptr, &tmp_lwp, sizeof(lwpid_t));
291*3c1e38eaSMarcel Moolenaar 		if (ret != 0)
292*3c1e38eaSMarcel Moolenaar 			return (P2T(ret));
293*3c1e38eaSMarcel Moolenaar 		if (tmp_lwp == lwp) {
294*3c1e38eaSMarcel Moolenaar 			th->th_ta = ta;
295*3c1e38eaSMarcel Moolenaar 			th->th_tid = pt_map_thread(ta, pt, PT_USER);
296*3c1e38eaSMarcel Moolenaar 			if (th->th_tid == -1)
297*3c1e38eaSMarcel Moolenaar 				return (TD_MALLOC);
298*3c1e38eaSMarcel Moolenaar 			pt_unmap_lwp(ta, lwp);
299*3c1e38eaSMarcel Moolenaar 			return (TD_OK);
300*3c1e38eaSMarcel Moolenaar 		}
301*3c1e38eaSMarcel Moolenaar 
302*3c1e38eaSMarcel Moolenaar 		/* get next thread */
303*3c1e38eaSMarcel Moolenaar 		ret = ps_pread(ta->ph,
304*3c1e38eaSMarcel Moolenaar 		           pt + offsetof(struct pthread, tle.tqe_next),
305*3c1e38eaSMarcel Moolenaar 		           &pt, sizeof(pt));
306*3c1e38eaSMarcel Moolenaar 		if (ret != 0)
307*3c1e38eaSMarcel Moolenaar 			return (P2T(ret));
308*3c1e38eaSMarcel Moolenaar 	}
309*3c1e38eaSMarcel Moolenaar 
310*3c1e38eaSMarcel Moolenaar 	return (TD_NOTHR);
311*3c1e38eaSMarcel Moolenaar }
312*3c1e38eaSMarcel Moolenaar 
313*3c1e38eaSMarcel Moolenaar static td_err_e
314*3c1e38eaSMarcel Moolenaar pt_ta_thr_iter(const td_thragent_t *ta,
315*3c1e38eaSMarcel Moolenaar                td_thr_iter_f *callback, void *cbdata_p,
316*3c1e38eaSMarcel Moolenaar                td_thr_state_e state, int ti_pri,
317*3c1e38eaSMarcel Moolenaar                sigset_t *ti_sigmask_p,
318*3c1e38eaSMarcel Moolenaar                unsigned int ti_user_flags)
319*3c1e38eaSMarcel Moolenaar {
320*3c1e38eaSMarcel Moolenaar 	TAILQ_HEAD(, pthread) thread_list;
321*3c1e38eaSMarcel Moolenaar 	td_thrhandle_t th;
322*3c1e38eaSMarcel Moolenaar 	psaddr_t pt;
323*3c1e38eaSMarcel Moolenaar 	ps_err_e pserr;
324*3c1e38eaSMarcel Moolenaar 	int activated;
325*3c1e38eaSMarcel Moolenaar 
326*3c1e38eaSMarcel Moolenaar 	TDBG_FUNC();
327*3c1e38eaSMarcel Moolenaar 
328*3c1e38eaSMarcel Moolenaar 	pserr = ps_pread(ta->ph, ta->thread_activated_addr, &activated,
329*3c1e38eaSMarcel Moolenaar 	    sizeof(int));
330*3c1e38eaSMarcel Moolenaar 	if (pserr != PS_OK)
331*3c1e38eaSMarcel Moolenaar 		return (P2T(pserr));
332*3c1e38eaSMarcel Moolenaar 	if (!activated)
333*3c1e38eaSMarcel Moolenaar 		return (TD_OK);
334*3c1e38eaSMarcel Moolenaar 
335*3c1e38eaSMarcel Moolenaar 	pserr = ps_pread(ta->ph, ta->thread_list_addr, &thread_list,
336*3c1e38eaSMarcel Moolenaar 	    sizeof(thread_list));
337*3c1e38eaSMarcel Moolenaar 	if (pserr != 0)
338*3c1e38eaSMarcel Moolenaar 		return (P2T(pserr));
339*3c1e38eaSMarcel Moolenaar 	pt = (psaddr_t)thread_list.tqh_first;
340*3c1e38eaSMarcel Moolenaar 	while (pt != 0) {
341*3c1e38eaSMarcel Moolenaar 		th.th_ta = ta;
342*3c1e38eaSMarcel Moolenaar 		th.th_tid = pt_map_thread(ta, pt, PT_USER);
343*3c1e38eaSMarcel Moolenaar 		/* should we unmap lwp here ? */
344*3c1e38eaSMarcel Moolenaar 		if (th.th_tid == -1)
345*3c1e38eaSMarcel Moolenaar 			return (TD_MALLOC);
346*3c1e38eaSMarcel Moolenaar 		if ((*callback)(&th, cbdata_p))
347*3c1e38eaSMarcel Moolenaar 			return (TD_DBERR);
348*3c1e38eaSMarcel Moolenaar 		/* get next thread */
349*3c1e38eaSMarcel Moolenaar 		pserr = ps_pread(ta->ph,
350*3c1e38eaSMarcel Moolenaar 		    pt + offsetof(struct pthread, tle.tqe_next), &pt,
351*3c1e38eaSMarcel Moolenaar 		    sizeof(pt));
352*3c1e38eaSMarcel Moolenaar 		if (pserr != PS_OK)
353*3c1e38eaSMarcel Moolenaar 			return (P2T(pserr));
354*3c1e38eaSMarcel Moolenaar 	}
355*3c1e38eaSMarcel Moolenaar 	return (TD_OK);
356*3c1e38eaSMarcel Moolenaar }
357*3c1e38eaSMarcel Moolenaar 
358*3c1e38eaSMarcel Moolenaar static td_err_e
359*3c1e38eaSMarcel Moolenaar pt_ta_tsd_iter(const td_thragent_t *ta, td_key_iter_f *ki, void *arg)
360*3c1e38eaSMarcel Moolenaar {
361*3c1e38eaSMarcel Moolenaar 	struct pthread_key keytable[PTHREAD_KEYS_MAX];
362*3c1e38eaSMarcel Moolenaar 	int i, ret;
363*3c1e38eaSMarcel Moolenaar 
364*3c1e38eaSMarcel Moolenaar 	TDBG_FUNC();
365*3c1e38eaSMarcel Moolenaar 
366*3c1e38eaSMarcel Moolenaar 	ret = ps_pread(ta->ph, (psaddr_t)ta->thread_keytable_addr, keytable,
367*3c1e38eaSMarcel Moolenaar 	                sizeof(keytable));
368*3c1e38eaSMarcel Moolenaar 	if (ret != 0)
369*3c1e38eaSMarcel Moolenaar 		return (P2T(ret));
370*3c1e38eaSMarcel Moolenaar 
371*3c1e38eaSMarcel Moolenaar 	for (i = 0; i < PTHREAD_KEYS_MAX; i++) {
372*3c1e38eaSMarcel Moolenaar 		if (keytable[i].allocated) {
373*3c1e38eaSMarcel Moolenaar 			ret = (ki)(i, keytable[i].destructor, arg);
374*3c1e38eaSMarcel Moolenaar 			if (ret != 0)
375*3c1e38eaSMarcel Moolenaar 				return (TD_DBERR);
376*3c1e38eaSMarcel Moolenaar 		}
377*3c1e38eaSMarcel Moolenaar 	}
378*3c1e38eaSMarcel Moolenaar 	return (TD_OK);
379*3c1e38eaSMarcel Moolenaar }
380*3c1e38eaSMarcel Moolenaar 
381*3c1e38eaSMarcel Moolenaar static td_err_e
382*3c1e38eaSMarcel Moolenaar pt_ta_event_addr(const td_thragent_t *ta, td_event_e event, td_notify_t *ptr)
383*3c1e38eaSMarcel Moolenaar {
384*3c1e38eaSMarcel Moolenaar 	TDBG_FUNC();
385*3c1e38eaSMarcel Moolenaar 	return (TD_NOEVENT);
386*3c1e38eaSMarcel Moolenaar }
387*3c1e38eaSMarcel Moolenaar 
388*3c1e38eaSMarcel Moolenaar static td_err_e
389*3c1e38eaSMarcel Moolenaar pt_ta_set_event(const td_thragent_t *ta, td_thr_events_t *events)
390*3c1e38eaSMarcel Moolenaar {
391*3c1e38eaSMarcel Moolenaar 	TDBG_FUNC();
392*3c1e38eaSMarcel Moolenaar 	return (TD_ERR);
393*3c1e38eaSMarcel Moolenaar }
394*3c1e38eaSMarcel Moolenaar 
395*3c1e38eaSMarcel Moolenaar static td_err_e
396*3c1e38eaSMarcel Moolenaar pt_ta_clear_event(const td_thragent_t *ta, td_thr_events_t *events)
397*3c1e38eaSMarcel Moolenaar {
398*3c1e38eaSMarcel Moolenaar 	TDBG_FUNC();
399*3c1e38eaSMarcel Moolenaar 	return (TD_ERR);
400*3c1e38eaSMarcel Moolenaar }
401*3c1e38eaSMarcel Moolenaar 
402*3c1e38eaSMarcel Moolenaar static td_err_e
403*3c1e38eaSMarcel Moolenaar pt_ta_event_getmsg(const td_thragent_t *ta, td_event_msg_t *msg)
404*3c1e38eaSMarcel Moolenaar {
405*3c1e38eaSMarcel Moolenaar 	TDBG_FUNC();
406*3c1e38eaSMarcel Moolenaar 	return (TD_NOMSG);
407*3c1e38eaSMarcel Moolenaar }
408*3c1e38eaSMarcel Moolenaar 
409*3c1e38eaSMarcel Moolenaar static td_err_e
410*3c1e38eaSMarcel Moolenaar pt_thr_dbresume(const td_thrhandle_t *th)
411*3c1e38eaSMarcel Moolenaar {
412*3c1e38eaSMarcel Moolenaar 	TDBG_FUNC();
413*3c1e38eaSMarcel Moolenaar 	return (TD_ERR);
414*3c1e38eaSMarcel Moolenaar }
415*3c1e38eaSMarcel Moolenaar 
416*3c1e38eaSMarcel Moolenaar static td_err_e
417*3c1e38eaSMarcel Moolenaar pt_thr_dbsuspend(const td_thrhandle_t *th)
418*3c1e38eaSMarcel Moolenaar {
419*3c1e38eaSMarcel Moolenaar 	TDBG_FUNC();
420*3c1e38eaSMarcel Moolenaar 	return (TD_ERR);
421*3c1e38eaSMarcel Moolenaar }
422*3c1e38eaSMarcel Moolenaar 
423*3c1e38eaSMarcel Moolenaar static td_err_e
424*3c1e38eaSMarcel Moolenaar pt_thr_validate(const td_thrhandle_t *th)
425*3c1e38eaSMarcel Moolenaar {
426*3c1e38eaSMarcel Moolenaar 	td_thrhandle_t temp;
427*3c1e38eaSMarcel Moolenaar 	int ret;
428*3c1e38eaSMarcel Moolenaar 
429*3c1e38eaSMarcel Moolenaar 	TDBG_FUNC();
430*3c1e38eaSMarcel Moolenaar 
431*3c1e38eaSMarcel Moolenaar 	ret = pt_ta_map_id2thr(th->th_ta, th->th_tid,
432*3c1e38eaSMarcel Moolenaar 	                       &temp);
433*3c1e38eaSMarcel Moolenaar 	return (P2T(ret));
434*3c1e38eaSMarcel Moolenaar }
435*3c1e38eaSMarcel Moolenaar 
436*3c1e38eaSMarcel Moolenaar static td_err_e
437*3c1e38eaSMarcel Moolenaar pt_thr_get_info(const td_thrhandle_t *th, td_thrinfo_t *info)
438*3c1e38eaSMarcel Moolenaar {
439*3c1e38eaSMarcel Moolenaar 	const td_thragent_t *ta = th->th_ta;
440*3c1e38eaSMarcel Moolenaar 	struct pthread pt;
441*3c1e38eaSMarcel Moolenaar 	int ret;
442*3c1e38eaSMarcel Moolenaar 
443*3c1e38eaSMarcel Moolenaar 	TDBG_FUNC();
444*3c1e38eaSMarcel Moolenaar 
445*3c1e38eaSMarcel Moolenaar 	ret = pt_validate(th);
446*3c1e38eaSMarcel Moolenaar 	if (ret)
447*3c1e38eaSMarcel Moolenaar 		return (ret);
448*3c1e38eaSMarcel Moolenaar 
449*3c1e38eaSMarcel Moolenaar 	memset(info, 0, sizeof(*info));
450*3c1e38eaSMarcel Moolenaar 	if (ta->map[th->th_tid].type == PT_LWP) {
451*3c1e38eaSMarcel Moolenaar 		info->ti_type = TD_THR_SYSTEM;
452*3c1e38eaSMarcel Moolenaar 		info->ti_lid = ta->map[th->th_tid].lwp;
453*3c1e38eaSMarcel Moolenaar 		info->ti_tid = th->th_tid;
454*3c1e38eaSMarcel Moolenaar 		info->ti_state = TD_THR_RUN;
455*3c1e38eaSMarcel Moolenaar 		info->ti_type = TD_THR_SYSTEM;
456*3c1e38eaSMarcel Moolenaar 		return (TD_OK);
457*3c1e38eaSMarcel Moolenaar 	}
458*3c1e38eaSMarcel Moolenaar 
459*3c1e38eaSMarcel Moolenaar 	ret = ps_pread(ta->ph, (psaddr_t)(ta->map[th->th_tid].thr),
460*3c1e38eaSMarcel Moolenaar 	                &pt, sizeof(pt));
461*3c1e38eaSMarcel Moolenaar 	if (ret != 0)
462*3c1e38eaSMarcel Moolenaar 		return (P2T(ret));
463*3c1e38eaSMarcel Moolenaar 	if (pt.magic != THR_MAGIC)
464*3c1e38eaSMarcel Moolenaar 		return (TD_BADTH);
465*3c1e38eaSMarcel Moolenaar 	ret = ps_pread(ta->ph,
466*3c1e38eaSMarcel Moolenaar 	        ((psaddr_t)pt.tcb) + offsetof(struct tcb, tcb_tmbx.tm_lwp),
467*3c1e38eaSMarcel Moolenaar 	        &info->ti_lid, sizeof(lwpid_t));
468*3c1e38eaSMarcel Moolenaar 	if (ret != 0)
469*3c1e38eaSMarcel Moolenaar 		return (P2T(ret));
470*3c1e38eaSMarcel Moolenaar 
471*3c1e38eaSMarcel Moolenaar 	info->ti_ta_p = th->th_ta;
472*3c1e38eaSMarcel Moolenaar 	info->ti_tid = th->th_tid;
473*3c1e38eaSMarcel Moolenaar 	info->ti_tls = (char *)pt.specific;
474*3c1e38eaSMarcel Moolenaar 	info->ti_startfunc = (psaddr_t)pt.start_routine;
475*3c1e38eaSMarcel Moolenaar 	info->ti_stkbase = (psaddr_t) pt.attr.stackaddr_attr;
476*3c1e38eaSMarcel Moolenaar 	info->ti_stksize = pt.attr.stacksize_attr;
477*3c1e38eaSMarcel Moolenaar 	switch (pt.state) {
478*3c1e38eaSMarcel Moolenaar 	case PS_RUNNING:
479*3c1e38eaSMarcel Moolenaar 		info->ti_state = TD_THR_RUN;
480*3c1e38eaSMarcel Moolenaar 		break;
481*3c1e38eaSMarcel Moolenaar 	case PS_LOCKWAIT:
482*3c1e38eaSMarcel Moolenaar 	case PS_MUTEX_WAIT:
483*3c1e38eaSMarcel Moolenaar 	case PS_COND_WAIT:
484*3c1e38eaSMarcel Moolenaar 	case PS_SIGSUSPEND:
485*3c1e38eaSMarcel Moolenaar 	case PS_SIGWAIT:
486*3c1e38eaSMarcel Moolenaar 	case PS_JOIN:
487*3c1e38eaSMarcel Moolenaar 	case PS_SUSPENDED:
488*3c1e38eaSMarcel Moolenaar 	case PS_DEADLOCK:
489*3c1e38eaSMarcel Moolenaar 	case PS_SLEEP_WAIT:
490*3c1e38eaSMarcel Moolenaar 		info->ti_state = TD_THR_SLEEP;
491*3c1e38eaSMarcel Moolenaar 		break;
492*3c1e38eaSMarcel Moolenaar 	case PS_DEAD:
493*3c1e38eaSMarcel Moolenaar 		info->ti_state = TD_THR_ZOMBIE;
494*3c1e38eaSMarcel Moolenaar 		break;
495*3c1e38eaSMarcel Moolenaar 	default:
496*3c1e38eaSMarcel Moolenaar 		info->ti_state = TD_THR_UNKNOWN;
497*3c1e38eaSMarcel Moolenaar 		break;
498*3c1e38eaSMarcel Moolenaar 	}
499*3c1e38eaSMarcel Moolenaar 
500*3c1e38eaSMarcel Moolenaar 	info->ti_db_suspended = 0;
501*3c1e38eaSMarcel Moolenaar 	info->ti_type = TD_THR_USER;
502*3c1e38eaSMarcel Moolenaar 	info->ti_pri = pt.active_priority;
503*3c1e38eaSMarcel Moolenaar 	info->ti_sigmask = pt.sigmask;
504*3c1e38eaSMarcel Moolenaar 	info->ti_traceme = 0;
505*3c1e38eaSMarcel Moolenaar 	info->ti_pending = pt.sigpend;
506*3c1e38eaSMarcel Moolenaar 	info->ti_events = 0;
507*3c1e38eaSMarcel Moolenaar 	return (0);
508*3c1e38eaSMarcel Moolenaar }
509*3c1e38eaSMarcel Moolenaar 
510*3c1e38eaSMarcel Moolenaar static td_err_e
511*3c1e38eaSMarcel Moolenaar pt_thr_getfpregs(const td_thrhandle_t *th, prfpregset_t *fpregs)
512*3c1e38eaSMarcel Moolenaar {
513*3c1e38eaSMarcel Moolenaar 	const td_thragent_t *ta = th->th_ta;
514*3c1e38eaSMarcel Moolenaar 	struct kse_thr_mailbox tmbx;
515*3c1e38eaSMarcel Moolenaar 	psaddr_t tcb_addr, tmbx_addr, ptr;
516*3c1e38eaSMarcel Moolenaar 	lwpid_t lwp;
517*3c1e38eaSMarcel Moolenaar 	int ret;
518*3c1e38eaSMarcel Moolenaar 
519*3c1e38eaSMarcel Moolenaar 	TDBG_FUNC();
520*3c1e38eaSMarcel Moolenaar 
521*3c1e38eaSMarcel Moolenaar 	ret = pt_validate(th);
522*3c1e38eaSMarcel Moolenaar 	if (ret)
523*3c1e38eaSMarcel Moolenaar 		return (ret);
524*3c1e38eaSMarcel Moolenaar 
525*3c1e38eaSMarcel Moolenaar 	if (ta->map[th->th_tid].type == PT_LWP) {
526*3c1e38eaSMarcel Moolenaar 		ret = ps_lgetfpregs(ta->ph, ta->map[th->th_tid].lwp, fpregs);
527*3c1e38eaSMarcel Moolenaar 		return (P2T(ret));
528*3c1e38eaSMarcel Moolenaar 	}
529*3c1e38eaSMarcel Moolenaar 
530*3c1e38eaSMarcel Moolenaar 	ret = ps_pread(ta->ph, ta->map[th->th_tid].thr +
531*3c1e38eaSMarcel Moolenaar  	                offsetof(struct pthread, tcb),
532*3c1e38eaSMarcel Moolenaar                         &tcb_addr, sizeof(tcb_addr));
533*3c1e38eaSMarcel Moolenaar 	if (ret != 0)
534*3c1e38eaSMarcel Moolenaar 		return (P2T(ret));
535*3c1e38eaSMarcel Moolenaar 	tmbx_addr = tcb_addr + offsetof(struct tcb, tcb_tmbx);
536*3c1e38eaSMarcel Moolenaar 	ptr = tmbx_addr + offsetof(struct kse_thr_mailbox, tm_lwp);
537*3c1e38eaSMarcel Moolenaar 	ret = ps_pread(ta->ph, ptr, &lwp, sizeof(lwpid_t));
538*3c1e38eaSMarcel Moolenaar 	if (ret != 0)
539*3c1e38eaSMarcel Moolenaar 		return (P2T(ret));
540*3c1e38eaSMarcel Moolenaar 	if (lwp != 0) {
541*3c1e38eaSMarcel Moolenaar 		ret = ps_lgetfpregs(ta->ph, lwp, fpregs);
542*3c1e38eaSMarcel Moolenaar 		return (P2T(ret));
543*3c1e38eaSMarcel Moolenaar 	}
544*3c1e38eaSMarcel Moolenaar 
545*3c1e38eaSMarcel Moolenaar 	ret = ps_pread(ta->ph, tmbx_addr, &tmbx, sizeof(tmbx));
546*3c1e38eaSMarcel Moolenaar 	if (ret != 0)
547*3c1e38eaSMarcel Moolenaar 		return (P2T(ret));
548*3c1e38eaSMarcel Moolenaar 	pt_ucontext_to_fpreg(&tmbx.tm_context, fpregs);
549*3c1e38eaSMarcel Moolenaar 	return (0);
550*3c1e38eaSMarcel Moolenaar }
551*3c1e38eaSMarcel Moolenaar 
552*3c1e38eaSMarcel Moolenaar static td_err_e
553*3c1e38eaSMarcel Moolenaar pt_thr_getgregs(const td_thrhandle_t *th, prgregset_t gregs)
554*3c1e38eaSMarcel Moolenaar {
555*3c1e38eaSMarcel Moolenaar 	const td_thragent_t *ta = th->th_ta;
556*3c1e38eaSMarcel Moolenaar 	struct kse_thr_mailbox tmbx;
557*3c1e38eaSMarcel Moolenaar 	psaddr_t tcb_addr, tmbx_addr, ptr;
558*3c1e38eaSMarcel Moolenaar 	lwpid_t lwp;
559*3c1e38eaSMarcel Moolenaar 	int ret;
560*3c1e38eaSMarcel Moolenaar 
561*3c1e38eaSMarcel Moolenaar 	TDBG_FUNC();
562*3c1e38eaSMarcel Moolenaar 
563*3c1e38eaSMarcel Moolenaar 	ret = pt_validate(th);
564*3c1e38eaSMarcel Moolenaar 	if (ret)
565*3c1e38eaSMarcel Moolenaar 		return (ret);
566*3c1e38eaSMarcel Moolenaar 
567*3c1e38eaSMarcel Moolenaar 	if (ta->map[th->th_tid].type == PT_LWP) {
568*3c1e38eaSMarcel Moolenaar 		ret = ps_lgetregs(ta->ph,
569*3c1e38eaSMarcel Moolenaar 		                  ta->map[th->th_tid].lwp, gregs);
570*3c1e38eaSMarcel Moolenaar 		return (P2T(ret));
571*3c1e38eaSMarcel Moolenaar 	}
572*3c1e38eaSMarcel Moolenaar 
573*3c1e38eaSMarcel Moolenaar 	ret = ps_pread(ta->ph, ta->map[th->th_tid].thr +
574*3c1e38eaSMarcel Moolenaar 	                offsetof(struct pthread, tcb),
575*3c1e38eaSMarcel Moolenaar 			&tcb_addr, sizeof(tcb_addr));
576*3c1e38eaSMarcel Moolenaar 	if (ret != 0)
577*3c1e38eaSMarcel Moolenaar 		return (P2T(ret));
578*3c1e38eaSMarcel Moolenaar 	tmbx_addr = tcb_addr + offsetof(struct tcb, tcb_tmbx);
579*3c1e38eaSMarcel Moolenaar 	ptr = tmbx_addr + offsetof(struct kse_thr_mailbox, tm_lwp);
580*3c1e38eaSMarcel Moolenaar 	ret = ps_pread(ta->ph, ptr, &lwp, sizeof(lwpid_t));
581*3c1e38eaSMarcel Moolenaar 	if (ret != 0)
582*3c1e38eaSMarcel Moolenaar 		return (P2T(ret));
583*3c1e38eaSMarcel Moolenaar 	if (lwp != 0) {
584*3c1e38eaSMarcel Moolenaar 		ret = ps_lgetregs(ta->ph, lwp, gregs);
585*3c1e38eaSMarcel Moolenaar 		return (P2T(ret));
586*3c1e38eaSMarcel Moolenaar 	}
587*3c1e38eaSMarcel Moolenaar 	ret = ps_pread(ta->ph, tmbx_addr, &tmbx, sizeof(tmbx));
588*3c1e38eaSMarcel Moolenaar 	if (ret != 0)
589*3c1e38eaSMarcel Moolenaar 		return (P2T(ret));
590*3c1e38eaSMarcel Moolenaar 	pt_ucontext_to_reg(&tmbx.tm_context, gregs);
591*3c1e38eaSMarcel Moolenaar 	return (0);
592*3c1e38eaSMarcel Moolenaar }
593*3c1e38eaSMarcel Moolenaar 
594*3c1e38eaSMarcel Moolenaar static td_err_e
595*3c1e38eaSMarcel Moolenaar pt_thr_setfpregs(const td_thrhandle_t *th, const prfpregset_t *fpregs)
596*3c1e38eaSMarcel Moolenaar {
597*3c1e38eaSMarcel Moolenaar 	const td_thragent_t *ta = th->th_ta;
598*3c1e38eaSMarcel Moolenaar 	struct kse_thr_mailbox tmbx;
599*3c1e38eaSMarcel Moolenaar 	psaddr_t tcb_addr, tmbx_addr, ptr;
600*3c1e38eaSMarcel Moolenaar 	lwpid_t lwp;
601*3c1e38eaSMarcel Moolenaar 	int ret;
602*3c1e38eaSMarcel Moolenaar 
603*3c1e38eaSMarcel Moolenaar 	TDBG_FUNC();
604*3c1e38eaSMarcel Moolenaar 
605*3c1e38eaSMarcel Moolenaar 	ret = pt_validate(th);
606*3c1e38eaSMarcel Moolenaar 	if (ret)
607*3c1e38eaSMarcel Moolenaar 		return (ret);
608*3c1e38eaSMarcel Moolenaar 
609*3c1e38eaSMarcel Moolenaar 	if (ta->map[th->th_tid].type == PT_LWP) {
610*3c1e38eaSMarcel Moolenaar 		ret = ps_lsetfpregs(ta->ph, ta->map[th->th_tid].lwp, fpregs);
611*3c1e38eaSMarcel Moolenaar 		return (P2T(ret));
612*3c1e38eaSMarcel Moolenaar 	}
613*3c1e38eaSMarcel Moolenaar 
614*3c1e38eaSMarcel Moolenaar 	ret = ps_pread(ta->ph, ta->map[th->th_tid].thr +
615*3c1e38eaSMarcel Moolenaar 	                offsetof(struct pthread, tcb),
616*3c1e38eaSMarcel Moolenaar                         &tcb_addr, sizeof(tcb_addr));
617*3c1e38eaSMarcel Moolenaar 	if (ret != 0)
618*3c1e38eaSMarcel Moolenaar 		return (P2T(ret));
619*3c1e38eaSMarcel Moolenaar 	tmbx_addr = tcb_addr + offsetof(struct tcb, tcb_tmbx);
620*3c1e38eaSMarcel Moolenaar 	ptr = tmbx_addr + offsetof(struct kse_thr_mailbox, tm_lwp);
621*3c1e38eaSMarcel Moolenaar 	ret = ps_pread(ta->ph, ptr, &lwp, sizeof(lwpid_t));
622*3c1e38eaSMarcel Moolenaar 	if (ret != 0)
623*3c1e38eaSMarcel Moolenaar 		return (P2T(ret));
624*3c1e38eaSMarcel Moolenaar 	if (lwp != 0) {
625*3c1e38eaSMarcel Moolenaar 		ret = ps_lsetfpregs(ta->ph, lwp, fpregs);
626*3c1e38eaSMarcel Moolenaar 		return (P2T(ret));
627*3c1e38eaSMarcel Moolenaar 	}
628*3c1e38eaSMarcel Moolenaar 	/*
629*3c1e38eaSMarcel Moolenaar 	 * Read a copy of context, this makes sure that registers
630*3c1e38eaSMarcel Moolenaar 	 * not covered by structure reg won't be clobbered
631*3c1e38eaSMarcel Moolenaar 	 */
632*3c1e38eaSMarcel Moolenaar 	ret = ps_pread(ta->ph, tmbx_addr, &tmbx, sizeof(tmbx));
633*3c1e38eaSMarcel Moolenaar 	if (ret != 0)
634*3c1e38eaSMarcel Moolenaar 		return (P2T(ret));
635*3c1e38eaSMarcel Moolenaar 
636*3c1e38eaSMarcel Moolenaar 	pt_fpreg_to_ucontext(fpregs, &tmbx.tm_context);
637*3c1e38eaSMarcel Moolenaar 	ret = ps_pwrite(ta->ph, tmbx_addr, &tmbx, sizeof(tmbx));
638*3c1e38eaSMarcel Moolenaar 	return (P2T(ret));
639*3c1e38eaSMarcel Moolenaar }
640*3c1e38eaSMarcel Moolenaar 
641*3c1e38eaSMarcel Moolenaar static td_err_e
642*3c1e38eaSMarcel Moolenaar pt_thr_setgregs(const td_thrhandle_t *th, const prgregset_t gregs)
643*3c1e38eaSMarcel Moolenaar {
644*3c1e38eaSMarcel Moolenaar 	const td_thragent_t *ta = th->th_ta;
645*3c1e38eaSMarcel Moolenaar 	struct kse_thr_mailbox tmbx;
646*3c1e38eaSMarcel Moolenaar 	psaddr_t tcb_addr, tmbx_addr, ptr;
647*3c1e38eaSMarcel Moolenaar 	lwpid_t lwp;
648*3c1e38eaSMarcel Moolenaar 	int ret;
649*3c1e38eaSMarcel Moolenaar 
650*3c1e38eaSMarcel Moolenaar 	TDBG_FUNC();
651*3c1e38eaSMarcel Moolenaar 
652*3c1e38eaSMarcel Moolenaar 	ret = pt_validate(th);
653*3c1e38eaSMarcel Moolenaar 	if (ret)
654*3c1e38eaSMarcel Moolenaar 		return (ret);
655*3c1e38eaSMarcel Moolenaar 
656*3c1e38eaSMarcel Moolenaar 	if (ta->map[th->th_tid].type == PT_LWP) {
657*3c1e38eaSMarcel Moolenaar 		ret = ps_lsetregs(ta->ph, ta->map[th->th_tid].lwp, gregs);
658*3c1e38eaSMarcel Moolenaar 		return (P2T(ret));
659*3c1e38eaSMarcel Moolenaar 	}
660*3c1e38eaSMarcel Moolenaar 
661*3c1e38eaSMarcel Moolenaar 	ret = ps_pread(ta->ph, ta->map[th->th_tid].thr +
662*3c1e38eaSMarcel Moolenaar 	                offsetof(struct pthread, tcb),
663*3c1e38eaSMarcel Moolenaar 	                &tcb_addr, sizeof(tcb_addr));
664*3c1e38eaSMarcel Moolenaar 	if (ret != 0)
665*3c1e38eaSMarcel Moolenaar 		return (P2T(ret));
666*3c1e38eaSMarcel Moolenaar 	tmbx_addr = tcb_addr + offsetof(struct tcb, tcb_tmbx);
667*3c1e38eaSMarcel Moolenaar 	ptr = tmbx_addr + offsetof(struct kse_thr_mailbox, tm_lwp);
668*3c1e38eaSMarcel Moolenaar 	ret = ps_pread(ta->ph, ptr, &lwp, sizeof(lwpid_t));
669*3c1e38eaSMarcel Moolenaar 	if (ret != 0)
670*3c1e38eaSMarcel Moolenaar 		return (P2T(ret));
671*3c1e38eaSMarcel Moolenaar 	if (lwp != 0) {
672*3c1e38eaSMarcel Moolenaar 		ret = ps_lsetregs(ta->ph, lwp, gregs);
673*3c1e38eaSMarcel Moolenaar 		return (P2T(ret));
674*3c1e38eaSMarcel Moolenaar 	}
675*3c1e38eaSMarcel Moolenaar 
676*3c1e38eaSMarcel Moolenaar 	/*
677*3c1e38eaSMarcel Moolenaar 	 * Read a copy of context, make sure that registers
678*3c1e38eaSMarcel Moolenaar 	 * not covered by structure reg won't be clobbered
679*3c1e38eaSMarcel Moolenaar 	 */
680*3c1e38eaSMarcel Moolenaar 	ret = ps_pread(ta->ph, tmbx_addr, &tmbx, sizeof(tmbx));
681*3c1e38eaSMarcel Moolenaar 	if (ret != 0)
682*3c1e38eaSMarcel Moolenaar 		return (P2T(ret));
683*3c1e38eaSMarcel Moolenaar 	pt_reg_to_ucontext(gregs, &tmbx.tm_context);
684*3c1e38eaSMarcel Moolenaar 	ret = ps_pwrite(ta->ph, tmbx_addr, &tmbx, sizeof(tmbx));
685*3c1e38eaSMarcel Moolenaar 	return (P2T(ret));
686*3c1e38eaSMarcel Moolenaar }
687*3c1e38eaSMarcel Moolenaar 
688*3c1e38eaSMarcel Moolenaar static td_err_e
689*3c1e38eaSMarcel Moolenaar pt_thr_event_enable(const td_thrhandle_t *th, int en)
690*3c1e38eaSMarcel Moolenaar {
691*3c1e38eaSMarcel Moolenaar 	TDBG_FUNC();
692*3c1e38eaSMarcel Moolenaar 	return (TD_ERR);
693*3c1e38eaSMarcel Moolenaar }
694*3c1e38eaSMarcel Moolenaar 
695*3c1e38eaSMarcel Moolenaar static td_err_e
696*3c1e38eaSMarcel Moolenaar pt_thr_set_event(const td_thrhandle_t *th, td_thr_events_t *setp)
697*3c1e38eaSMarcel Moolenaar {
698*3c1e38eaSMarcel Moolenaar 	TDBG_FUNC();
699*3c1e38eaSMarcel Moolenaar 	return (TD_ERR);
700*3c1e38eaSMarcel Moolenaar }
701*3c1e38eaSMarcel Moolenaar 
702*3c1e38eaSMarcel Moolenaar static td_err_e
703*3c1e38eaSMarcel Moolenaar pt_thr_clear_event(const td_thrhandle_t *th, td_thr_events_t *setp)
704*3c1e38eaSMarcel Moolenaar {
705*3c1e38eaSMarcel Moolenaar 	TDBG_FUNC();
706*3c1e38eaSMarcel Moolenaar 	return (TD_ERR);
707*3c1e38eaSMarcel Moolenaar }
708*3c1e38eaSMarcel Moolenaar 
709*3c1e38eaSMarcel Moolenaar static td_err_e
710*3c1e38eaSMarcel Moolenaar pt_thr_event_getmsg(const td_thrhandle_t *th, td_event_msg_t *msg)
711*3c1e38eaSMarcel Moolenaar {
712*3c1e38eaSMarcel Moolenaar 	TDBG_FUNC();
713*3c1e38eaSMarcel Moolenaar 	return (TD_NOMSG);
714*3c1e38eaSMarcel Moolenaar }
715*3c1e38eaSMarcel Moolenaar 
716*3c1e38eaSMarcel Moolenaar static td_err_e
717*3c1e38eaSMarcel Moolenaar pt_thr_sstep(const td_thrhandle_t *th, int step)
718*3c1e38eaSMarcel Moolenaar {
719*3c1e38eaSMarcel Moolenaar 	const td_thragent_t *ta = th->th_ta;
720*3c1e38eaSMarcel Moolenaar 	struct kse_thr_mailbox tmbx;
721*3c1e38eaSMarcel Moolenaar 	struct reg regs;
722*3c1e38eaSMarcel Moolenaar 	psaddr_t tcb_addr, tmbx_addr;
723*3c1e38eaSMarcel Moolenaar 	uint32_t tmp;
724*3c1e38eaSMarcel Moolenaar 	lwpid_t lwp;
725*3c1e38eaSMarcel Moolenaar 	int ret;
726*3c1e38eaSMarcel Moolenaar 
727*3c1e38eaSMarcel Moolenaar 	TDBG_FUNC();
728*3c1e38eaSMarcel Moolenaar 
729*3c1e38eaSMarcel Moolenaar 	ret = pt_validate(th);
730*3c1e38eaSMarcel Moolenaar 	if (ret)
731*3c1e38eaSMarcel Moolenaar 		return (ret);
732*3c1e38eaSMarcel Moolenaar 
733*3c1e38eaSMarcel Moolenaar 	if (ta->map[th->th_tid].type == PT_LWP)
734*3c1e38eaSMarcel Moolenaar 		return (TD_BADTH);
735*3c1e38eaSMarcel Moolenaar 
736*3c1e38eaSMarcel Moolenaar 	ret = ps_pread(ta->ph, ta->map[th->th_tid].thr +
737*3c1e38eaSMarcel Moolenaar 	                offsetof(struct pthread, tcb),
738*3c1e38eaSMarcel Moolenaar 	                &tcb_addr, sizeof(tcb_addr));
739*3c1e38eaSMarcel Moolenaar 	if (ret != 0)
740*3c1e38eaSMarcel Moolenaar 		return (P2T(ret));
741*3c1e38eaSMarcel Moolenaar 
742*3c1e38eaSMarcel Moolenaar 	/* Clear or set single step flag in thread mailbox */
743*3c1e38eaSMarcel Moolenaar 	tmp = step ? TMDF_SSTEP : 0;
744*3c1e38eaSMarcel Moolenaar 	ret = ps_pwrite(ta->ph, tcb_addr + offsetof(struct tcb,
745*3c1e38eaSMarcel Moolenaar 	                 tcb_tmbx.tm_dflags), &tmp, sizeof(tmp));
746*3c1e38eaSMarcel Moolenaar 	if (ret != 0)
747*3c1e38eaSMarcel Moolenaar 		return (P2T(ret));
748*3c1e38eaSMarcel Moolenaar 	/* Get lwp */
749*3c1e38eaSMarcel Moolenaar 	ret = ps_pread(ta->ph, tcb_addr + offsetof(struct tcb,
750*3c1e38eaSMarcel Moolenaar 	                tcb_tmbx.tm_lwp), &lwp, sizeof(lwpid_t));
751*3c1e38eaSMarcel Moolenaar 	if (ret != 0)
752*3c1e38eaSMarcel Moolenaar 		return (P2T(ret));
753*3c1e38eaSMarcel Moolenaar 	if (lwp != 0)
754*3c1e38eaSMarcel Moolenaar 		return (TD_BADTH);
755*3c1e38eaSMarcel Moolenaar 
756*3c1e38eaSMarcel Moolenaar 	tmbx_addr = tcb_addr + offsetof(struct tcb, tcb_tmbx);
757*3c1e38eaSMarcel Moolenaar 	/*
758*3c1e38eaSMarcel Moolenaar 	 * context is in userland, some architectures store
759*3c1e38eaSMarcel Moolenaar 	 * single step status in registers, we should change
760*3c1e38eaSMarcel Moolenaar 	 * these registers.
761*3c1e38eaSMarcel Moolenaar 	 */
762*3c1e38eaSMarcel Moolenaar 	ret = ps_pread(ta->ph, tmbx_addr, &tmbx, sizeof(tmbx));
763*3c1e38eaSMarcel Moolenaar 	if (ret == 0) {
764*3c1e38eaSMarcel Moolenaar 		pt_ucontext_to_reg(&tmbx.tm_context, &regs);
765*3c1e38eaSMarcel Moolenaar 		/* only write out if it is really changed. */
766*3c1e38eaSMarcel Moolenaar 		if (pt_reg_sstep(&regs, step) != 0) {
767*3c1e38eaSMarcel Moolenaar 			pt_reg_to_ucontext(&regs, &tmbx.tm_context);
768*3c1e38eaSMarcel Moolenaar 			ret = ps_pwrite(ta->ph, tmbx_addr, &tmbx,
769*3c1e38eaSMarcel Moolenaar 			                 sizeof(tmbx));
770*3c1e38eaSMarcel Moolenaar 		}
771*3c1e38eaSMarcel Moolenaar 	}
772*3c1e38eaSMarcel Moolenaar 	return (P2T(ret));
773*3c1e38eaSMarcel Moolenaar }
774*3c1e38eaSMarcel Moolenaar 
775*3c1e38eaSMarcel Moolenaar static void
776*3c1e38eaSMarcel Moolenaar pt_unmap_lwp(const td_thragent_t *ta, lwpid_t lwp)
777*3c1e38eaSMarcel Moolenaar {
778*3c1e38eaSMarcel Moolenaar 	int i;
779*3c1e38eaSMarcel Moolenaar 
780*3c1e38eaSMarcel Moolenaar 	for (i = 0; i < ta->map_len; ++i) {
781*3c1e38eaSMarcel Moolenaar 		if (ta->map[i].type == PT_LWP && ta->map[i].lwp == lwp) {
782*3c1e38eaSMarcel Moolenaar 			ta->map[i].type = PT_NONE;
783*3c1e38eaSMarcel Moolenaar 			return;
784*3c1e38eaSMarcel Moolenaar 		}
785*3c1e38eaSMarcel Moolenaar 	}
786*3c1e38eaSMarcel Moolenaar }
787*3c1e38eaSMarcel Moolenaar 
788*3c1e38eaSMarcel Moolenaar static int
789*3c1e38eaSMarcel Moolenaar pt_validate(const td_thrhandle_t *th)
790*3c1e38eaSMarcel Moolenaar {
791*3c1e38eaSMarcel Moolenaar 
792*3c1e38eaSMarcel Moolenaar 	if (th->th_tid < 0 || th->th_tid >= th->th_ta->map_len ||
793*3c1e38eaSMarcel Moolenaar 	    th->th_ta->map[th->th_tid].type == PT_NONE)
794*3c1e38eaSMarcel Moolenaar 		return (TD_NOTHR);
795*3c1e38eaSMarcel Moolenaar 	return (TD_OK);
796*3c1e38eaSMarcel Moolenaar }
797*3c1e38eaSMarcel Moolenaar 
798*3c1e38eaSMarcel Moolenaar struct ta_ops libpthread_db_ops = {
799*3c1e38eaSMarcel Moolenaar 	.to_init		= pt_init,
800*3c1e38eaSMarcel Moolenaar 	.to_ta_clear_event	= pt_ta_clear_event,
801*3c1e38eaSMarcel Moolenaar 	.to_ta_delete		= pt_ta_delete,
802*3c1e38eaSMarcel Moolenaar 	.to_ta_event_addr	= pt_ta_event_addr,
803*3c1e38eaSMarcel Moolenaar 	.to_ta_event_getmsg	= pt_ta_event_getmsg,
804*3c1e38eaSMarcel Moolenaar 	.to_ta_map_id2thr	= pt_ta_map_id2thr,
805*3c1e38eaSMarcel Moolenaar 	.to_ta_map_lwp2thr	= pt_ta_map_lwp2thr,
806*3c1e38eaSMarcel Moolenaar 	.to_ta_new		= pt_ta_new,
807*3c1e38eaSMarcel Moolenaar 	.to_ta_set_event	= pt_ta_set_event,
808*3c1e38eaSMarcel Moolenaar 	.to_ta_thr_iter		= pt_ta_thr_iter,
809*3c1e38eaSMarcel Moolenaar 	.to_ta_tsd_iter		= pt_ta_tsd_iter,
810*3c1e38eaSMarcel Moolenaar 	.to_thr_clear_event	= pt_thr_clear_event,
811*3c1e38eaSMarcel Moolenaar 	.to_thr_dbresume	= pt_thr_dbresume,
812*3c1e38eaSMarcel Moolenaar 	.to_thr_dbsuspend	= pt_thr_dbsuspend,
813*3c1e38eaSMarcel Moolenaar 	.to_thr_event_enable	= pt_thr_event_enable,
814*3c1e38eaSMarcel Moolenaar 	.to_thr_event_getmsg	= pt_thr_event_getmsg,
815*3c1e38eaSMarcel Moolenaar 	.to_thr_get_info	= pt_thr_get_info,
816*3c1e38eaSMarcel Moolenaar 	.to_thr_getfpregs	= pt_thr_getfpregs,
817*3c1e38eaSMarcel Moolenaar 	.to_thr_getgregs	= pt_thr_getgregs,
818*3c1e38eaSMarcel Moolenaar 	.to_thr_set_event	= pt_thr_set_event,
819*3c1e38eaSMarcel Moolenaar 	.to_thr_setfpregs	= pt_thr_setfpregs,
820*3c1e38eaSMarcel Moolenaar 	.to_thr_setgregs	= pt_thr_setgregs,
821*3c1e38eaSMarcel Moolenaar 	.to_thr_validate	= pt_thr_validate,
822*3c1e38eaSMarcel Moolenaar 
823*3c1e38eaSMarcel Moolenaar 	/* FreeBSD specific extensions. */
824*3c1e38eaSMarcel Moolenaar 	.to_thr_sstep		= pt_thr_sstep,
825*3c1e38eaSMarcel Moolenaar };
826