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