xref: /dragonfly/lib/libthread_db/libthread_xu.c (revision 86d7f5d3)
1*86d7f5d3SJohn Marino /*
2*86d7f5d3SJohn Marino  * Copyright (c) 2004 Marcel Moolenaar
3*86d7f5d3SJohn Marino  * Copyright (c) 2005 David Xu
4*86d7f5d3SJohn Marino  * All rights reserved.
5*86d7f5d3SJohn Marino  *
6*86d7f5d3SJohn Marino  * Redistribution and use in source and binary forms, with or without
7*86d7f5d3SJohn Marino  * modification, are permitted provided that the following conditions
8*86d7f5d3SJohn Marino  * are met:
9*86d7f5d3SJohn Marino  *
10*86d7f5d3SJohn Marino  * 1. Redistributions of source code must retain the above copyright
11*86d7f5d3SJohn Marino  *    notice, this list of conditions and the following disclaimer.
12*86d7f5d3SJohn Marino  * 2. Redistributions in binary form must reproduce the above copyright
13*86d7f5d3SJohn Marino  *    notice, this list of conditions and the following disclaimer in the
14*86d7f5d3SJohn Marino  *    documentation and/or other materials provided with the distribution.
15*86d7f5d3SJohn Marino  *
16*86d7f5d3SJohn Marino  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17*86d7f5d3SJohn Marino  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18*86d7f5d3SJohn Marino  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19*86d7f5d3SJohn Marino  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
20*86d7f5d3SJohn Marino  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
21*86d7f5d3SJohn Marino  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22*86d7f5d3SJohn Marino  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23*86d7f5d3SJohn Marino  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24*86d7f5d3SJohn Marino  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
25*86d7f5d3SJohn Marino  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26*86d7f5d3SJohn Marino  *
27*86d7f5d3SJohn Marino  * $DragonFly: src/lib/libthread_db/libthread_xu.c,v 1.3 2005/05/07 10:08:08 davidxu Exp $
28*86d7f5d3SJohn Marino  */
29*86d7f5d3SJohn Marino 
30*86d7f5d3SJohn Marino #include <sys/cdefs.h>
31*86d7f5d3SJohn Marino 
32*86d7f5d3SJohn Marino #include <proc_service.h>
33*86d7f5d3SJohn Marino #include <stddef.h>
34*86d7f5d3SJohn Marino #include <stdlib.h>
35*86d7f5d3SJohn Marino #include <string.h>
36*86d7f5d3SJohn Marino #include <machine/tls.h>
37*86d7f5d3SJohn Marino #include <sys/types.h>
38*86d7f5d3SJohn Marino #include <sys/ptrace.h>
39*86d7f5d3SJohn Marino #include <rtld.h>
40*86d7f5d3SJohn Marino #include <thread_db.h>
41*86d7f5d3SJohn Marino #include <unistd.h>
42*86d7f5d3SJohn Marino 
43*86d7f5d3SJohn Marino #include "thread_db_int.h"
44*86d7f5d3SJohn Marino 
45*86d7f5d3SJohn Marino #define	TERMINATED	1
46*86d7f5d3SJohn Marino 
47*86d7f5d3SJohn Marino struct td_thragent {
48*86d7f5d3SJohn Marino 	TD_THRAGENT_FIELDS;
49*86d7f5d3SJohn Marino 	psaddr_t	libthread_xu_debug_addr;
50*86d7f5d3SJohn Marino 	psaddr_t	thread_active_threads_addr;
51*86d7f5d3SJohn Marino 	psaddr_t	thread_bp_create_addr;
52*86d7f5d3SJohn Marino 	psaddr_t	thread_bp_death_addr;
53*86d7f5d3SJohn Marino 	psaddr_t	thread_event_mask_addr;
54*86d7f5d3SJohn Marino 	psaddr_t	thread_keytable_addr;
55*86d7f5d3SJohn Marino 	psaddr_t	thread_last_event_addr;
56*86d7f5d3SJohn Marino 	psaddr_t	thread_list_addr;
57*86d7f5d3SJohn Marino 	int		thread_max_keys;
58*86d7f5d3SJohn Marino 	int		thread_off_attr_flags;
59*86d7f5d3SJohn Marino 	int		thread_off_dtv;
60*86d7f5d3SJohn Marino 	int		thread_off_event_buf;
61*86d7f5d3SJohn Marino 	int		thread_off_event_mask;
62*86d7f5d3SJohn Marino 	int		thread_off_key_allocated;
63*86d7f5d3SJohn Marino 	int		thread_off_key_destructor;
64*86d7f5d3SJohn Marino 	int		thread_off_linkmap;
65*86d7f5d3SJohn Marino 	int		thread_off_next;
66*86d7f5d3SJohn Marino 	int		thread_off_report_events;
67*86d7f5d3SJohn Marino 	int		thread_off_state;
68*86d7f5d3SJohn Marino 	int		thread_off_tcb;
69*86d7f5d3SJohn Marino 	int		thread_off_tid;
70*86d7f5d3SJohn Marino 	int		thread_off_tlsindex;
71*86d7f5d3SJohn Marino 	int		thread_size_key;
72*86d7f5d3SJohn Marino 	int		thread_state_running;
73*86d7f5d3SJohn Marino 	int		thread_state_zoombie;
74*86d7f5d3SJohn Marino };
75*86d7f5d3SJohn Marino 
76*86d7f5d3SJohn Marino #define P2T(c) ps2td(c)
77*86d7f5d3SJohn Marino 
78*86d7f5d3SJohn Marino static int pt_validate(const td_thrhandle_t *th);
79*86d7f5d3SJohn Marino 
80*86d7f5d3SJohn Marino static int
ps2td(int c)81*86d7f5d3SJohn Marino ps2td(int c)
82*86d7f5d3SJohn Marino {
83*86d7f5d3SJohn Marino 	switch (c) {
84*86d7f5d3SJohn Marino 	case PS_OK:
85*86d7f5d3SJohn Marino 		return TD_OK;
86*86d7f5d3SJohn Marino 	case PS_ERR:
87*86d7f5d3SJohn Marino 		return TD_ERR;
88*86d7f5d3SJohn Marino 	case PS_BADPID:
89*86d7f5d3SJohn Marino 		return TD_BADPH;
90*86d7f5d3SJohn Marino 	case PS_BADLID:
91*86d7f5d3SJohn Marino 		return TD_NOLWP;
92*86d7f5d3SJohn Marino 	case PS_BADADDR:
93*86d7f5d3SJohn Marino 		return TD_ERR;
94*86d7f5d3SJohn Marino 	case PS_NOSYM:
95*86d7f5d3SJohn Marino 		return TD_NOLIBTHREAD;
96*86d7f5d3SJohn Marino 	case PS_NOFREGS:
97*86d7f5d3SJohn Marino 		return TD_NOFPREGS;
98*86d7f5d3SJohn Marino 	default:
99*86d7f5d3SJohn Marino 		return TD_ERR;
100*86d7f5d3SJohn Marino 	}
101*86d7f5d3SJohn Marino }
102*86d7f5d3SJohn Marino 
103*86d7f5d3SJohn Marino static td_err_e
pt_init(void)104*86d7f5d3SJohn Marino pt_init(void)
105*86d7f5d3SJohn Marino {
106*86d7f5d3SJohn Marino 	return (0);
107*86d7f5d3SJohn Marino }
108*86d7f5d3SJohn Marino 
109*86d7f5d3SJohn Marino static td_err_e
pt_ta_new(struct ps_prochandle * ph,td_thragent_t ** pta)110*86d7f5d3SJohn Marino pt_ta_new(struct ps_prochandle *ph, td_thragent_t **pta)
111*86d7f5d3SJohn Marino {
112*86d7f5d3SJohn Marino #define LOOKUP_SYM(proc, sym, addr) 			\
113*86d7f5d3SJohn Marino 	ret = ps_pglobal_lookup(proc, NULL, sym, addr);	\
114*86d7f5d3SJohn Marino 	if (ret != 0) {					\
115*86d7f5d3SJohn Marino 		TDBG("can not find symbol: %s\n", sym);	\
116*86d7f5d3SJohn Marino 		ret = TD_NOLIBTHREAD;			\
117*86d7f5d3SJohn Marino 		goto error;				\
118*86d7f5d3SJohn Marino 	}
119*86d7f5d3SJohn Marino 
120*86d7f5d3SJohn Marino #define	LOOKUP_VAL(proc, sym, val)			\
121*86d7f5d3SJohn Marino 	ret = ps_pglobal_lookup(proc, NULL, sym, &vaddr);\
122*86d7f5d3SJohn Marino 	if (ret != 0) {					\
123*86d7f5d3SJohn Marino 		TDBG("can not find symbol: %s\n", sym);	\
124*86d7f5d3SJohn Marino 		ret = TD_NOLIBTHREAD;			\
125*86d7f5d3SJohn Marino 		goto error;				\
126*86d7f5d3SJohn Marino 	}						\
127*86d7f5d3SJohn Marino 	ret = ps_pread(proc, vaddr, val, sizeof(int));	\
128*86d7f5d3SJohn Marino 	if (ret != 0) {					\
129*86d7f5d3SJohn Marino 		TDBG("can not read value of %s\n", sym);\
130*86d7f5d3SJohn Marino 		ret = TD_NOLIBTHREAD;			\
131*86d7f5d3SJohn Marino 		goto error;				\
132*86d7f5d3SJohn Marino 	}
133*86d7f5d3SJohn Marino 
134*86d7f5d3SJohn Marino 	td_thragent_t *ta;
135*86d7f5d3SJohn Marino 	psaddr_t vaddr;
136*86d7f5d3SJohn Marino 	int dbg;
137*86d7f5d3SJohn Marino 	int ret;
138*86d7f5d3SJohn Marino 
139*86d7f5d3SJohn Marino 	TDBG_FUNC();
140*86d7f5d3SJohn Marino 
141*86d7f5d3SJohn Marino 	ta = malloc(sizeof(td_thragent_t));
142*86d7f5d3SJohn Marino 	if (ta == NULL)
143*86d7f5d3SJohn Marino 		return (TD_MALLOC);
144*86d7f5d3SJohn Marino 
145*86d7f5d3SJohn Marino 	ta->ph = ph;
146*86d7f5d3SJohn Marino 
147*86d7f5d3SJohn Marino 	LOOKUP_SYM(ph, "_libthread_xu_debug",	&ta->libthread_xu_debug_addr);
148*86d7f5d3SJohn Marino 	LOOKUP_SYM(ph, "_thread_active_threads",&ta->thread_active_threads_addr);
149*86d7f5d3SJohn Marino 	LOOKUP_SYM(ph, "_thread_bp_create",	&ta->thread_bp_create_addr);
150*86d7f5d3SJohn Marino 	LOOKUP_SYM(ph, "_thread_bp_death",	&ta->thread_bp_death_addr);
151*86d7f5d3SJohn Marino 	LOOKUP_SYM(ph, "_thread_event_mask",	&ta->thread_event_mask_addr);
152*86d7f5d3SJohn Marino 	LOOKUP_SYM(ph, "_thread_keytable",	&ta->thread_keytable_addr);
153*86d7f5d3SJohn Marino 	LOOKUP_SYM(ph, "_thread_last_event",	&ta->thread_last_event_addr);
154*86d7f5d3SJohn Marino 	LOOKUP_SYM(ph, "_thread_list",		&ta->thread_list_addr);
155*86d7f5d3SJohn Marino 	LOOKUP_VAL(ph, "_thread_max_keys",	&ta->thread_max_keys);
156*86d7f5d3SJohn Marino 	LOOKUP_VAL(ph, "_thread_off_attr_flags",	&ta->thread_off_attr_flags);
157*86d7f5d3SJohn Marino 	LOOKUP_VAL(ph, "_thread_off_event_buf", &ta->thread_off_event_buf);
158*86d7f5d3SJohn Marino 	LOOKUP_VAL(ph, "_thread_off_event_mask", &ta->thread_off_event_mask);
159*86d7f5d3SJohn Marino 	LOOKUP_VAL(ph, "_thread_off_key_allocated", &ta->thread_off_key_allocated);
160*86d7f5d3SJohn Marino 	LOOKUP_VAL(ph, "_thread_off_key_destructor", &ta->thread_off_key_destructor);
161*86d7f5d3SJohn Marino 	LOOKUP_VAL(ph, "_thread_off_next",	&ta->thread_off_next);
162*86d7f5d3SJohn Marino 	LOOKUP_VAL(ph, "_thread_off_report_events", &ta->thread_off_report_events);
163*86d7f5d3SJohn Marino 	LOOKUP_VAL(ph, "_thread_off_state",	&ta->thread_off_state);
164*86d7f5d3SJohn Marino 	LOOKUP_VAL(ph, "_thread_off_tcb",	&ta->thread_off_tcb);
165*86d7f5d3SJohn Marino 	LOOKUP_VAL(ph, "_thread_off_tid",	&ta->thread_off_tid);
166*86d7f5d3SJohn Marino 	LOOKUP_VAL(ph, "_thread_size_key",	&ta->thread_size_key);
167*86d7f5d3SJohn Marino 	LOOKUP_VAL(ph, "_thread_state_running", &ta->thread_state_running);
168*86d7f5d3SJohn Marino 	LOOKUP_VAL(ph, "_thread_state_zoombie", &ta->thread_state_zoombie);
169*86d7f5d3SJohn Marino 
170*86d7f5d3SJohn Marino 	ta->thread_off_linkmap = offsetof(Obj_Entry, linkmap);
171*86d7f5d3SJohn Marino 	ta->thread_off_tlsindex = offsetof(Obj_Entry, tlsindex);
172*86d7f5d3SJohn Marino 	ta->thread_off_dtv = offsetof(struct tls_tcb, tcb_dtv);
173*86d7f5d3SJohn Marino 
174*86d7f5d3SJohn Marino 	dbg = getpid();
175*86d7f5d3SJohn Marino 	/*
176*86d7f5d3SJohn Marino 	 * If this fails it probably means we're debugging a core file and
177*86d7f5d3SJohn Marino 	 * can't write to it.
178*86d7f5d3SJohn Marino 	 */
179*86d7f5d3SJohn Marino 	ps_pwrite(ph, ta->libthread_xu_debug_addr, &dbg, sizeof(int));
180*86d7f5d3SJohn Marino 	*pta = ta;
181*86d7f5d3SJohn Marino 	return (0);
182*86d7f5d3SJohn Marino 
183*86d7f5d3SJohn Marino error:
184*86d7f5d3SJohn Marino 	free(ta);
185*86d7f5d3SJohn Marino 	return (ret);
186*86d7f5d3SJohn Marino }
187*86d7f5d3SJohn Marino 
188*86d7f5d3SJohn Marino static td_err_e
pt_ta_delete(td_thragent_t * ta)189*86d7f5d3SJohn Marino pt_ta_delete(td_thragent_t *ta)
190*86d7f5d3SJohn Marino {
191*86d7f5d3SJohn Marino 	int dbg;
192*86d7f5d3SJohn Marino 
193*86d7f5d3SJohn Marino 	TDBG_FUNC();
194*86d7f5d3SJohn Marino 
195*86d7f5d3SJohn Marino 	dbg = 0;
196*86d7f5d3SJohn Marino 	/*
197*86d7f5d3SJohn Marino 	 * Error returns from this write are not really a problem;
198*86d7f5d3SJohn Marino 	 * the process doesn't exist any more.
199*86d7f5d3SJohn Marino 	 */
200*86d7f5d3SJohn Marino 	ps_pwrite(ta->ph, ta->libthread_xu_debug_addr, &dbg, sizeof(int));
201*86d7f5d3SJohn Marino 	free(ta);
202*86d7f5d3SJohn Marino 	return (TD_OK);
203*86d7f5d3SJohn Marino }
204*86d7f5d3SJohn Marino 
205*86d7f5d3SJohn Marino static td_err_e
pt_ta_map_id2thr(const td_thragent_t * ta,thread_t id,td_thrhandle_t * th)206*86d7f5d3SJohn Marino pt_ta_map_id2thr(const td_thragent_t *ta, thread_t id, td_thrhandle_t *th)
207*86d7f5d3SJohn Marino {
208*86d7f5d3SJohn Marino 	prgregset_t gregs;
209*86d7f5d3SJohn Marino 	TAILQ_HEAD(, pthread) thread_list;
210*86d7f5d3SJohn Marino 	psaddr_t pt;
211*86d7f5d3SJohn Marino 	long lwp;
212*86d7f5d3SJohn Marino 	int ret;
213*86d7f5d3SJohn Marino 
214*86d7f5d3SJohn Marino 	TDBG_FUNC();
215*86d7f5d3SJohn Marino 
216*86d7f5d3SJohn Marino 	if (id == 0)
217*86d7f5d3SJohn Marino 		return (TD_NOTHR);
218*86d7f5d3SJohn Marino 	ret = ps_pread(ta->ph, ta->thread_list_addr, &thread_list,
219*86d7f5d3SJohn Marino 		sizeof(thread_list));
220*86d7f5d3SJohn Marino 	if (ret != 0)
221*86d7f5d3SJohn Marino 		return (P2T(ret));
222*86d7f5d3SJohn Marino 	/* Iterate through thread list to find pthread */
223*86d7f5d3SJohn Marino 	pt = (psaddr_t)thread_list.tqh_first;
224*86d7f5d3SJohn Marino 	while (pt != NULL) {
225*86d7f5d3SJohn Marino 		ret = ps_pread(ta->ph, pt + ta->thread_off_tid,
226*86d7f5d3SJohn Marino 			       &lwp, sizeof(lwp));
227*86d7f5d3SJohn Marino 		if (ret != 0)
228*86d7f5d3SJohn Marino 			return (P2T(ret));
229*86d7f5d3SJohn Marino 		if (lwp == id)
230*86d7f5d3SJohn Marino 			break;
231*86d7f5d3SJohn Marino 		/* get next thread */
232*86d7f5d3SJohn Marino 		ret = ps_pread(ta->ph,
233*86d7f5d3SJohn Marino 				pt + ta->thread_off_next,
234*86d7f5d3SJohn Marino 				&pt, sizeof(pt));
235*86d7f5d3SJohn Marino 		if (ret != 0)
236*86d7f5d3SJohn Marino 			return (P2T(ret));
237*86d7f5d3SJohn Marino 	}
238*86d7f5d3SJohn Marino 	if (pt == NULL)
239*86d7f5d3SJohn Marino 		return (TD_NOTHR);
240*86d7f5d3SJohn Marino 	th->th_ta = ta;
241*86d7f5d3SJohn Marino 	th->th_tid = id;
242*86d7f5d3SJohn Marino 	th->th_thread = pt;
243*86d7f5d3SJohn Marino 	return (TD_OK);
244*86d7f5d3SJohn Marino }
245*86d7f5d3SJohn Marino 
246*86d7f5d3SJohn Marino static td_err_e
pt_ta_map_lwp2thr(const td_thragent_t * ta,lwpid_t lwp,td_thrhandle_t * th)247*86d7f5d3SJohn Marino pt_ta_map_lwp2thr(const td_thragent_t *ta, lwpid_t lwp, td_thrhandle_t *th)
248*86d7f5d3SJohn Marino {
249*86d7f5d3SJohn Marino 	return (pt_ta_map_id2thr(ta, lwp, th));
250*86d7f5d3SJohn Marino }
251*86d7f5d3SJohn Marino 
252*86d7f5d3SJohn Marino 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,int ti_pri,sigset_t * ti_sigmask_p,unsigned int ti_user_flags)253*86d7f5d3SJohn Marino pt_ta_thr_iter(const td_thragent_t *ta,
254*86d7f5d3SJohn Marino                td_thr_iter_f *callback, void *cbdata_p,
255*86d7f5d3SJohn Marino                td_thr_state_e state, int ti_pri,
256*86d7f5d3SJohn Marino                sigset_t *ti_sigmask_p,
257*86d7f5d3SJohn Marino                unsigned int ti_user_flags)
258*86d7f5d3SJohn Marino {
259*86d7f5d3SJohn Marino 	TAILQ_HEAD(, pthread) thread_list;
260*86d7f5d3SJohn Marino 	td_thrhandle_t th;
261*86d7f5d3SJohn Marino 	psaddr_t pt;
262*86d7f5d3SJohn Marino 	long lwp;
263*86d7f5d3SJohn Marino 	int ret;
264*86d7f5d3SJohn Marino 
265*86d7f5d3SJohn Marino 	TDBG_FUNC();
266*86d7f5d3SJohn Marino 
267*86d7f5d3SJohn Marino 	ret = ps_pread(ta->ph, ta->thread_list_addr, &thread_list,
268*86d7f5d3SJohn Marino 		       sizeof(thread_list));
269*86d7f5d3SJohn Marino 	if (ret != 0)
270*86d7f5d3SJohn Marino 		return (P2T(ret));
271*86d7f5d3SJohn Marino 	pt = (psaddr_t)thread_list.tqh_first;
272*86d7f5d3SJohn Marino 	while (pt != 0) {
273*86d7f5d3SJohn Marino 		ret = ps_pread(ta->ph, pt + ta->thread_off_tid, &lwp,
274*86d7f5d3SJohn Marino 			      sizeof(lwp));
275*86d7f5d3SJohn Marino 		if (ret != 0)
276*86d7f5d3SJohn Marino 			return (P2T(ret));
277*86d7f5d3SJohn Marino 		if (lwp != 0 && lwp != TERMINATED) {
278*86d7f5d3SJohn Marino 			th.th_ta = ta;
279*86d7f5d3SJohn Marino 			th.th_tid = (thread_t)lwp;
280*86d7f5d3SJohn Marino 			th.th_thread = pt;
281*86d7f5d3SJohn Marino 			if ((*callback)(&th, cbdata_p))
282*86d7f5d3SJohn Marino 				return (TD_DBERR);
283*86d7f5d3SJohn Marino 		}
284*86d7f5d3SJohn Marino 		/* get next thread */
285*86d7f5d3SJohn Marino 		ret = ps_pread(ta->ph, pt + ta->thread_off_next, &pt,
286*86d7f5d3SJohn Marino 			       sizeof(pt));
287*86d7f5d3SJohn Marino 		if (ret != 0)
288*86d7f5d3SJohn Marino 			return (P2T(ret));
289*86d7f5d3SJohn Marino 	}
290*86d7f5d3SJohn Marino 	return (TD_OK);
291*86d7f5d3SJohn Marino }
292*86d7f5d3SJohn Marino 
293*86d7f5d3SJohn Marino static td_err_e
pt_ta_tsd_iter(const td_thragent_t * ta,td_key_iter_f * ki,void * arg)294*86d7f5d3SJohn Marino pt_ta_tsd_iter(const td_thragent_t *ta, td_key_iter_f *ki, void *arg)
295*86d7f5d3SJohn Marino {
296*86d7f5d3SJohn Marino 	char *keytable;
297*86d7f5d3SJohn Marino 	void *destructor;
298*86d7f5d3SJohn Marino 	int i, ret, allocated;
299*86d7f5d3SJohn Marino 
300*86d7f5d3SJohn Marino 	TDBG_FUNC();
301*86d7f5d3SJohn Marino 
302*86d7f5d3SJohn Marino 	keytable = malloc(ta->thread_max_keys * ta->thread_size_key);
303*86d7f5d3SJohn Marino 	if (keytable == NULL)
304*86d7f5d3SJohn Marino 		return (TD_MALLOC);
305*86d7f5d3SJohn Marino 	ret = ps_pread(ta->ph, (psaddr_t)ta->thread_keytable_addr, keytable,
306*86d7f5d3SJohn Marino 	               ta->thread_max_keys * ta->thread_size_key);
307*86d7f5d3SJohn Marino 	if (ret != 0) {
308*86d7f5d3SJohn Marino 		free(keytable);
309*86d7f5d3SJohn Marino 		return (P2T(ret));
310*86d7f5d3SJohn Marino 	}
311*86d7f5d3SJohn Marino 	for (i = 0; i < ta->thread_max_keys; i++) {
312*86d7f5d3SJohn Marino 		allocated = *(int *)(keytable + i * ta->thread_size_key +
313*86d7f5d3SJohn Marino 			ta->thread_off_key_allocated);
314*86d7f5d3SJohn Marino 		destructor = *(void **)(keytable + i * ta->thread_size_key +
315*86d7f5d3SJohn Marino 			ta->thread_off_key_destructor);
316*86d7f5d3SJohn Marino 		if (allocated) {
317*86d7f5d3SJohn Marino 			ret = (ki)(i, destructor, arg);
318*86d7f5d3SJohn Marino 			if (ret != 0) {
319*86d7f5d3SJohn Marino 				free(keytable);
320*86d7f5d3SJohn Marino 				return (TD_DBERR);
321*86d7f5d3SJohn Marino 			}
322*86d7f5d3SJohn Marino 		}
323*86d7f5d3SJohn Marino 	}
324*86d7f5d3SJohn Marino 	free(keytable);
325*86d7f5d3SJohn Marino 	return (TD_OK);
326*86d7f5d3SJohn Marino }
327*86d7f5d3SJohn Marino 
328*86d7f5d3SJohn Marino static td_err_e
pt_ta_event_addr(const td_thragent_t * ta,td_event_e event,td_notify_t * ptr)329*86d7f5d3SJohn Marino pt_ta_event_addr(const td_thragent_t *ta, td_event_e event, td_notify_t *ptr)
330*86d7f5d3SJohn Marino {
331*86d7f5d3SJohn Marino 
332*86d7f5d3SJohn Marino 	TDBG_FUNC();
333*86d7f5d3SJohn Marino 
334*86d7f5d3SJohn Marino 	switch (event) {
335*86d7f5d3SJohn Marino 	case TD_CREATE:
336*86d7f5d3SJohn Marino 		ptr->type = NOTIFY_BPT;
337*86d7f5d3SJohn Marino 		ptr->u.bptaddr = ta->thread_bp_create_addr;
338*86d7f5d3SJohn Marino 		return (0);
339*86d7f5d3SJohn Marino 	case TD_DEATH:
340*86d7f5d3SJohn Marino 		ptr->type = NOTIFY_BPT;
341*86d7f5d3SJohn Marino 		ptr->u.bptaddr = ta->thread_bp_death_addr;
342*86d7f5d3SJohn Marino 		return (0);
343*86d7f5d3SJohn Marino 	default:
344*86d7f5d3SJohn Marino 		return (TD_ERR);
345*86d7f5d3SJohn Marino 	}
346*86d7f5d3SJohn Marino }
347*86d7f5d3SJohn Marino 
348*86d7f5d3SJohn Marino static td_err_e
pt_ta_set_event(const td_thragent_t * ta,td_thr_events_t * events)349*86d7f5d3SJohn Marino pt_ta_set_event(const td_thragent_t *ta, td_thr_events_t *events)
350*86d7f5d3SJohn Marino {
351*86d7f5d3SJohn Marino 	td_thr_events_t mask;
352*86d7f5d3SJohn Marino 	int ret;
353*86d7f5d3SJohn Marino 
354*86d7f5d3SJohn Marino 	TDBG_FUNC();
355*86d7f5d3SJohn Marino 	ret = ps_pread(ta->ph, ta->thread_event_mask_addr, &mask,
356*86d7f5d3SJohn Marino 		sizeof(mask));
357*86d7f5d3SJohn Marino 	if (ret != 0)
358*86d7f5d3SJohn Marino 		return (P2T(ret));
359*86d7f5d3SJohn Marino 	mask |= *events;
360*86d7f5d3SJohn Marino 	ret = ps_pwrite(ta->ph, ta->thread_event_mask_addr, &mask,
361*86d7f5d3SJohn Marino 		sizeof(mask));
362*86d7f5d3SJohn Marino 	return (P2T(ret));
363*86d7f5d3SJohn Marino }
364*86d7f5d3SJohn Marino 
365*86d7f5d3SJohn Marino static td_err_e
pt_ta_clear_event(const td_thragent_t * ta,td_thr_events_t * events)366*86d7f5d3SJohn Marino pt_ta_clear_event(const td_thragent_t *ta, td_thr_events_t *events)
367*86d7f5d3SJohn Marino {
368*86d7f5d3SJohn Marino 	td_thr_events_t mask;
369*86d7f5d3SJohn Marino 	int ret;
370*86d7f5d3SJohn Marino 
371*86d7f5d3SJohn Marino 	TDBG_FUNC();
372*86d7f5d3SJohn Marino 	ret = ps_pread(ta->ph, ta->thread_event_mask_addr, &mask,
373*86d7f5d3SJohn Marino 		sizeof(mask));
374*86d7f5d3SJohn Marino 	if (ret != 0)
375*86d7f5d3SJohn Marino 		return (P2T(ret));
376*86d7f5d3SJohn Marino 	mask &= ~*events;
377*86d7f5d3SJohn Marino 	ret = ps_pwrite(ta->ph, ta->thread_event_mask_addr, &mask,
378*86d7f5d3SJohn Marino 		sizeof(mask));
379*86d7f5d3SJohn Marino 	return (P2T(ret));
380*86d7f5d3SJohn Marino }
381*86d7f5d3SJohn Marino 
382*86d7f5d3SJohn Marino static td_err_e
pt_ta_event_getmsg(const td_thragent_t * ta,td_event_msg_t * msg)383*86d7f5d3SJohn Marino pt_ta_event_getmsg(const td_thragent_t *ta, td_event_msg_t *msg)
384*86d7f5d3SJohn Marino {
385*86d7f5d3SJohn Marino 	static td_thrhandle_t handle;
386*86d7f5d3SJohn Marino 
387*86d7f5d3SJohn Marino 	psaddr_t pt, pt_temp;
388*86d7f5d3SJohn Marino 	td_thr_events_e	tmp;
389*86d7f5d3SJohn Marino 	long lwp;
390*86d7f5d3SJohn Marino 	int ret;
391*86d7f5d3SJohn Marino 
392*86d7f5d3SJohn Marino 	TDBG_FUNC();
393*86d7f5d3SJohn Marino 
394*86d7f5d3SJohn Marino 	ret = ps_pread(ta->ph, ta->thread_last_event_addr, &pt, sizeof(pt));
395*86d7f5d3SJohn Marino 	if (ret != 0)
396*86d7f5d3SJohn Marino 		return (P2T(ret));
397*86d7f5d3SJohn Marino 	if (pt == NULL)
398*86d7f5d3SJohn Marino 		return (TD_NOMSG);
399*86d7f5d3SJohn Marino 	/*
400*86d7f5d3SJohn Marino 	 * Take the event pointer, at the time, libthr only reports event
401*86d7f5d3SJohn Marino 	 * once a time, so it is not a link list.
402*86d7f5d3SJohn Marino 	 */
403*86d7f5d3SJohn Marino 	pt_temp = NULL;
404*86d7f5d3SJohn Marino 	ps_pwrite(ta->ph, ta->thread_last_event_addr, &pt_temp, sizeof(pt_temp));
405*86d7f5d3SJohn Marino 
406*86d7f5d3SJohn Marino 	/* Read event info */
407*86d7f5d3SJohn Marino 	ret = ps_pread(ta->ph, pt + ta->thread_off_event_buf, msg, sizeof(*msg));
408*86d7f5d3SJohn Marino 	if (ret != 0)
409*86d7f5d3SJohn Marino 		return (P2T(ret));
410*86d7f5d3SJohn Marino 	if (msg->event == 0)
411*86d7f5d3SJohn Marino 		return (TD_NOMSG);
412*86d7f5d3SJohn Marino 	/* Clear event */
413*86d7f5d3SJohn Marino 	tmp = 0;
414*86d7f5d3SJohn Marino 	ps_pwrite(ta->ph, pt + ta->thread_off_event_buf, &tmp, sizeof(tmp));
415*86d7f5d3SJohn Marino 	/* Convert event */
416*86d7f5d3SJohn Marino 	pt = (psaddr_t)msg->th_p;
417*86d7f5d3SJohn Marino 	ret = ps_pread(ta->ph, pt + ta->thread_off_tid, &lwp, sizeof(lwp));
418*86d7f5d3SJohn Marino 	if (ret != 0)
419*86d7f5d3SJohn Marino 		return (P2T(ret));
420*86d7f5d3SJohn Marino 	handle.th_ta = ta;
421*86d7f5d3SJohn Marino 	handle.th_tid = lwp;
422*86d7f5d3SJohn Marino 	handle.th_thread = pt;
423*86d7f5d3SJohn Marino 	msg->th_p = &handle;
424*86d7f5d3SJohn Marino 	return (0);
425*86d7f5d3SJohn Marino }
426*86d7f5d3SJohn Marino 
427*86d7f5d3SJohn Marino static td_err_e
pt_dbsuspend(const td_thrhandle_t * th,int suspend)428*86d7f5d3SJohn Marino pt_dbsuspend(const td_thrhandle_t *th, int suspend)
429*86d7f5d3SJohn Marino {
430*86d7f5d3SJohn Marino 	td_thragent_t *ta = (td_thragent_t *)th->th_ta;
431*86d7f5d3SJohn Marino 	int ret;
432*86d7f5d3SJohn Marino 
433*86d7f5d3SJohn Marino 	TDBG_FUNC();
434*86d7f5d3SJohn Marino 
435*86d7f5d3SJohn Marino 	ret = pt_validate(th);
436*86d7f5d3SJohn Marino 	if (ret)
437*86d7f5d3SJohn Marino 		return (ret);
438*86d7f5d3SJohn Marino 
439*86d7f5d3SJohn Marino 	if (suspend)
440*86d7f5d3SJohn Marino 		ret = ps_lstop(ta->ph, th->th_tid);
441*86d7f5d3SJohn Marino 	else
442*86d7f5d3SJohn Marino 		ret = ps_lcontinue(ta->ph, th->th_tid);
443*86d7f5d3SJohn Marino 	return (P2T(ret));
444*86d7f5d3SJohn Marino }
445*86d7f5d3SJohn Marino 
446*86d7f5d3SJohn Marino static td_err_e
pt_thr_dbresume(const td_thrhandle_t * th)447*86d7f5d3SJohn Marino pt_thr_dbresume(const td_thrhandle_t *th)
448*86d7f5d3SJohn Marino {
449*86d7f5d3SJohn Marino 	TDBG_FUNC();
450*86d7f5d3SJohn Marino 
451*86d7f5d3SJohn Marino 	return pt_dbsuspend(th, 0);
452*86d7f5d3SJohn Marino }
453*86d7f5d3SJohn Marino 
454*86d7f5d3SJohn Marino static td_err_e
pt_thr_dbsuspend(const td_thrhandle_t * th)455*86d7f5d3SJohn Marino pt_thr_dbsuspend(const td_thrhandle_t *th)
456*86d7f5d3SJohn Marino {
457*86d7f5d3SJohn Marino 	TDBG_FUNC();
458*86d7f5d3SJohn Marino 
459*86d7f5d3SJohn Marino 	return pt_dbsuspend(th, 1);
460*86d7f5d3SJohn Marino }
461*86d7f5d3SJohn Marino 
462*86d7f5d3SJohn Marino static td_err_e
pt_thr_validate(const td_thrhandle_t * th)463*86d7f5d3SJohn Marino pt_thr_validate(const td_thrhandle_t *th)
464*86d7f5d3SJohn Marino {
465*86d7f5d3SJohn Marino 	td_thrhandle_t temp;
466*86d7f5d3SJohn Marino 	int ret;
467*86d7f5d3SJohn Marino 
468*86d7f5d3SJohn Marino 	TDBG_FUNC();
469*86d7f5d3SJohn Marino 
470*86d7f5d3SJohn Marino 	ret = pt_ta_map_id2thr(th->th_ta, th->th_tid, &temp);
471*86d7f5d3SJohn Marino 	return (ret);
472*86d7f5d3SJohn Marino }
473*86d7f5d3SJohn Marino 
474*86d7f5d3SJohn Marino static td_err_e
pt_thr_get_info(const td_thrhandle_t * th,td_thrinfo_t * info)475*86d7f5d3SJohn Marino pt_thr_get_info(const td_thrhandle_t *th, td_thrinfo_t *info)
476*86d7f5d3SJohn Marino {
477*86d7f5d3SJohn Marino 	const td_thragent_t *ta = th->th_ta;
478*86d7f5d3SJohn Marino 	int state;
479*86d7f5d3SJohn Marino 	int ret;
480*86d7f5d3SJohn Marino 
481*86d7f5d3SJohn Marino 	TDBG_FUNC();
482*86d7f5d3SJohn Marino 
483*86d7f5d3SJohn Marino 	ret = pt_validate(th);
484*86d7f5d3SJohn Marino 	if (ret)
485*86d7f5d3SJohn Marino 		return (ret);
486*86d7f5d3SJohn Marino 	ret = ps_pread(ta->ph, th->th_thread + ta->thread_off_state,
487*86d7f5d3SJohn Marino 	               &state, sizeof(state));
488*86d7f5d3SJohn Marino 	if (ret != 0)
489*86d7f5d3SJohn Marino 		return (P2T(ret));
490*86d7f5d3SJohn Marino 	ret = ps_pread(ta->ph, th->th_thread + ta->thread_off_report_events,
491*86d7f5d3SJohn Marino 		&info->ti_traceme, sizeof(int));
492*86d7f5d3SJohn Marino 	if (ret != 0)
493*86d7f5d3SJohn Marino 		return (P2T(ret));
494*86d7f5d3SJohn Marino 	ret = ps_pread(ta->ph, th->th_thread + ta->thread_off_event_mask,
495*86d7f5d3SJohn Marino 		&info->ti_events, sizeof(td_thr_events_t));
496*86d7f5d3SJohn Marino 	if (ret != 0)
497*86d7f5d3SJohn Marino 		return (P2T(ret));
498*86d7f5d3SJohn Marino 	ret = ps_pread(ta->ph, th->th_thread + ta->thread_off_tcb,
499*86d7f5d3SJohn Marino 		&info->ti_tls, sizeof(void *));
500*86d7f5d3SJohn Marino 	info->ti_lid = th->th_tid;
501*86d7f5d3SJohn Marino 	info->ti_tid = th->th_tid;
502*86d7f5d3SJohn Marino 	info->ti_thread = th->th_thread;
503*86d7f5d3SJohn Marino 	info->ti_ta_p = th->th_ta;
504*86d7f5d3SJohn Marino 	if (state == ta->thread_state_running)
505*86d7f5d3SJohn Marino 		info->ti_state = TD_THR_RUN;
506*86d7f5d3SJohn Marino 	else if (state == ta->thread_state_zoombie)
507*86d7f5d3SJohn Marino 		info->ti_state = TD_THR_ZOMBIE;
508*86d7f5d3SJohn Marino 	else
509*86d7f5d3SJohn Marino 		info->ti_state = TD_THR_SLEEP;
510*86d7f5d3SJohn Marino 	info->ti_type = TD_THR_USER;
511*86d7f5d3SJohn Marino 	return (0);
512*86d7f5d3SJohn Marino }
513*86d7f5d3SJohn Marino 
514*86d7f5d3SJohn Marino static td_err_e
pt_thr_getfpregs(const td_thrhandle_t * th,prfpregset_t * fpregs)515*86d7f5d3SJohn Marino pt_thr_getfpregs(const td_thrhandle_t *th, prfpregset_t *fpregs)
516*86d7f5d3SJohn Marino {
517*86d7f5d3SJohn Marino 	const td_thragent_t *ta = th->th_ta;
518*86d7f5d3SJohn Marino 	int ret;
519*86d7f5d3SJohn Marino 
520*86d7f5d3SJohn Marino 	TDBG_FUNC();
521*86d7f5d3SJohn Marino 
522*86d7f5d3SJohn Marino 	ret = pt_validate(th);
523*86d7f5d3SJohn Marino 	if (ret)
524*86d7f5d3SJohn Marino 		return (ret);
525*86d7f5d3SJohn Marino 
526*86d7f5d3SJohn Marino 	ret = ps_lgetfpregs(ta->ph, th->th_tid, fpregs);
527*86d7f5d3SJohn Marino 	return (P2T(ret));
528*86d7f5d3SJohn Marino }
529*86d7f5d3SJohn Marino 
530*86d7f5d3SJohn Marino static td_err_e
pt_thr_getgregs(const td_thrhandle_t * th,prgregset_t gregs)531*86d7f5d3SJohn Marino pt_thr_getgregs(const td_thrhandle_t *th, prgregset_t gregs)
532*86d7f5d3SJohn Marino {
533*86d7f5d3SJohn Marino 	const td_thragent_t *ta = th->th_ta;
534*86d7f5d3SJohn Marino 	int ret;
535*86d7f5d3SJohn Marino 
536*86d7f5d3SJohn Marino 	TDBG_FUNC();
537*86d7f5d3SJohn Marino 
538*86d7f5d3SJohn Marino 	ret = pt_validate(th);
539*86d7f5d3SJohn Marino 	if (ret)
540*86d7f5d3SJohn Marino 		return (ret);
541*86d7f5d3SJohn Marino 
542*86d7f5d3SJohn Marino 	ret = ps_lgetregs(ta->ph, th->th_tid, gregs);
543*86d7f5d3SJohn Marino 	return (P2T(ret));
544*86d7f5d3SJohn Marino }
545*86d7f5d3SJohn Marino 
546*86d7f5d3SJohn Marino static td_err_e
pt_thr_setfpregs(const td_thrhandle_t * th,const prfpregset_t * fpregs)547*86d7f5d3SJohn Marino pt_thr_setfpregs(const td_thrhandle_t *th, const prfpregset_t *fpregs)
548*86d7f5d3SJohn Marino {
549*86d7f5d3SJohn Marino 	const td_thragent_t *ta = th->th_ta;
550*86d7f5d3SJohn Marino 	int ret;
551*86d7f5d3SJohn Marino 
552*86d7f5d3SJohn Marino 	TDBG_FUNC();
553*86d7f5d3SJohn Marino 
554*86d7f5d3SJohn Marino 	ret = pt_validate(th);
555*86d7f5d3SJohn Marino 	if (ret)
556*86d7f5d3SJohn Marino 		return (ret);
557*86d7f5d3SJohn Marino 
558*86d7f5d3SJohn Marino 	ret = ps_lsetfpregs(ta->ph, th->th_tid, fpregs);
559*86d7f5d3SJohn Marino 	return (P2T(ret));
560*86d7f5d3SJohn Marino }
561*86d7f5d3SJohn Marino 
562*86d7f5d3SJohn Marino static td_err_e
pt_thr_setgregs(const td_thrhandle_t * th,const prgregset_t gregs)563*86d7f5d3SJohn Marino pt_thr_setgregs(const td_thrhandle_t *th, const prgregset_t gregs)
564*86d7f5d3SJohn Marino {
565*86d7f5d3SJohn Marino 	const td_thragent_t *ta = th->th_ta;
566*86d7f5d3SJohn Marino 	int ret;
567*86d7f5d3SJohn Marino 
568*86d7f5d3SJohn Marino 	TDBG_FUNC();
569*86d7f5d3SJohn Marino 
570*86d7f5d3SJohn Marino 	ret = pt_validate(th);
571*86d7f5d3SJohn Marino 	if (ret)
572*86d7f5d3SJohn Marino 		return (ret);
573*86d7f5d3SJohn Marino 
574*86d7f5d3SJohn Marino 	ret = ps_lsetregs(ta->ph, th->th_tid, gregs);
575*86d7f5d3SJohn Marino 	return (P2T(ret));
576*86d7f5d3SJohn Marino }
577*86d7f5d3SJohn Marino 
578*86d7f5d3SJohn Marino static td_err_e
pt_thr_event_enable(const td_thrhandle_t * th,int en)579*86d7f5d3SJohn Marino pt_thr_event_enable(const td_thrhandle_t *th, int en)
580*86d7f5d3SJohn Marino {
581*86d7f5d3SJohn Marino 	const td_thragent_t *ta = th->th_ta;
582*86d7f5d3SJohn Marino 	int ret;
583*86d7f5d3SJohn Marino 
584*86d7f5d3SJohn Marino 	TDBG_FUNC();
585*86d7f5d3SJohn Marino 	ret = ps_pwrite(ta->ph, th->th_thread + ta->thread_off_report_events,
586*86d7f5d3SJohn Marino 		&en, sizeof(int));
587*86d7f5d3SJohn Marino 	return (P2T(ret));
588*86d7f5d3SJohn Marino }
589*86d7f5d3SJohn Marino 
590*86d7f5d3SJohn Marino static td_err_e
pt_thr_set_event(const td_thrhandle_t * th,td_thr_events_t * setp)591*86d7f5d3SJohn Marino pt_thr_set_event(const td_thrhandle_t *th, td_thr_events_t *setp)
592*86d7f5d3SJohn Marino {
593*86d7f5d3SJohn Marino 	const td_thragent_t *ta = th->th_ta;
594*86d7f5d3SJohn Marino 	td_thr_events_t mask;
595*86d7f5d3SJohn Marino 	int ret;
596*86d7f5d3SJohn Marino 
597*86d7f5d3SJohn Marino 	TDBG_FUNC();
598*86d7f5d3SJohn Marino 	ret = ps_pread(ta->ph, th->th_thread + ta->thread_off_event_mask,
599*86d7f5d3SJohn Marino 			&mask, sizeof(mask));
600*86d7f5d3SJohn Marino 	mask |= *setp;
601*86d7f5d3SJohn Marino 	ret = ps_pwrite(ta->ph, th->th_thread + ta->thread_off_event_mask,
602*86d7f5d3SJohn Marino 			&mask, sizeof(mask));
603*86d7f5d3SJohn Marino 	return (P2T(ret));
604*86d7f5d3SJohn Marino }
605*86d7f5d3SJohn Marino 
606*86d7f5d3SJohn Marino static td_err_e
pt_thr_clear_event(const td_thrhandle_t * th,td_thr_events_t * setp)607*86d7f5d3SJohn Marino pt_thr_clear_event(const td_thrhandle_t *th, td_thr_events_t *setp)
608*86d7f5d3SJohn Marino {
609*86d7f5d3SJohn Marino 	const td_thragent_t *ta = th->th_ta;
610*86d7f5d3SJohn Marino 	td_thr_events_t mask;
611*86d7f5d3SJohn Marino 	int ret;
612*86d7f5d3SJohn Marino 
613*86d7f5d3SJohn Marino 	TDBG_FUNC();
614*86d7f5d3SJohn Marino 	ret = ps_pread(ta->ph, th->th_thread + ta->thread_off_event_mask,
615*86d7f5d3SJohn Marino 			&mask, sizeof(mask));
616*86d7f5d3SJohn Marino 	mask &= ~*setp;
617*86d7f5d3SJohn Marino 	ret = ps_pwrite(ta->ph, th->th_thread + ta->thread_off_event_mask,
618*86d7f5d3SJohn Marino 			&mask, sizeof(mask));
619*86d7f5d3SJohn Marino 	return (P2T(ret));
620*86d7f5d3SJohn Marino }
621*86d7f5d3SJohn Marino 
622*86d7f5d3SJohn Marino static td_err_e
pt_thr_event_getmsg(const td_thrhandle_t * th,td_event_msg_t * msg)623*86d7f5d3SJohn Marino pt_thr_event_getmsg(const td_thrhandle_t *th, td_event_msg_t *msg)
624*86d7f5d3SJohn Marino {
625*86d7f5d3SJohn Marino 	static td_thrhandle_t handle;
626*86d7f5d3SJohn Marino 	td_thragent_t *ta = (td_thragent_t *)th->th_ta;
627*86d7f5d3SJohn Marino 	psaddr_t pt, pt_temp;
628*86d7f5d3SJohn Marino 	long lwp;
629*86d7f5d3SJohn Marino 	int ret;
630*86d7f5d3SJohn Marino 	td_thr_events_e	tmp;
631*86d7f5d3SJohn Marino 
632*86d7f5d3SJohn Marino 	TDBG_FUNC();
633*86d7f5d3SJohn Marino 	pt = th->th_thread;
634*86d7f5d3SJohn Marino 	ret = ps_pread(ta->ph, ta->thread_last_event_addr, &pt_temp, sizeof(pt_temp));
635*86d7f5d3SJohn Marino 	if (ret != 0)
636*86d7f5d3SJohn Marino 		return (P2T(ret));
637*86d7f5d3SJohn Marino 	/* Get event */
638*86d7f5d3SJohn Marino 	ret = ps_pread(ta->ph, pt + ta->thread_off_event_buf, msg, sizeof(*msg));
639*86d7f5d3SJohn Marino 	if (ret != 0)
640*86d7f5d3SJohn Marino 		return (P2T(ret));
641*86d7f5d3SJohn Marino 	if (msg->event == 0)
642*86d7f5d3SJohn Marino 		return (TD_NOMSG);
643*86d7f5d3SJohn Marino 	/*
644*86d7f5d3SJohn Marino 	 * Take the event pointer, at the time, libthr only reports event
645*86d7f5d3SJohn Marino 	 * once a time, so it is not a link list.
646*86d7f5d3SJohn Marino 	 */
647*86d7f5d3SJohn Marino 	if (pt == pt_temp) {
648*86d7f5d3SJohn Marino 		pt_temp = NULL;
649*86d7f5d3SJohn Marino 		ps_pwrite(ta->ph, ta->thread_last_event_addr, &pt_temp, sizeof(pt_temp));
650*86d7f5d3SJohn Marino 	}
651*86d7f5d3SJohn Marino 	/* Clear event */
652*86d7f5d3SJohn Marino 	tmp = 0;
653*86d7f5d3SJohn Marino 	ps_pwrite(ta->ph, pt + ta->thread_off_event_buf, &tmp, sizeof(tmp));
654*86d7f5d3SJohn Marino 	/* Convert event */
655*86d7f5d3SJohn Marino 	pt = (psaddr_t)msg->th_p;
656*86d7f5d3SJohn Marino 	ret = ps_pread(ta->ph, pt + ta->thread_off_tid, &lwp, sizeof(lwp));
657*86d7f5d3SJohn Marino 	if (ret != 0)
658*86d7f5d3SJohn Marino 		return (P2T(ret));
659*86d7f5d3SJohn Marino 	handle.th_ta = ta;
660*86d7f5d3SJohn Marino 	handle.th_tid = lwp;
661*86d7f5d3SJohn Marino 	handle.th_thread = pt;
662*86d7f5d3SJohn Marino 	msg->th_p = &handle;
663*86d7f5d3SJohn Marino 	return (0);
664*86d7f5d3SJohn Marino }
665*86d7f5d3SJohn Marino 
666*86d7f5d3SJohn Marino static int
pt_validate(const td_thrhandle_t * th)667*86d7f5d3SJohn Marino pt_validate(const td_thrhandle_t *th)
668*86d7f5d3SJohn Marino {
669*86d7f5d3SJohn Marino 
670*86d7f5d3SJohn Marino 	if (th->th_tid == 0 || th->th_thread == NULL)
671*86d7f5d3SJohn Marino 		return (TD_ERR);
672*86d7f5d3SJohn Marino 	return (TD_OK);
673*86d7f5d3SJohn Marino }
674*86d7f5d3SJohn Marino 
675*86d7f5d3SJohn Marino static td_err_e
pt_thr_tls_get_addr(const td_thrhandle_t * th,void * _linkmap,size_t offset,void ** address)676*86d7f5d3SJohn Marino pt_thr_tls_get_addr(const td_thrhandle_t *th, void *_linkmap, size_t offset,
677*86d7f5d3SJohn Marino 		    void **address)
678*86d7f5d3SJohn Marino {
679*86d7f5d3SJohn Marino 	char *obj_entry;
680*86d7f5d3SJohn Marino 	const td_thragent_t *ta = th->th_ta;
681*86d7f5d3SJohn Marino 	psaddr_t tcb_addr, *dtv_addr, tcb_tp;
682*86d7f5d3SJohn Marino 	int tls_index, ret;
683*86d7f5d3SJohn Marino 
684*86d7f5d3SJohn Marino 	/* linkmap is a member of Obj_Entry */
685*86d7f5d3SJohn Marino 	obj_entry = (char *)_linkmap - ta->thread_off_linkmap;
686*86d7f5d3SJohn Marino 
687*86d7f5d3SJohn Marino 	/* get tlsindex of the object file */
688*86d7f5d3SJohn Marino 	ret = ps_pread(ta->ph,
689*86d7f5d3SJohn Marino 		obj_entry + ta->thread_off_tlsindex,
690*86d7f5d3SJohn Marino 		&tls_index, sizeof(tls_index));
691*86d7f5d3SJohn Marino 	if (ret != 0)
692*86d7f5d3SJohn Marino 		return (P2T(ret));
693*86d7f5d3SJohn Marino 
694*86d7f5d3SJohn Marino 	/* get thread tcb */
695*86d7f5d3SJohn Marino 	ret = ps_pread(ta->ph, th->th_thread + ta->thread_off_tcb,
696*86d7f5d3SJohn Marino 		&tcb_addr, sizeof(tcb_addr));
697*86d7f5d3SJohn Marino 	if (ret != 0)
698*86d7f5d3SJohn Marino 		return (P2T(ret));
699*86d7f5d3SJohn Marino 
700*86d7f5d3SJohn Marino 	/* get dtv array address */
701*86d7f5d3SJohn Marino 	ret = ps_pread(ta->ph, tcb_addr + ta->thread_off_dtv,
702*86d7f5d3SJohn Marino 		&dtv_addr, sizeof(dtv_addr));
703*86d7f5d3SJohn Marino 	if (ret != 0)
704*86d7f5d3SJohn Marino 		return (P2T(ret));
705*86d7f5d3SJohn Marino 	/* now get the object's tls block base address */
706*86d7f5d3SJohn Marino 	ret = ps_pread(ta->ph, &dtv_addr[tls_index+1], address,
707*86d7f5d3SJohn Marino 		sizeof(*address));
708*86d7f5d3SJohn Marino 	if (ret != 0)
709*86d7f5d3SJohn Marino 		return (P2T(ret));
710*86d7f5d3SJohn Marino 
711*86d7f5d3SJohn Marino 	*address += offset;
712*86d7f5d3SJohn Marino 	return (TD_OK);
713*86d7f5d3SJohn Marino }
714*86d7f5d3SJohn Marino 
715*86d7f5d3SJohn Marino struct ta_ops libthread_xu_ops = {
716*86d7f5d3SJohn Marino 	.to_init		= pt_init,
717*86d7f5d3SJohn Marino 	.to_ta_clear_event	= pt_ta_clear_event,
718*86d7f5d3SJohn Marino 	.to_ta_delete		= pt_ta_delete,
719*86d7f5d3SJohn Marino 	.to_ta_event_addr	= pt_ta_event_addr,
720*86d7f5d3SJohn Marino 	.to_ta_event_getmsg	= pt_ta_event_getmsg,
721*86d7f5d3SJohn Marino 	.to_ta_map_id2thr	= pt_ta_map_id2thr,
722*86d7f5d3SJohn Marino 	.to_ta_map_lwp2thr	= pt_ta_map_lwp2thr,
723*86d7f5d3SJohn Marino 	.to_ta_new		= pt_ta_new,
724*86d7f5d3SJohn Marino 	.to_ta_set_event	= pt_ta_set_event,
725*86d7f5d3SJohn Marino 	.to_ta_thr_iter		= pt_ta_thr_iter,
726*86d7f5d3SJohn Marino 	.to_ta_tsd_iter		= pt_ta_tsd_iter,
727*86d7f5d3SJohn Marino 	.to_thr_clear_event	= pt_thr_clear_event,
728*86d7f5d3SJohn Marino 	.to_thr_dbresume	= pt_thr_dbresume,
729*86d7f5d3SJohn Marino 	.to_thr_dbsuspend	= pt_thr_dbsuspend,
730*86d7f5d3SJohn Marino 	.to_thr_event_enable	= pt_thr_event_enable,
731*86d7f5d3SJohn Marino 	.to_thr_event_getmsg	= pt_thr_event_getmsg,
732*86d7f5d3SJohn Marino 	.to_thr_get_info	= pt_thr_get_info,
733*86d7f5d3SJohn Marino 	.to_thr_getfpregs	= pt_thr_getfpregs,
734*86d7f5d3SJohn Marino 	.to_thr_getgregs	= pt_thr_getgregs,
735*86d7f5d3SJohn Marino 	.to_thr_set_event	= pt_thr_set_event,
736*86d7f5d3SJohn Marino 	.to_thr_setfpregs	= pt_thr_setfpregs,
737*86d7f5d3SJohn Marino 	.to_thr_setgregs	= pt_thr_setgregs,
738*86d7f5d3SJohn Marino 	.to_thr_validate	= pt_thr_validate,
739*86d7f5d3SJohn Marino 	.to_thr_tls_get_addr	= pt_thr_tls_get_addr,
740*86d7f5d3SJohn Marino };
741