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