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