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