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