xref: /freebsd-src/lib/libthread_db/libthr_db.c (revision 1d386b48a555f61cb7325543adbbb5c3f3407a66)
15e53a4f9SPedro F. Giffuni /*-
2*4d846d26SWarner Losh  * SPDX-License-Identifier: BSD-2-Clause
35e53a4f9SPedro F. Giffuni  *
43c1e38eaSMarcel Moolenaar  * Copyright (c) 2004 Marcel Moolenaar
5e65421baSDavid Xu  * Copyright (c) 2005 David Xu
63c1e38eaSMarcel Moolenaar  * All rights reserved.
73c1e38eaSMarcel Moolenaar  *
83c1e38eaSMarcel Moolenaar  * Redistribution and use in source and binary forms, with or without
93c1e38eaSMarcel Moolenaar  * modification, are permitted provided that the following conditions
103c1e38eaSMarcel Moolenaar  * are met:
113c1e38eaSMarcel Moolenaar  *
123c1e38eaSMarcel Moolenaar  * 1. Redistributions of source code must retain the above copyright
133c1e38eaSMarcel Moolenaar  *    notice, this list of conditions and the following disclaimer.
143c1e38eaSMarcel Moolenaar  * 2. Redistributions in binary form must reproduce the above copyright
153c1e38eaSMarcel Moolenaar  *    notice, this list of conditions and the following disclaimer in the
163c1e38eaSMarcel Moolenaar  *    documentation and/or other materials provided with the distribution.
173c1e38eaSMarcel Moolenaar  *
183c1e38eaSMarcel Moolenaar  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
193c1e38eaSMarcel Moolenaar  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
203c1e38eaSMarcel Moolenaar  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
213c1e38eaSMarcel Moolenaar  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
223c1e38eaSMarcel Moolenaar  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
233c1e38eaSMarcel Moolenaar  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
243c1e38eaSMarcel Moolenaar  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
253c1e38eaSMarcel Moolenaar  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
263c1e38eaSMarcel Moolenaar  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
273c1e38eaSMarcel Moolenaar  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
283c1e38eaSMarcel Moolenaar  */
293c1e38eaSMarcel Moolenaar 
303c1e38eaSMarcel Moolenaar #include <sys/cdefs.h>
313c1e38eaSMarcel Moolenaar #include <proc_service.h>
32e65421baSDavid Xu #include <stddef.h>
333c1e38eaSMarcel Moolenaar #include <stdlib.h>
34e65421baSDavid Xu #include <string.h>
35e65421baSDavid Xu #include <sys/types.h>
3620b94d80SDavid Xu #include <sys/linker_set.h>
37e65421baSDavid Xu #include <sys/ptrace.h>
383c1e38eaSMarcel Moolenaar #include <thread_db.h>
39e65421baSDavid Xu #include <unistd.h>
403c1e38eaSMarcel Moolenaar 
413c1e38eaSMarcel Moolenaar #include "thread_db_int.h"
423c1e38eaSMarcel Moolenaar 
43a80845eaSDavid Xu #define	TERMINATED	1
44a80845eaSDavid Xu 
45e65421baSDavid Xu struct td_thragent {
46e65421baSDavid Xu 	TD_THRAGENT_FIELDS;
47e65421baSDavid Xu 	psaddr_t	libthr_debug_addr;
48e65421baSDavid Xu 	psaddr_t	thread_list_addr;
49e65421baSDavid Xu 	psaddr_t	thread_active_threads_addr;
50e65421baSDavid Xu 	psaddr_t	thread_keytable_addr;
51a80845eaSDavid Xu 	psaddr_t	thread_last_event_addr;
52a80845eaSDavid Xu 	psaddr_t	thread_event_mask_addr;
53a80845eaSDavid Xu 	psaddr_t	thread_bp_create_addr;
54a80845eaSDavid Xu 	psaddr_t	thread_bp_death_addr;
55e65421baSDavid Xu 	int		thread_off_dtv;
56e65421baSDavid Xu 	int		thread_off_tlsindex;
57e65421baSDavid Xu 	int		thread_off_attr_flags;
58e65421baSDavid Xu 	int		thread_size_key;
59e65421baSDavid Xu 	int		thread_off_tcb;
60e65421baSDavid Xu 	int		thread_off_linkmap;
61e65421baSDavid Xu 	int		thread_off_next;
62e65421baSDavid Xu 	int		thread_off_state;
63e65421baSDavid Xu 	int		thread_off_tid;
64e65421baSDavid Xu 	int		thread_max_keys;
65e65421baSDavid Xu 	int		thread_off_key_allocated;
66e65421baSDavid Xu 	int		thread_off_key_destructor;
67a80845eaSDavid Xu 	int		thread_off_report_events;
68a80845eaSDavid Xu 	int		thread_off_event_mask;
69a80845eaSDavid Xu 	int		thread_off_event_buf;
70e65421baSDavid Xu 	int		thread_state_zoombie;
71e65421baSDavid Xu 	int		thread_state_running;
72e65421baSDavid Xu };
73e65421baSDavid Xu 
74e65421baSDavid Xu #define P2T(c) ps2td(c)
75e65421baSDavid Xu 
76e65421baSDavid Xu static int pt_validate(const td_thrhandle_t *th);
77e65421baSDavid Xu 
78e65421baSDavid Xu static int
ps2td(int c)79e65421baSDavid Xu ps2td(int c)
803c1e38eaSMarcel Moolenaar {
81e65421baSDavid Xu 	switch (c) {
82e65421baSDavid Xu 	case PS_OK:
83e65421baSDavid Xu 		return TD_OK;
84e65421baSDavid Xu 	case PS_ERR:
85e65421baSDavid Xu 		return TD_ERR;
86e65421baSDavid Xu 	case PS_BADPID:
87e65421baSDavid Xu 		return TD_BADPH;
88e65421baSDavid Xu 	case PS_BADLID:
89e65421baSDavid Xu 		return TD_NOLWP;
90e65421baSDavid Xu 	case PS_BADADDR:
91e65421baSDavid Xu 		return TD_ERR;
92e65421baSDavid Xu 	case PS_NOSYM:
93e65421baSDavid Xu 		return TD_NOLIBTHREAD;
94e65421baSDavid Xu 	case PS_NOFREGS:
95e65421baSDavid Xu 		return TD_NOFPREGS;
96e65421baSDavid Xu 	default:
97e65421baSDavid Xu 		return TD_ERR;
98e65421baSDavid Xu 	}
99e65421baSDavid Xu }
100e65421baSDavid Xu 
1013c1e38eaSMarcel Moolenaar static td_err_e
pt_init(void)102e65421baSDavid Xu pt_init(void)
1033c1e38eaSMarcel Moolenaar {
104e65421baSDavid Xu 	return (0);
1053c1e38eaSMarcel Moolenaar }
1063c1e38eaSMarcel Moolenaar 
1073c1e38eaSMarcel Moolenaar static td_err_e
pt_ta_new(struct ps_prochandle * ph,td_thragent_t ** pta)108e65421baSDavid Xu pt_ta_new(struct ps_prochandle *ph, td_thragent_t **pta)
1093c1e38eaSMarcel Moolenaar {
110e65421baSDavid Xu #define LOOKUP_SYM(proc, sym, addr) 			\
111e65421baSDavid Xu 	ret = ps_pglobal_lookup(proc, NULL, sym, addr);	\
112e65421baSDavid Xu 	if (ret != 0) {					\
113e65421baSDavid Xu 		TDBG("can not find symbol: %s\n", sym);	\
114e65421baSDavid Xu 		ret = TD_NOLIBTHREAD;			\
115e65421baSDavid Xu 		goto error;				\
1163c1e38eaSMarcel Moolenaar 	}
1173c1e38eaSMarcel Moolenaar 
118e65421baSDavid Xu #define	LOOKUP_VAL(proc, sym, val)			\
119e65421baSDavid Xu 	ret = ps_pglobal_lookup(proc, NULL, sym, &vaddr);\
120e65421baSDavid Xu 	if (ret != 0) {					\
121e65421baSDavid Xu 		TDBG("can not find symbol: %s\n", sym);	\
122e65421baSDavid Xu 		ret = TD_NOLIBTHREAD;			\
123e65421baSDavid Xu 		goto error;				\
124e65421baSDavid Xu 	}						\
125e65421baSDavid Xu 	ret = ps_pread(proc, vaddr, val, sizeof(int));	\
126e65421baSDavid Xu 	if (ret != 0) {					\
127e65421baSDavid Xu 		TDBG("can not read value of %s\n", sym);\
128e65421baSDavid Xu 		ret = TD_NOLIBTHREAD;			\
129e65421baSDavid Xu 		goto error;				\
1303c1e38eaSMarcel Moolenaar 	}
1313c1e38eaSMarcel Moolenaar 
1323c1e38eaSMarcel Moolenaar 	td_thragent_t *ta;
133e65421baSDavid Xu 	psaddr_t vaddr;
134e65421baSDavid Xu 	int dbg;
135e65421baSDavid Xu 	int ret;
1363c1e38eaSMarcel Moolenaar 
137e65421baSDavid Xu 	TDBG_FUNC();
1383c1e38eaSMarcel Moolenaar 
1393c1e38eaSMarcel Moolenaar 	ta = malloc(sizeof(td_thragent_t));
1403c1e38eaSMarcel Moolenaar 	if (ta == NULL)
1413c1e38eaSMarcel Moolenaar 		return (TD_MALLOC);
1423c1e38eaSMarcel Moolenaar 
143e65421baSDavid Xu 	ta->ph = ph;
1443c1e38eaSMarcel Moolenaar 
145e65421baSDavid Xu 	LOOKUP_SYM(ph, "_libthr_debug",		&ta->libthr_debug_addr);
146e65421baSDavid Xu 	LOOKUP_SYM(ph, "_thread_list",		&ta->thread_list_addr);
147e65421baSDavid Xu 	LOOKUP_SYM(ph, "_thread_active_threads",&ta->thread_active_threads_addr);
148e65421baSDavid Xu 	LOOKUP_SYM(ph, "_thread_keytable",	&ta->thread_keytable_addr);
149a80845eaSDavid Xu 	LOOKUP_SYM(ph, "_thread_last_event",	&ta->thread_last_event_addr);
150a80845eaSDavid Xu 	LOOKUP_SYM(ph, "_thread_event_mask",	&ta->thread_event_mask_addr);
151a80845eaSDavid Xu 	LOOKUP_SYM(ph, "_thread_bp_create",	&ta->thread_bp_create_addr);
152a80845eaSDavid Xu 	LOOKUP_SYM(ph, "_thread_bp_death",	&ta->thread_bp_death_addr);
153e65421baSDavid Xu 	LOOKUP_VAL(ph, "_thread_off_dtv",	&ta->thread_off_dtv);
154e65421baSDavid Xu 	LOOKUP_VAL(ph, "_thread_off_tlsindex",	&ta->thread_off_tlsindex);
155e65421baSDavid Xu 	LOOKUP_VAL(ph, "_thread_off_attr_flags",	&ta->thread_off_attr_flags);
156e65421baSDavid Xu 	LOOKUP_VAL(ph, "_thread_size_key",	&ta->thread_size_key);
157e65421baSDavid Xu 	LOOKUP_VAL(ph, "_thread_off_tcb",	&ta->thread_off_tcb);
158e65421baSDavid Xu 	LOOKUP_VAL(ph, "_thread_off_tid",	&ta->thread_off_tid);
159e65421baSDavid Xu 	LOOKUP_VAL(ph, "_thread_off_linkmap",	&ta->thread_off_linkmap);
160e65421baSDavid Xu 	LOOKUP_VAL(ph, "_thread_off_next",	&ta->thread_off_next);
161e65421baSDavid Xu 	LOOKUP_VAL(ph, "_thread_off_state",	&ta->thread_off_state);
162e65421baSDavid Xu 	LOOKUP_VAL(ph, "_thread_max_keys",	&ta->thread_max_keys);
163e65421baSDavid Xu 	LOOKUP_VAL(ph, "_thread_off_key_allocated", &ta->thread_off_key_allocated);
164e65421baSDavid Xu 	LOOKUP_VAL(ph, "_thread_off_key_destructor", &ta->thread_off_key_destructor);
165e65421baSDavid Xu 	LOOKUP_VAL(ph, "_thread_state_running", &ta->thread_state_running);
166e65421baSDavid Xu 	LOOKUP_VAL(ph, "_thread_state_zoombie", &ta->thread_state_zoombie);
167a80845eaSDavid Xu 	LOOKUP_VAL(ph, "_thread_off_report_events", &ta->thread_off_report_events);
168a80845eaSDavid Xu 	LOOKUP_VAL(ph, "_thread_off_event_mask", &ta->thread_off_event_mask);
169a80845eaSDavid Xu 	LOOKUP_VAL(ph, "_thread_off_event_buf", &ta->thread_off_event_buf);
170e65421baSDavid Xu 	dbg = getpid();
171e65421baSDavid Xu 	/*
172e65421baSDavid Xu 	 * If this fails it probably means we're debugging a core file and
173e65421baSDavid Xu 	 * can't write to it.
174e65421baSDavid Xu 	 */
175e65421baSDavid Xu 	ps_pwrite(ph, ta->libthr_debug_addr, &dbg, sizeof(int));
176e65421baSDavid Xu 	*pta = ta;
177e65421baSDavid Xu 	return (0);
1783c1e38eaSMarcel Moolenaar 
179e65421baSDavid Xu error:
1803c1e38eaSMarcel Moolenaar 	free(ta);
181e65421baSDavid Xu 	return (ret);
1823c1e38eaSMarcel Moolenaar }
1833c1e38eaSMarcel Moolenaar 
1843c1e38eaSMarcel Moolenaar static td_err_e
pt_ta_delete(td_thragent_t * ta)185e65421baSDavid Xu pt_ta_delete(td_thragent_t *ta)
1863c1e38eaSMarcel Moolenaar {
187e65421baSDavid Xu 	int dbg;
188e65421baSDavid Xu 
189e65421baSDavid Xu 	TDBG_FUNC();
190e65421baSDavid Xu 
191e65421baSDavid Xu 	dbg = 0;
192e65421baSDavid Xu 	/*
193e65421baSDavid Xu 	 * Error returns from this write are not really a problem;
194e65421baSDavid Xu 	 * the process doesn't exist any more.
195e65421baSDavid Xu 	 */
196e65421baSDavid Xu 	ps_pwrite(ta->ph, ta->libthr_debug_addr, &dbg, sizeof(int));
197e65421baSDavid Xu 	free(ta);
198e65421baSDavid Xu 	return (TD_OK);
1993c1e38eaSMarcel Moolenaar }
2003c1e38eaSMarcel Moolenaar 
2013c1e38eaSMarcel Moolenaar static td_err_e
pt_ta_map_id2thr(const td_thragent_t * ta,thread_t id,td_thrhandle_t * th)202e65421baSDavid Xu pt_ta_map_id2thr(const td_thragent_t *ta, thread_t id, td_thrhandle_t *th)
2033c1e38eaSMarcel Moolenaar {
204e65421baSDavid Xu 	psaddr_t pt;
205ef6f47c4SMarius Strobl 	int64_t lwp;
206787e88a3SDavid Xu 	int ret;
207e65421baSDavid Xu 
208e65421baSDavid Xu 	TDBG_FUNC();
209e65421baSDavid Xu 
210787e88a3SDavid Xu 	if (id == 0)
211e65421baSDavid Xu 		return (TD_NOTHR);
21203fad2adSMarcel Moolenaar 	ret = thr_pread_ptr(ta, ta->thread_list_addr, &pt);
213e65421baSDavid Xu 	if (ret != 0)
21403fad2adSMarcel Moolenaar 		return (TD_ERR);
215787e88a3SDavid Xu 	/* Iterate through thread list to find pthread */
21616b0c20cSMarcel Moolenaar 	while (pt != 0) {
217e31fe879SMarius Strobl 		ret = thr_pread_long(ta, pt + ta->thread_off_tid, &lwp);
218787e88a3SDavid Xu 		if (ret != 0)
21903fad2adSMarcel Moolenaar 			return (TD_ERR);
220787e88a3SDavid Xu 		if (lwp == id)
221787e88a3SDavid Xu 			break;
222e65421baSDavid Xu 		/* get next thread */
22303fad2adSMarcel Moolenaar 		ret = thr_pread_ptr(ta, pt + ta->thread_off_next, &pt);
224e65421baSDavid Xu 		if (ret != 0)
22503fad2adSMarcel Moolenaar 			return (TD_ERR);
226e65421baSDavid Xu 	}
22716b0c20cSMarcel Moolenaar 	if (pt == 0)
228e65421baSDavid Xu 		return (TD_NOTHR);
229e65421baSDavid Xu 	th->th_ta = ta;
230e65421baSDavid Xu 	th->th_tid = id;
2312ec2da86SDavid Xu 	th->th_thread = pt;
232e65421baSDavid Xu 	return (TD_OK);
233e65421baSDavid Xu }
234e65421baSDavid Xu 
235e65421baSDavid Xu static td_err_e
pt_ta_map_lwp2thr(const td_thragent_t * ta,lwpid_t lwp,td_thrhandle_t * th)236e65421baSDavid Xu pt_ta_map_lwp2thr(const td_thragent_t *ta, lwpid_t lwp, td_thrhandle_t *th)
237e65421baSDavid Xu {
238787e88a3SDavid Xu 	return (pt_ta_map_id2thr(ta, lwp, th));
239e65421baSDavid Xu }
240e65421baSDavid Xu 
241e65421baSDavid Xu 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)242f60a5b31SMarcel Moolenaar pt_ta_thr_iter(const td_thragent_t *ta, td_thr_iter_f *callback,
243f60a5b31SMarcel Moolenaar     void *cbdata_p, td_thr_state_e state __unused, int ti_pri __unused,
244f60a5b31SMarcel Moolenaar     sigset_t *ti_sigmask_p __unused, unsigned int ti_user_flags __unused)
245e65421baSDavid Xu {
2463c1e38eaSMarcel Moolenaar 	td_thrhandle_t th;
247e65421baSDavid Xu 	psaddr_t pt;
248ef6f47c4SMarius Strobl 	int64_t lwp;
249787e88a3SDavid Xu 	int ret;
2503c1e38eaSMarcel Moolenaar 
251e65421baSDavid Xu 	TDBG_FUNC();
252e65421baSDavid Xu 
25303fad2adSMarcel Moolenaar 	ret = thr_pread_ptr(ta, ta->thread_list_addr, &pt);
254e65421baSDavid Xu 	if (ret != 0)
25503fad2adSMarcel Moolenaar 		return (TD_ERR);
256e65421baSDavid Xu 	while (pt != 0) {
257e31fe879SMarius Strobl 		ret = thr_pread_long(ta, pt + ta->thread_off_tid, &lwp);
258e65421baSDavid Xu 		if (ret != 0)
25903fad2adSMarcel Moolenaar 			return (TD_ERR);
260787e88a3SDavid Xu 		if (lwp != 0 && lwp != TERMINATED) {
2613c1e38eaSMarcel Moolenaar 			th.th_ta = ta;
262787e88a3SDavid Xu 			th.th_tid = (thread_t)lwp;
2632ec2da86SDavid Xu 			th.th_thread = pt;
264e65421baSDavid Xu 			if ((*callback)(&th, cbdata_p))
265e65421baSDavid Xu 				return (TD_DBERR);
266e65421baSDavid Xu 		}
267e65421baSDavid Xu 		/* get next thread */
26803fad2adSMarcel Moolenaar 		ret = thr_pread_ptr(ta, pt + ta->thread_off_next, &pt);
269e65421baSDavid Xu 		if (ret != 0)
27003fad2adSMarcel Moolenaar 			return (TD_ERR);
2713c1e38eaSMarcel Moolenaar 	}
2723c1e38eaSMarcel Moolenaar 	return (TD_OK);
2733c1e38eaSMarcel Moolenaar }
2743c1e38eaSMarcel Moolenaar 
2753c1e38eaSMarcel Moolenaar static td_err_e
pt_ta_tsd_iter(const td_thragent_t * ta,td_key_iter_f * ki,void * arg)276e65421baSDavid Xu pt_ta_tsd_iter(const td_thragent_t *ta, td_key_iter_f *ki, void *arg)
2773c1e38eaSMarcel Moolenaar {
278f60a5b31SMarcel Moolenaar 	void *keytable;
279e65421baSDavid Xu 	void *destructor;
280e65421baSDavid Xu 	int i, ret, allocated;
281e65421baSDavid Xu 
282e65421baSDavid Xu 	TDBG_FUNC();
283e65421baSDavid Xu 
284e65421baSDavid Xu 	keytable = malloc(ta->thread_max_keys * ta->thread_size_key);
285e65421baSDavid Xu 	if (keytable == NULL)
286e65421baSDavid Xu 		return (TD_MALLOC);
287e65421baSDavid Xu 	ret = ps_pread(ta->ph, (psaddr_t)ta->thread_keytable_addr, keytable,
288e65421baSDavid Xu 	               ta->thread_max_keys * ta->thread_size_key);
289e65421baSDavid Xu 	if (ret != 0) {
290e65421baSDavid Xu 		free(keytable);
291e65421baSDavid Xu 		return (P2T(ret));
292e65421baSDavid Xu 	}
293e65421baSDavid Xu 	for (i = 0; i < ta->thread_max_keys; i++) {
294f60a5b31SMarcel Moolenaar 		allocated = *(int *)(void *)((uintptr_t)keytable +
295f60a5b31SMarcel Moolenaar 		    i * ta->thread_size_key + ta->thread_off_key_allocated);
296f60a5b31SMarcel Moolenaar 		destructor = *(void **)(void *)((uintptr_t)keytable +
297f60a5b31SMarcel Moolenaar 		    i * ta->thread_size_key + ta->thread_off_key_destructor);
298e65421baSDavid Xu 		if (allocated) {
299e65421baSDavid Xu 			ret = (ki)(i, destructor, arg);
300e65421baSDavid Xu 			if (ret != 0) {
301e65421baSDavid Xu 				free(keytable);
302e65421baSDavid Xu 				return (TD_DBERR);
303e65421baSDavid Xu 			}
304e65421baSDavid Xu 		}
305e65421baSDavid Xu 	}
306e65421baSDavid Xu 	free(keytable);
307e65421baSDavid Xu 	return (TD_OK);
308e65421baSDavid Xu }
309e65421baSDavid Xu 
310e65421baSDavid Xu static td_err_e
pt_ta_event_addr(const td_thragent_t * ta,td_event_e event,td_notify_t * ptr)311e65421baSDavid Xu pt_ta_event_addr(const td_thragent_t *ta, td_event_e event, td_notify_t *ptr)
312e65421baSDavid Xu {
313787e88a3SDavid Xu 
314e65421baSDavid Xu 	TDBG_FUNC();
315a80845eaSDavid Xu 
316a80845eaSDavid Xu 	switch (event) {
317a80845eaSDavid Xu 	case TD_CREATE:
318a80845eaSDavid Xu 		ptr->type = NOTIFY_BPT;
319a80845eaSDavid Xu 		ptr->u.bptaddr = ta->thread_bp_create_addr;
320a80845eaSDavid Xu 		return (0);
321a80845eaSDavid Xu 	case TD_DEATH:
322a80845eaSDavid Xu 		ptr->type = NOTIFY_BPT;
323a80845eaSDavid Xu 		ptr->u.bptaddr = ta->thread_bp_death_addr;
324a80845eaSDavid Xu 		return (0);
325a80845eaSDavid Xu 	default:
326a80845eaSDavid Xu 		return (TD_ERR);
327a80845eaSDavid Xu 	}
328e65421baSDavid Xu }
329e65421baSDavid Xu 
330e65421baSDavid Xu static td_err_e
pt_ta_set_event(const td_thragent_t * ta,td_thr_events_t * events)331e65421baSDavid Xu pt_ta_set_event(const td_thragent_t *ta, td_thr_events_t *events)
332e65421baSDavid Xu {
333a80845eaSDavid Xu 	td_thr_events_t mask;
334787e88a3SDavid Xu 	int ret;
335a80845eaSDavid Xu 
336e65421baSDavid Xu 	TDBG_FUNC();
337a80845eaSDavid Xu 	ret = ps_pread(ta->ph, ta->thread_event_mask_addr, &mask,
338a80845eaSDavid Xu 		sizeof(mask));
339a80845eaSDavid Xu 	if (ret != 0)
340a80845eaSDavid Xu 		return (P2T(ret));
341a80845eaSDavid Xu 	mask |= *events;
342a80845eaSDavid Xu 	ret = ps_pwrite(ta->ph, ta->thread_event_mask_addr, &mask,
343a80845eaSDavid Xu 		sizeof(mask));
344a80845eaSDavid Xu 	return (P2T(ret));
3453c1e38eaSMarcel Moolenaar }
3463c1e38eaSMarcel Moolenaar 
3473c1e38eaSMarcel Moolenaar static td_err_e
pt_ta_clear_event(const td_thragent_t * ta,td_thr_events_t * events)348e65421baSDavid Xu pt_ta_clear_event(const td_thragent_t *ta, td_thr_events_t *events)
349d4ee7126SDavid Xu {
350a80845eaSDavid Xu 	td_thr_events_t mask;
351787e88a3SDavid Xu 	int ret;
352a80845eaSDavid Xu 
353e65421baSDavid Xu 	TDBG_FUNC();
354a80845eaSDavid Xu 	ret = ps_pread(ta->ph, ta->thread_event_mask_addr, &mask,
355a80845eaSDavid Xu 		sizeof(mask));
356a80845eaSDavid Xu 	if (ret != 0)
357a80845eaSDavid Xu 		return (P2T(ret));
358a80845eaSDavid Xu 	mask &= ~*events;
359a80845eaSDavid Xu 	ret = ps_pwrite(ta->ph, ta->thread_event_mask_addr, &mask,
360a80845eaSDavid Xu 		sizeof(mask));
361a80845eaSDavid Xu 	return (P2T(ret));
3623c1e38eaSMarcel Moolenaar }
3633c1e38eaSMarcel Moolenaar 
3643c1e38eaSMarcel Moolenaar static td_err_e
pt_ta_event_getmsg(const td_thragent_t * ta,td_event_msg_t * msg)365e65421baSDavid Xu pt_ta_event_getmsg(const td_thragent_t *ta, td_event_msg_t *msg)
3663c1e38eaSMarcel Moolenaar {
367a80845eaSDavid Xu 	static td_thrhandle_t handle;
368a80845eaSDavid Xu 
36903fad2adSMarcel Moolenaar 	psaddr_t pt;
370787e88a3SDavid Xu 	td_thr_events_e	tmp;
371ef6f47c4SMarius Strobl 	int64_t lwp;
372a80845eaSDavid Xu 	int ret;
373a80845eaSDavid Xu 
374e65421baSDavid Xu 	TDBG_FUNC();
375a80845eaSDavid Xu 
37603fad2adSMarcel Moolenaar 	ret = thr_pread_ptr(ta, ta->thread_last_event_addr, &pt);
377a80845eaSDavid Xu 	if (ret != 0)
37803fad2adSMarcel Moolenaar 		return (TD_ERR);
37916b0c20cSMarcel Moolenaar 	if (pt == 0)
380e65421baSDavid Xu 		return (TD_NOMSG);
381787e88a3SDavid Xu 	/*
382787e88a3SDavid Xu 	 * Take the event pointer, at the time, libthr only reports event
383787e88a3SDavid Xu 	 * once a time, so it is not a link list.
384787e88a3SDavid Xu 	 */
38503fad2adSMarcel Moolenaar 	thr_pwrite_ptr(ta, ta->thread_last_event_addr, 0);
386a80845eaSDavid Xu 
387787e88a3SDavid Xu 	/* Read event info */
388a80845eaSDavid Xu 	ret = ps_pread(ta->ph, pt + ta->thread_off_event_buf, msg, sizeof(*msg));
389a80845eaSDavid Xu 	if (ret != 0)
390a80845eaSDavid Xu 		return (P2T(ret));
391a80845eaSDavid Xu 	if (msg->event == 0)
392a80845eaSDavid Xu 		return (TD_NOMSG);
393787e88a3SDavid Xu 	/* Clear event */
394a80845eaSDavid Xu 	tmp = 0;
395a80845eaSDavid Xu 	ps_pwrite(ta->ph, pt + ta->thread_off_event_buf, &tmp, sizeof(tmp));
396787e88a3SDavid Xu 	/* Convert event */
39703fad2adSMarcel Moolenaar 	pt = msg->th_p;
398e31fe879SMarius Strobl 	ret = thr_pread_long(ta, pt + ta->thread_off_tid, &lwp);
399a80845eaSDavid Xu 	if (ret != 0)
40003fad2adSMarcel Moolenaar 		return (TD_ERR);
401a80845eaSDavid Xu 	handle.th_ta = ta;
402787e88a3SDavid Xu 	handle.th_tid = lwp;
403a80845eaSDavid Xu 	handle.th_thread = pt;
40403fad2adSMarcel Moolenaar 	msg->th_p = (uintptr_t)&handle;
405a80845eaSDavid Xu 	return (0);
406e65421baSDavid Xu }
407e65421baSDavid Xu 
408e65421baSDavid Xu static td_err_e
pt_dbsuspend(const td_thrhandle_t * th,int suspend)409e65421baSDavid Xu pt_dbsuspend(const td_thrhandle_t *th, int suspend)
410e65421baSDavid Xu {
411f60a5b31SMarcel Moolenaar 	const td_thragent_t *ta = th->th_ta;
412e65421baSDavid Xu 	int ret;
413e65421baSDavid Xu 
414e65421baSDavid Xu 	TDBG_FUNC();
415e65421baSDavid Xu 
416e65421baSDavid Xu 	ret = pt_validate(th);
417e65421baSDavid Xu 	if (ret)
418e65421baSDavid Xu 		return (ret);
419e65421baSDavid Xu 
420e65421baSDavid Xu 	if (suspend)
421787e88a3SDavid Xu 		ret = ps_lstop(ta->ph, th->th_tid);
422e65421baSDavid Xu 	else
423787e88a3SDavid Xu 		ret = ps_lcontinue(ta->ph, th->th_tid);
424e65421baSDavid Xu 	return (P2T(ret));
425e65421baSDavid Xu }
426e65421baSDavid Xu 
427e65421baSDavid Xu static td_err_e
pt_thr_dbresume(const td_thrhandle_t * th)428e65421baSDavid Xu pt_thr_dbresume(const td_thrhandle_t *th)
429e65421baSDavid Xu {
430e65421baSDavid Xu 	TDBG_FUNC();
431e65421baSDavid Xu 
432e65421baSDavid Xu 	return pt_dbsuspend(th, 0);
433e65421baSDavid Xu }
434e65421baSDavid Xu 
435e65421baSDavid Xu static td_err_e
pt_thr_dbsuspend(const td_thrhandle_t * th)436e65421baSDavid Xu pt_thr_dbsuspend(const td_thrhandle_t *th)
437e65421baSDavid Xu {
438e65421baSDavid Xu 	TDBG_FUNC();
439e65421baSDavid Xu 
440e65421baSDavid Xu 	return pt_dbsuspend(th, 1);
441e65421baSDavid Xu }
442e65421baSDavid Xu 
443e65421baSDavid Xu static td_err_e
pt_thr_validate(const td_thrhandle_t * th)444e65421baSDavid Xu pt_thr_validate(const td_thrhandle_t *th)
445e65421baSDavid Xu {
446e65421baSDavid Xu 	td_thrhandle_t temp;
447e65421baSDavid Xu 	int ret;
448e65421baSDavid Xu 
449e65421baSDavid Xu 	TDBG_FUNC();
450e65421baSDavid Xu 
451787e88a3SDavid Xu 	ret = pt_ta_map_id2thr(th->th_ta, th->th_tid, &temp);
452e65421baSDavid Xu 	return (ret);
453e65421baSDavid Xu }
454e65421baSDavid Xu 
455e65421baSDavid Xu static td_err_e
pt_thr_get_info_common(const td_thrhandle_t * th,td_thrinfo_t * info,int old)456098d0537SKonstantin Belousov pt_thr_get_info_common(const td_thrhandle_t *th, td_thrinfo_t *info, int old)
457e65421baSDavid Xu {
458e65421baSDavid Xu 	const td_thragent_t *ta = th->th_ta;
4594f7b0f0eSDavid Xu 	struct ptrace_lwpinfo linfo;
46018860a1cSDag-Erling Smørgrav 	int traceme;
461e65421baSDavid Xu 	int state;
462e65421baSDavid Xu 	int ret;
463e65421baSDavid Xu 
464e65421baSDavid Xu 	TDBG_FUNC();
465e65421baSDavid Xu 
46683154c48SDavid Xu 	bzero(info, sizeof(*info));
467e65421baSDavid Xu 	ret = pt_validate(th);
468e65421baSDavid Xu 	if (ret)
469e65421baSDavid Xu 		return (ret);
47003fad2adSMarcel Moolenaar 	ret = thr_pread_int(ta, th->th_thread + ta->thread_off_state, &state);
471e65421baSDavid Xu 	if (ret != 0)
47203fad2adSMarcel Moolenaar 		return (TD_ERR);
47303fad2adSMarcel Moolenaar 	ret = thr_pread_int(ta, th->th_thread + ta->thread_off_report_events,
47418860a1cSDag-Erling Smørgrav 	    &traceme);
47518860a1cSDag-Erling Smørgrav 	info->ti_traceme = traceme;
476b9da3fd7SDavid Xu 	if (ret != 0)
47703fad2adSMarcel Moolenaar 		return (TD_ERR);
478787e88a3SDavid Xu 	ret = ps_pread(ta->ph, th->th_thread + ta->thread_off_event_mask,
479b9da3fd7SDavid Xu 		&info->ti_events, sizeof(td_thr_events_t));
480b9da3fd7SDavid Xu 	if (ret != 0)
481b9da3fd7SDavid Xu 		return (P2T(ret));
482787e88a3SDavid Xu 	ret = ps_pread(ta->ph, th->th_thread + ta->thread_off_tcb,
483787e88a3SDavid Xu 		&info->ti_tls, sizeof(void *));
484787e88a3SDavid Xu 	info->ti_lid = th->th_tid;
485e65421baSDavid Xu 	info->ti_tid = th->th_tid;
486787e88a3SDavid Xu 	info->ti_thread = th->th_thread;
487e65421baSDavid Xu 	info->ti_ta_p = th->th_ta;
4884f7b0f0eSDavid Xu 	ret = ps_linfo(ta->ph, th->th_tid, &linfo);
4894f7b0f0eSDavid Xu 	if (ret == PS_OK) {
4904f7b0f0eSDavid Xu 		info->ti_sigmask = linfo.pl_sigmask;
4914f7b0f0eSDavid Xu 		info->ti_pending = linfo.pl_siglist;
492098d0537SKonstantin Belousov 		if (!old) {
493098d0537SKonstantin Belousov 			if ((linfo.pl_flags & PL_FLAG_SI) != 0)
494098d0537SKonstantin Belousov 				info->ti_siginfo = linfo.pl_siginfo;
495098d0537SKonstantin Belousov 			else
496098d0537SKonstantin Belousov 				bzero(&info->ti_siginfo,
497098d0537SKonstantin Belousov 				    sizeof(info->ti_siginfo));
498098d0537SKonstantin Belousov 		}
499ef39743bSDavid Xu 	} else
500ef39743bSDavid Xu 		return (ret);
501e65421baSDavid Xu 	if (state == ta->thread_state_running)
502e65421baSDavid Xu 		info->ti_state = TD_THR_RUN;
503e65421baSDavid Xu 	else if (state == ta->thread_state_zoombie)
504e65421baSDavid Xu 		info->ti_state = TD_THR_ZOMBIE;
505e65421baSDavid Xu 	else
506e65421baSDavid Xu 		info->ti_state = TD_THR_SLEEP;
507e65421baSDavid Xu 	info->ti_type = TD_THR_USER;
508e65421baSDavid Xu 	return (0);
509e65421baSDavid Xu }
510e65421baSDavid Xu 
511098d0537SKonstantin Belousov static td_err_e
pt_thr_old_get_info(const td_thrhandle_t * th,td_old_thrinfo_t * info)512098d0537SKonstantin Belousov pt_thr_old_get_info(const td_thrhandle_t *th, td_old_thrinfo_t *info)
513098d0537SKonstantin Belousov {
514098d0537SKonstantin Belousov 
515098d0537SKonstantin Belousov 	return (pt_thr_get_info_common(th, (td_thrinfo_t *)info, 1));
516098d0537SKonstantin Belousov }
517098d0537SKonstantin Belousov 
518098d0537SKonstantin Belousov static td_err_e
pt_thr_get_info(const td_thrhandle_t * th,td_thrinfo_t * info)519098d0537SKonstantin Belousov pt_thr_get_info(const td_thrhandle_t *th, td_thrinfo_t *info)
520098d0537SKonstantin Belousov {
521098d0537SKonstantin Belousov 
522098d0537SKonstantin Belousov 	return (pt_thr_get_info_common(th, info, 0));
523098d0537SKonstantin Belousov }
524098d0537SKonstantin Belousov 
5258d7681bbSDoug Rabson #ifdef __i386__
5268d7681bbSDoug Rabson static td_err_e
pt_thr_getxmmregs(const td_thrhandle_t * th,char * fxsave)5278d7681bbSDoug Rabson pt_thr_getxmmregs(const td_thrhandle_t *th, char *fxsave)
5288d7681bbSDoug Rabson {
5298d7681bbSDoug Rabson 	const td_thragent_t *ta = th->th_ta;
5308d7681bbSDoug Rabson 	int ret;
5318d7681bbSDoug Rabson 
5328d7681bbSDoug Rabson 	TDBG_FUNC();
5338d7681bbSDoug Rabson 
5348d7681bbSDoug Rabson 	ret = pt_validate(th);
5358d7681bbSDoug Rabson 	if (ret)
5368d7681bbSDoug Rabson 		return (ret);
5378d7681bbSDoug Rabson 
5388d7681bbSDoug Rabson 	ret = ps_lgetxmmregs(ta->ph, th->th_tid, fxsave);
5398d7681bbSDoug Rabson 	return (P2T(ret));
5408d7681bbSDoug Rabson }
5418d7681bbSDoug Rabson #endif
5428d7681bbSDoug Rabson 
543e65421baSDavid Xu static td_err_e
pt_thr_getfpregs(const td_thrhandle_t * th,prfpregset_t * fpregs)544e65421baSDavid Xu pt_thr_getfpregs(const td_thrhandle_t *th, prfpregset_t *fpregs)
545e65421baSDavid Xu {
546e65421baSDavid Xu 	const td_thragent_t *ta = th->th_ta;
547e65421baSDavid Xu 	int ret;
548e65421baSDavid Xu 
549e65421baSDavid Xu 	TDBG_FUNC();
550e65421baSDavid Xu 
551e65421baSDavid Xu 	ret = pt_validate(th);
552e65421baSDavid Xu 	if (ret)
553e65421baSDavid Xu 		return (ret);
554e65421baSDavid Xu 
555787e88a3SDavid Xu 	ret = ps_lgetfpregs(ta->ph, th->th_tid, fpregs);
556e65421baSDavid Xu 	return (P2T(ret));
557e65421baSDavid Xu }
558e65421baSDavid Xu 
559e65421baSDavid Xu static td_err_e
pt_thr_getgregs(const td_thrhandle_t * th,prgregset_t gregs)560e65421baSDavid Xu pt_thr_getgregs(const td_thrhandle_t *th, prgregset_t gregs)
561e65421baSDavid Xu {
562e65421baSDavid Xu 	const td_thragent_t *ta = th->th_ta;
563e65421baSDavid Xu 	int ret;
564e65421baSDavid Xu 
565e65421baSDavid Xu 	TDBG_FUNC();
566e65421baSDavid Xu 
567e65421baSDavid Xu 	ret = pt_validate(th);
568e65421baSDavid Xu 	if (ret)
569e65421baSDavid Xu 		return (ret);
570e65421baSDavid Xu 
571787e88a3SDavid Xu 	ret = ps_lgetregs(ta->ph, th->th_tid, gregs);
572e65421baSDavid Xu 	return (P2T(ret));
573e65421baSDavid Xu }
574e65421baSDavid Xu 
5758d7681bbSDoug Rabson #ifdef __i386__
5768d7681bbSDoug Rabson static td_err_e
pt_thr_setxmmregs(const td_thrhandle_t * th,const char * fxsave)5778d7681bbSDoug Rabson pt_thr_setxmmregs(const td_thrhandle_t *th, const char *fxsave)
5788d7681bbSDoug Rabson {
5798d7681bbSDoug Rabson 	const td_thragent_t *ta = th->th_ta;
5808d7681bbSDoug Rabson 	int ret;
5818d7681bbSDoug Rabson 
5828d7681bbSDoug Rabson 	TDBG_FUNC();
5838d7681bbSDoug Rabson 
5848d7681bbSDoug Rabson 	ret = pt_validate(th);
5858d7681bbSDoug Rabson 	if (ret)
5868d7681bbSDoug Rabson 		return (ret);
5878d7681bbSDoug Rabson 
5888d7681bbSDoug Rabson 	ret = ps_lsetxmmregs(ta->ph, th->th_tid, fxsave);
5898d7681bbSDoug Rabson 	return (P2T(ret));
5908d7681bbSDoug Rabson }
5918d7681bbSDoug Rabson #endif
5928d7681bbSDoug Rabson 
593e65421baSDavid Xu static td_err_e
pt_thr_setfpregs(const td_thrhandle_t * th,const prfpregset_t * fpregs)594e65421baSDavid Xu pt_thr_setfpregs(const td_thrhandle_t *th, const prfpregset_t *fpregs)
595e65421baSDavid Xu {
596e65421baSDavid Xu 	const td_thragent_t *ta = th->th_ta;
597e65421baSDavid Xu 	int ret;
598e65421baSDavid Xu 
599e65421baSDavid Xu 	TDBG_FUNC();
600e65421baSDavid Xu 
601e65421baSDavid Xu 	ret = pt_validate(th);
602e65421baSDavid Xu 	if (ret)
603e65421baSDavid Xu 		return (ret);
604e65421baSDavid Xu 
605787e88a3SDavid Xu 	ret = ps_lsetfpregs(ta->ph, th->th_tid, fpregs);
606e65421baSDavid Xu 	return (P2T(ret));
607e65421baSDavid Xu }
608e65421baSDavid Xu 
609e65421baSDavid Xu static td_err_e
pt_thr_setgregs(const td_thrhandle_t * th,const prgregset_t gregs)610e65421baSDavid Xu pt_thr_setgregs(const td_thrhandle_t *th, const prgregset_t gregs)
611e65421baSDavid Xu {
612e65421baSDavid Xu 	const td_thragent_t *ta = th->th_ta;
613e65421baSDavid Xu 	int ret;
614e65421baSDavid Xu 
615e65421baSDavid Xu 	TDBG_FUNC();
616e65421baSDavid Xu 
617e65421baSDavid Xu 	ret = pt_validate(th);
618e65421baSDavid Xu 	if (ret)
619e65421baSDavid Xu 		return (ret);
620e65421baSDavid Xu 
621787e88a3SDavid Xu 	ret = ps_lsetregs(ta->ph, th->th_tid, gregs);
622e65421baSDavid Xu 	return (P2T(ret));
623e65421baSDavid Xu }
624e65421baSDavid Xu 
625e65421baSDavid Xu static td_err_e
pt_thr_event_enable(const td_thrhandle_t * th,int en)626e65421baSDavid Xu pt_thr_event_enable(const td_thrhandle_t *th, int en)
627e65421baSDavid Xu {
628a80845eaSDavid Xu 	const td_thragent_t *ta = th->th_ta;
629a80845eaSDavid Xu 	int ret;
630a80845eaSDavid Xu 
631e65421baSDavid Xu 	TDBG_FUNC();
632a80845eaSDavid Xu 	ret = ps_pwrite(ta->ph, th->th_thread + ta->thread_off_report_events,
633a80845eaSDavid Xu 		&en, sizeof(int));
634a80845eaSDavid Xu 	return (P2T(ret));
6353c1e38eaSMarcel Moolenaar }
6363c1e38eaSMarcel Moolenaar 
6373c1e38eaSMarcel Moolenaar static td_err_e
pt_thr_set_event(const td_thrhandle_t * th,td_thr_events_t * setp)638e65421baSDavid Xu pt_thr_set_event(const td_thrhandle_t *th, td_thr_events_t *setp)
6393c1e38eaSMarcel Moolenaar {
640a80845eaSDavid Xu 	const td_thragent_t *ta = th->th_ta;
641a80845eaSDavid Xu 	td_thr_events_t mask;
642a80845eaSDavid Xu 	int ret;
643a80845eaSDavid Xu 
644e65421baSDavid Xu 	TDBG_FUNC();
645a80845eaSDavid Xu 	ret = ps_pread(ta->ph, th->th_thread + ta->thread_off_event_mask,
646a80845eaSDavid Xu 			&mask, sizeof(mask));
647a80845eaSDavid Xu 	mask |= *setp;
648a80845eaSDavid Xu 	ret = ps_pwrite(ta->ph, th->th_thread + ta->thread_off_event_mask,
649a80845eaSDavid Xu 			&mask, sizeof(mask));
650a80845eaSDavid Xu 	return (P2T(ret));
6513c1e38eaSMarcel Moolenaar }
6523c1e38eaSMarcel Moolenaar 
6533c1e38eaSMarcel Moolenaar static td_err_e
pt_thr_clear_event(const td_thrhandle_t * th,td_thr_events_t * setp)654e65421baSDavid Xu pt_thr_clear_event(const td_thrhandle_t *th, td_thr_events_t *setp)
6553c1e38eaSMarcel Moolenaar {
656a80845eaSDavid Xu 	const td_thragent_t *ta = th->th_ta;
657a80845eaSDavid Xu 	td_thr_events_t mask;
658a80845eaSDavid Xu 	int ret;
659a80845eaSDavid Xu 
660e65421baSDavid Xu 	TDBG_FUNC();
661a80845eaSDavid Xu 	ret = ps_pread(ta->ph, th->th_thread + ta->thread_off_event_mask,
662a80845eaSDavid Xu 			&mask, sizeof(mask));
663a80845eaSDavid Xu 	mask &= ~*setp;
664a80845eaSDavid Xu 	ret = ps_pwrite(ta->ph, th->th_thread + ta->thread_off_event_mask,
665a80845eaSDavid Xu 			&mask, sizeof(mask));
666a80845eaSDavid Xu 	return (P2T(ret));
6673c1e38eaSMarcel Moolenaar }
6683c1e38eaSMarcel Moolenaar 
669d4ee7126SDavid Xu static td_err_e
pt_thr_event_getmsg(const td_thrhandle_t * th,td_event_msg_t * msg)670e65421baSDavid Xu pt_thr_event_getmsg(const td_thrhandle_t *th, td_event_msg_t *msg)
671d4ee7126SDavid Xu {
672a80845eaSDavid Xu 	static td_thrhandle_t handle;
673f60a5b31SMarcel Moolenaar 	const td_thragent_t *ta = th->th_ta;
674a80845eaSDavid Xu 	psaddr_t pt, pt_temp;
675ef6f47c4SMarius Strobl 	int64_t lwp;
676a80845eaSDavid Xu 	int ret;
677a80845eaSDavid Xu 	td_thr_events_e	tmp;
678a80845eaSDavid Xu 
679e65421baSDavid Xu 	TDBG_FUNC();
680a80845eaSDavid Xu 	pt = th->th_thread;
68103fad2adSMarcel Moolenaar 	ret = thr_pread_ptr(ta, ta->thread_last_event_addr, &pt_temp);
682a80845eaSDavid Xu 	if (ret != 0)
68303fad2adSMarcel Moolenaar 		return (TD_ERR);
684787e88a3SDavid Xu 	/* Get event */
685a80845eaSDavid Xu 	ret = ps_pread(ta->ph, pt + ta->thread_off_event_buf, msg, sizeof(*msg));
686a80845eaSDavid Xu 	if (ret != 0)
687a80845eaSDavid Xu 		return (P2T(ret));
688a80845eaSDavid Xu 	if (msg->event == 0)
689e65421baSDavid Xu 		return (TD_NOMSG);
690787e88a3SDavid Xu 	/*
691787e88a3SDavid Xu 	 * Take the event pointer, at the time, libthr only reports event
692787e88a3SDavid Xu 	 * once a time, so it is not a link list.
693787e88a3SDavid Xu 	 */
69403fad2adSMarcel Moolenaar 	if (pt == pt_temp)
69503fad2adSMarcel Moolenaar 		thr_pwrite_ptr(ta, ta->thread_last_event_addr, 0);
69603fad2adSMarcel Moolenaar 
697787e88a3SDavid Xu 	/* Clear event */
698a80845eaSDavid Xu 	tmp = 0;
699a80845eaSDavid Xu 	ps_pwrite(ta->ph, pt + ta->thread_off_event_buf, &tmp, sizeof(tmp));
700787e88a3SDavid Xu 	/* Convert event */
70103fad2adSMarcel Moolenaar 	pt = msg->th_p;
702e31fe879SMarius Strobl 	ret = thr_pread_long(ta, pt + ta->thread_off_tid, &lwp);
703a80845eaSDavid Xu 	if (ret != 0)
70403fad2adSMarcel Moolenaar 		return (TD_ERR);
705a80845eaSDavid Xu 	handle.th_ta = ta;
706787e88a3SDavid Xu 	handle.th_tid = lwp;
707a80845eaSDavid Xu 	handle.th_thread = pt;
70803fad2adSMarcel Moolenaar 	msg->th_p = (uintptr_t)&handle;
709a80845eaSDavid Xu 	return (0);
710e65421baSDavid Xu }
711e65421baSDavid Xu 
712e65421baSDavid Xu static td_err_e
pt_thr_sstep(const td_thrhandle_t * th,int step __unused)713f60a5b31SMarcel Moolenaar pt_thr_sstep(const td_thrhandle_t *th, int step __unused)
714e65421baSDavid Xu {
715e65421baSDavid Xu 	TDBG_FUNC();
716e65421baSDavid Xu 
717787e88a3SDavid Xu 	return pt_validate(th);
718e65421baSDavid Xu }
719e65421baSDavid Xu 
720e65421baSDavid Xu static int
pt_validate(const td_thrhandle_t * th)721e65421baSDavid Xu pt_validate(const td_thrhandle_t *th)
722e65421baSDavid Xu {
723e65421baSDavid Xu 
72416b0c20cSMarcel Moolenaar 	if (th->th_tid == 0 || th->th_thread == 0)
725787e88a3SDavid Xu 		return (TD_ERR);
726e65421baSDavid Xu 	return (TD_OK);
727e65421baSDavid Xu }
728e65421baSDavid Xu 
729e65421baSDavid Xu static td_err_e
pt_thr_tls_get_addr(const td_thrhandle_t * th,psaddr_t _linkmap,size_t offset,psaddr_t * address)73016b0c20cSMarcel Moolenaar pt_thr_tls_get_addr(const td_thrhandle_t *th, psaddr_t _linkmap, size_t offset,
73116b0c20cSMarcel Moolenaar     psaddr_t *address)
732e65421baSDavid Xu {
733e65421baSDavid Xu 	const td_thragent_t *ta = th->th_ta;
73416b0c20cSMarcel Moolenaar 	psaddr_t dtv_addr, obj_entry, tcb_addr;
735e65421baSDavid Xu 	int tls_index, ret;
736e65421baSDavid Xu 
737e65421baSDavid Xu 	/* linkmap is a member of Obj_Entry */
73816b0c20cSMarcel Moolenaar 	obj_entry = _linkmap - ta->thread_off_linkmap;
739e65421baSDavid Xu 
740e65421baSDavid Xu 	/* get tlsindex of the object file */
741e65421baSDavid Xu 	ret = ps_pread(ta->ph,
742e65421baSDavid Xu 		obj_entry + ta->thread_off_tlsindex,
743e65421baSDavid Xu 		&tls_index, sizeof(tls_index));
744e65421baSDavid Xu 	if (ret != 0)
745e65421baSDavid Xu 		return (P2T(ret));
746e65421baSDavid Xu 
747e65421baSDavid Xu 	/* get thread tcb */
748787e88a3SDavid Xu 	ret = ps_pread(ta->ph, th->th_thread + ta->thread_off_tcb,
749e65421baSDavid Xu 		&tcb_addr, sizeof(tcb_addr));
750e65421baSDavid Xu 	if (ret != 0)
751e65421baSDavid Xu 		return (P2T(ret));
752e65421baSDavid Xu 
753e65421baSDavid Xu 	/* get dtv array address */
754e65421baSDavid Xu 	ret = ps_pread(ta->ph, tcb_addr + ta->thread_off_dtv,
755e65421baSDavid Xu 		&dtv_addr, sizeof(dtv_addr));
756e65421baSDavid Xu 	if (ret != 0)
757e65421baSDavid Xu 		return (P2T(ret));
758e65421baSDavid Xu 	/* now get the object's tls block base address */
75916b0c20cSMarcel Moolenaar 	ret = ps_pread(ta->ph, dtv_addr + sizeof(void *) * (tls_index+1),
76016b0c20cSMarcel Moolenaar 	    address, sizeof(*address));
761e65421baSDavid Xu 	if (ret != 0)
762e65421baSDavid Xu 		return (P2T(ret));
763e65421baSDavid Xu 
764e65421baSDavid Xu 	*address += offset;
765d4ee7126SDavid Xu 	return (TD_OK);
766d4ee7126SDavid Xu }
767d4ee7126SDavid Xu 
768ae824d80SEd Schouten static struct ta_ops libthr_db_ops = {
769e65421baSDavid Xu 	.to_init		= pt_init,
770e65421baSDavid Xu 	.to_ta_clear_event	= pt_ta_clear_event,
771e65421baSDavid Xu 	.to_ta_delete		= pt_ta_delete,
772e65421baSDavid Xu 	.to_ta_event_addr	= pt_ta_event_addr,
773e65421baSDavid Xu 	.to_ta_event_getmsg	= pt_ta_event_getmsg,
774e65421baSDavid Xu 	.to_ta_map_id2thr	= pt_ta_map_id2thr,
775e65421baSDavid Xu 	.to_ta_map_lwp2thr	= pt_ta_map_lwp2thr,
776e65421baSDavid Xu 	.to_ta_new		= pt_ta_new,
777e65421baSDavid Xu 	.to_ta_set_event	= pt_ta_set_event,
778e65421baSDavid Xu 	.to_ta_thr_iter		= pt_ta_thr_iter,
779e65421baSDavid Xu 	.to_ta_tsd_iter		= pt_ta_tsd_iter,
780e65421baSDavid Xu 	.to_thr_clear_event	= pt_thr_clear_event,
781e65421baSDavid Xu 	.to_thr_dbresume	= pt_thr_dbresume,
782e65421baSDavid Xu 	.to_thr_dbsuspend	= pt_thr_dbsuspend,
783e65421baSDavid Xu 	.to_thr_event_enable	= pt_thr_event_enable,
784e65421baSDavid Xu 	.to_thr_event_getmsg	= pt_thr_event_getmsg,
785098d0537SKonstantin Belousov 	.to_thr_old_get_info	= pt_thr_old_get_info,
786e65421baSDavid Xu 	.to_thr_get_info	= pt_thr_get_info,
787e65421baSDavid Xu 	.to_thr_getfpregs	= pt_thr_getfpregs,
788e65421baSDavid Xu 	.to_thr_getgregs	= pt_thr_getgregs,
789e65421baSDavid Xu 	.to_thr_set_event	= pt_thr_set_event,
790e65421baSDavid Xu 	.to_thr_setfpregs	= pt_thr_setfpregs,
791e65421baSDavid Xu 	.to_thr_setgregs	= pt_thr_setgregs,
792e65421baSDavid Xu 	.to_thr_validate	= pt_thr_validate,
793e65421baSDavid Xu 	.to_thr_tls_get_addr	= pt_thr_tls_get_addr,
794d4ee7126SDavid Xu 
795d4ee7126SDavid Xu 	/* FreeBSD specific extensions. */
796e65421baSDavid Xu 	.to_thr_sstep		= pt_thr_sstep,
7978d7681bbSDoug Rabson #ifdef __i386__
7988d7681bbSDoug Rabson 	.to_thr_getxmmregs	= pt_thr_getxmmregs,
7998d7681bbSDoug Rabson 	.to_thr_setxmmregs	= pt_thr_setxmmregs,
8008d7681bbSDoug Rabson #endif
8013c1e38eaSMarcel Moolenaar };
80220b94d80SDavid Xu 
80320b94d80SDavid Xu DATA_SET(__ta_ops, libthr_db_ops);
804