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