]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - lib/libthread_db/libthr_db.c
ident(1): Normalizing date format
[FreeBSD/FreeBSD.git] / lib / libthread_db / libthr_db.c
1 /*-
2  * SPDX-License-Identifier: BSD-2-Clause-FreeBSD
3  *
4  * Copyright (c) 2004 Marcel Moolenaar
5  * Copyright (c) 2005 David Xu
6  * All rights reserved.
7  *
8  * Redistribution and use in source and binary forms, with or without
9  * modification, are permitted provided that the following conditions
10  * are met:
11  *
12  * 1. Redistributions of source code must retain the above copyright
13  *    notice, this list of conditions and the following disclaimer.
14  * 2. Redistributions in binary form must reproduce the above copyright
15  *    notice, this list of conditions and the following disclaimer in the
16  *    documentation and/or other materials provided with the distribution.
17  *
18  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
19  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
20  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
22  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
23  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28  */
29
30 #include <sys/cdefs.h>
31 __FBSDID("$FreeBSD$");
32
33 #include <proc_service.h>
34 #include <stddef.h>
35 #include <stdlib.h>
36 #include <string.h>
37 #include <sys/types.h>
38 #include <sys/linker_set.h>
39 #include <sys/ptrace.h>
40 #include <thread_db.h>
41 #include <unistd.h>
42
43 #include "thread_db_int.h"
44
45 #define TERMINATED      1
46
47 struct td_thragent {
48         TD_THRAGENT_FIELDS;
49         psaddr_t        libthr_debug_addr;
50         psaddr_t        thread_list_addr;
51         psaddr_t        thread_active_threads_addr;
52         psaddr_t        thread_keytable_addr;
53         psaddr_t        thread_last_event_addr;
54         psaddr_t        thread_event_mask_addr;
55         psaddr_t        thread_bp_create_addr;
56         psaddr_t        thread_bp_death_addr;
57         int             thread_off_dtv;
58         int             thread_off_tlsindex;
59         int             thread_off_attr_flags;
60         int             thread_size_key;
61         int             thread_off_tcb;
62         int             thread_off_linkmap;
63         int             thread_off_next;
64         int             thread_off_state;
65         int             thread_off_tid;
66         int             thread_max_keys;
67         int             thread_off_key_allocated;
68         int             thread_off_key_destructor;
69         int             thread_off_report_events;
70         int             thread_off_event_mask;
71         int             thread_off_event_buf;
72         int             thread_state_zoombie;
73         int             thread_state_running;
74 };
75
76 #define P2T(c) ps2td(c)
77
78 static int pt_validate(const td_thrhandle_t *th);
79
80 static int
81 ps2td(int c)
82 {
83         switch (c) {
84         case PS_OK:
85                 return TD_OK;
86         case PS_ERR:
87                 return TD_ERR;
88         case PS_BADPID:
89                 return TD_BADPH;
90         case PS_BADLID:
91                 return TD_NOLWP;
92         case PS_BADADDR:
93                 return TD_ERR;
94         case PS_NOSYM:
95                 return TD_NOLIBTHREAD;
96         case PS_NOFREGS:
97                 return TD_NOFPREGS;
98         default:
99                 return TD_ERR;
100         }
101 }
102
103 static td_err_e
104 pt_init(void)
105 {
106         return (0);
107 }
108
109 static td_err_e
110 pt_ta_new(struct ps_prochandle *ph, td_thragent_t **pta)
111 {
112 #define LOOKUP_SYM(proc, sym, addr)                     \
113         ret = ps_pglobal_lookup(proc, NULL, sym, addr); \
114         if (ret != 0) {                                 \
115                 TDBG("can not find symbol: %s\n", sym); \
116                 ret = TD_NOLIBTHREAD;                   \
117                 goto error;                             \
118         }
119
120 #define LOOKUP_VAL(proc, sym, val)                      \
121         ret = ps_pglobal_lookup(proc, NULL, sym, &vaddr);\
122         if (ret != 0) {                                 \
123                 TDBG("can not find symbol: %s\n", sym); \
124                 ret = TD_NOLIBTHREAD;                   \
125                 goto error;                             \
126         }                                               \
127         ret = ps_pread(proc, vaddr, val, sizeof(int));  \
128         if (ret != 0) {                                 \
129                 TDBG("can not read value of %s\n", sym);\
130                 ret = TD_NOLIBTHREAD;                   \
131                 goto error;                             \
132         }
133
134         td_thragent_t *ta;
135         psaddr_t vaddr;
136         int dbg;
137         int ret;
138
139         TDBG_FUNC();
140
141         ta = malloc(sizeof(td_thragent_t));
142         if (ta == NULL)
143                 return (TD_MALLOC);
144
145         ta->ph = ph;
146
147         LOOKUP_SYM(ph, "_libthr_debug",         &ta->libthr_debug_addr);
148         LOOKUP_SYM(ph, "_thread_list",          &ta->thread_list_addr);
149         LOOKUP_SYM(ph, "_thread_active_threads",&ta->thread_active_threads_addr);
150         LOOKUP_SYM(ph, "_thread_keytable",      &ta->thread_keytable_addr);
151         LOOKUP_SYM(ph, "_thread_last_event",    &ta->thread_last_event_addr);
152         LOOKUP_SYM(ph, "_thread_event_mask",    &ta->thread_event_mask_addr);
153         LOOKUP_SYM(ph, "_thread_bp_create",     &ta->thread_bp_create_addr);
154         LOOKUP_SYM(ph, "_thread_bp_death",      &ta->thread_bp_death_addr);
155         LOOKUP_VAL(ph, "_thread_off_dtv",       &ta->thread_off_dtv);
156         LOOKUP_VAL(ph, "_thread_off_tlsindex",  &ta->thread_off_tlsindex);
157         LOOKUP_VAL(ph, "_thread_off_attr_flags",        &ta->thread_off_attr_flags);
158         LOOKUP_VAL(ph, "_thread_size_key",      &ta->thread_size_key);
159         LOOKUP_VAL(ph, "_thread_off_tcb",       &ta->thread_off_tcb);
160         LOOKUP_VAL(ph, "_thread_off_tid",       &ta->thread_off_tid);
161         LOOKUP_VAL(ph, "_thread_off_linkmap",   &ta->thread_off_linkmap);
162         LOOKUP_VAL(ph, "_thread_off_next",      &ta->thread_off_next);
163         LOOKUP_VAL(ph, "_thread_off_state",     &ta->thread_off_state);
164         LOOKUP_VAL(ph, "_thread_max_keys",      &ta->thread_max_keys);
165         LOOKUP_VAL(ph, "_thread_off_key_allocated", &ta->thread_off_key_allocated);
166         LOOKUP_VAL(ph, "_thread_off_key_destructor", &ta->thread_off_key_destructor);
167         LOOKUP_VAL(ph, "_thread_state_running", &ta->thread_state_running);
168         LOOKUP_VAL(ph, "_thread_state_zoombie", &ta->thread_state_zoombie);
169         LOOKUP_VAL(ph, "_thread_off_report_events", &ta->thread_off_report_events);
170         LOOKUP_VAL(ph, "_thread_off_event_mask", &ta->thread_off_event_mask);
171         LOOKUP_VAL(ph, "_thread_off_event_buf", &ta->thread_off_event_buf);
172         dbg = getpid();
173         /*
174          * If this fails it probably means we're debugging a core file and
175          * can't write to it.
176          */
177         ps_pwrite(ph, ta->libthr_debug_addr, &dbg, sizeof(int));
178         *pta = ta;
179         return (0);
180
181 error:
182         free(ta);
183         return (ret);
184 }
185
186 static td_err_e
187 pt_ta_delete(td_thragent_t *ta)
188 {
189         int dbg;
190
191         TDBG_FUNC();
192
193         dbg = 0;
194         /*
195          * Error returns from this write are not really a problem;
196          * the process doesn't exist any more.
197          */
198         ps_pwrite(ta->ph, ta->libthr_debug_addr, &dbg, sizeof(int));
199         free(ta);
200         return (TD_OK);
201 }
202
203 static td_err_e
204 pt_ta_map_id2thr(const td_thragent_t *ta, thread_t id, td_thrhandle_t *th)
205 {
206         psaddr_t pt;
207         int64_t lwp;
208         int ret;
209
210         TDBG_FUNC();
211
212         if (id == 0)
213                 return (TD_NOTHR);
214         ret = thr_pread_ptr(ta, ta->thread_list_addr, &pt);
215         if (ret != 0)
216                 return (TD_ERR);
217         /* Iterate through thread list to find pthread */
218         while (pt != 0) {
219                 ret = thr_pread_long(ta, pt + ta->thread_off_tid, &lwp);
220                 if (ret != 0)
221                         return (TD_ERR);
222                 if (lwp == id)
223                         break;
224                 /* get next thread */
225                 ret = thr_pread_ptr(ta, pt + ta->thread_off_next, &pt);
226                 if (ret != 0)
227                         return (TD_ERR);
228         }
229         if (pt == 0)
230                 return (TD_NOTHR);
231         th->th_ta = ta;
232         th->th_tid = id;
233         th->th_thread = pt;
234         return (TD_OK);
235 }
236
237 static td_err_e
238 pt_ta_map_lwp2thr(const td_thragent_t *ta, lwpid_t lwp, td_thrhandle_t *th)
239 {
240         return (pt_ta_map_id2thr(ta, lwp, th));
241 }
242
243 static td_err_e
244 pt_ta_thr_iter(const td_thragent_t *ta, td_thr_iter_f *callback,
245     void *cbdata_p, td_thr_state_e state __unused, int ti_pri __unused,
246     sigset_t *ti_sigmask_p __unused, unsigned int ti_user_flags __unused)
247 {
248         td_thrhandle_t th;
249         psaddr_t pt;
250         int64_t lwp;
251         int ret;
252
253         TDBG_FUNC();
254
255         ret = thr_pread_ptr(ta, ta->thread_list_addr, &pt);
256         if (ret != 0)
257                 return (TD_ERR);
258         while (pt != 0) {
259                 ret = thr_pread_long(ta, pt + ta->thread_off_tid, &lwp);
260                 if (ret != 0)
261                         return (TD_ERR);
262                 if (lwp != 0 && lwp != TERMINATED) {
263                         th.th_ta = ta;
264                         th.th_tid = (thread_t)lwp;
265                         th.th_thread = pt;
266                         if ((*callback)(&th, cbdata_p))
267                                 return (TD_DBERR);
268                 }
269                 /* get next thread */
270                 ret = thr_pread_ptr(ta, pt + ta->thread_off_next, &pt);
271                 if (ret != 0)
272                         return (TD_ERR);
273         }
274         return (TD_OK);
275 }
276
277 static td_err_e
278 pt_ta_tsd_iter(const td_thragent_t *ta, td_key_iter_f *ki, void *arg)
279 {
280         void *keytable;
281         void *destructor;
282         int i, ret, allocated;
283
284         TDBG_FUNC();
285
286         keytable = malloc(ta->thread_max_keys * ta->thread_size_key);
287         if (keytable == NULL)
288                 return (TD_MALLOC);
289         ret = ps_pread(ta->ph, (psaddr_t)ta->thread_keytable_addr, keytable,
290                        ta->thread_max_keys * ta->thread_size_key);
291         if (ret != 0) {
292                 free(keytable);
293                 return (P2T(ret));
294         }
295         for (i = 0; i < ta->thread_max_keys; i++) {
296                 allocated = *(int *)(void *)((uintptr_t)keytable +
297                     i * ta->thread_size_key + ta->thread_off_key_allocated);
298                 destructor = *(void **)(void *)((uintptr_t)keytable +
299                     i * ta->thread_size_key + ta->thread_off_key_destructor);
300                 if (allocated) {
301                         ret = (ki)(i, destructor, arg);
302                         if (ret != 0) {
303                                 free(keytable);
304                                 return (TD_DBERR);
305                         }
306                 }
307         }
308         free(keytable);
309         return (TD_OK);
310 }
311
312 static td_err_e
313 pt_ta_event_addr(const td_thragent_t *ta, td_event_e event, td_notify_t *ptr)
314 {
315
316         TDBG_FUNC();
317
318         switch (event) {
319         case TD_CREATE:
320                 ptr->type = NOTIFY_BPT;
321                 ptr->u.bptaddr = ta->thread_bp_create_addr;
322                 return (0);
323         case TD_DEATH:
324                 ptr->type = NOTIFY_BPT;
325                 ptr->u.bptaddr = ta->thread_bp_death_addr;
326                 return (0);
327         default:
328                 return (TD_ERR);
329         }
330 }
331
332 static td_err_e
333 pt_ta_set_event(const td_thragent_t *ta, td_thr_events_t *events)
334 {
335         td_thr_events_t mask;
336         int ret;
337
338         TDBG_FUNC();
339         ret = ps_pread(ta->ph, ta->thread_event_mask_addr, &mask,
340                 sizeof(mask));
341         if (ret != 0)
342                 return (P2T(ret));
343         mask |= *events;
344         ret = ps_pwrite(ta->ph, ta->thread_event_mask_addr, &mask,
345                 sizeof(mask));
346         return (P2T(ret));
347 }
348
349 static td_err_e
350 pt_ta_clear_event(const td_thragent_t *ta, td_thr_events_t *events)
351 {
352         td_thr_events_t mask;
353         int ret;
354
355         TDBG_FUNC();
356         ret = ps_pread(ta->ph, ta->thread_event_mask_addr, &mask,
357                 sizeof(mask));
358         if (ret != 0)
359                 return (P2T(ret));
360         mask &= ~*events;
361         ret = ps_pwrite(ta->ph, ta->thread_event_mask_addr, &mask,
362                 sizeof(mask));
363         return (P2T(ret));
364 }
365
366 static td_err_e
367 pt_ta_event_getmsg(const td_thragent_t *ta, td_event_msg_t *msg)
368 {
369         static td_thrhandle_t handle;
370
371         psaddr_t pt;
372         td_thr_events_e tmp;
373         int64_t lwp;
374         int ret;
375
376         TDBG_FUNC();
377
378         ret = thr_pread_ptr(ta, ta->thread_last_event_addr, &pt);
379         if (ret != 0)
380                 return (TD_ERR);
381         if (pt == 0)
382                 return (TD_NOMSG);
383         /*
384          * Take the event pointer, at the time, libthr only reports event
385          * once a time, so it is not a link list.
386          */
387         thr_pwrite_ptr(ta, ta->thread_last_event_addr, 0);
388
389         /* Read event info */
390         ret = ps_pread(ta->ph, pt + ta->thread_off_event_buf, msg, sizeof(*msg));
391         if (ret != 0)
392                 return (P2T(ret));
393         if (msg->event == 0)
394                 return (TD_NOMSG);
395         /* Clear event */
396         tmp = 0;
397         ps_pwrite(ta->ph, pt + ta->thread_off_event_buf, &tmp, sizeof(tmp));
398         /* Convert event */
399         pt = msg->th_p;
400         ret = thr_pread_long(ta, pt + ta->thread_off_tid, &lwp);
401         if (ret != 0)
402                 return (TD_ERR);
403         handle.th_ta = ta;
404         handle.th_tid = lwp;
405         handle.th_thread = pt;
406         msg->th_p = (uintptr_t)&handle;
407         return (0);
408 }
409
410 static td_err_e
411 pt_dbsuspend(const td_thrhandle_t *th, int suspend)
412 {
413         const td_thragent_t *ta = th->th_ta;
414         int ret;
415
416         TDBG_FUNC();
417
418         ret = pt_validate(th);
419         if (ret)
420                 return (ret);
421
422         if (suspend)
423                 ret = ps_lstop(ta->ph, th->th_tid);
424         else
425                 ret = ps_lcontinue(ta->ph, th->th_tid);
426         return (P2T(ret));
427 }
428
429 static td_err_e
430 pt_thr_dbresume(const td_thrhandle_t *th)
431 {
432         TDBG_FUNC();
433
434         return pt_dbsuspend(th, 0);
435 }
436
437 static td_err_e
438 pt_thr_dbsuspend(const td_thrhandle_t *th)
439 {
440         TDBG_FUNC();
441
442         return pt_dbsuspend(th, 1);
443 }
444
445 static td_err_e
446 pt_thr_validate(const td_thrhandle_t *th)
447 {
448         td_thrhandle_t temp;
449         int ret;
450
451         TDBG_FUNC();
452
453         ret = pt_ta_map_id2thr(th->th_ta, th->th_tid, &temp);
454         return (ret);
455 }
456
457 static td_err_e
458 pt_thr_get_info_common(const td_thrhandle_t *th, td_thrinfo_t *info, int old)
459 {
460         const td_thragent_t *ta = th->th_ta;
461         struct ptrace_lwpinfo linfo;
462         int traceme;
463         int state;
464         int ret;
465
466         TDBG_FUNC();
467
468         bzero(info, sizeof(*info));
469         ret = pt_validate(th);
470         if (ret)
471                 return (ret);
472         ret = thr_pread_int(ta, th->th_thread + ta->thread_off_state, &state);
473         if (ret != 0)
474                 return (TD_ERR);
475         ret = thr_pread_int(ta, th->th_thread + ta->thread_off_report_events,
476             &traceme);
477         info->ti_traceme = traceme;
478         if (ret != 0)
479                 return (TD_ERR);
480         ret = ps_pread(ta->ph, th->th_thread + ta->thread_off_event_mask,
481                 &info->ti_events, sizeof(td_thr_events_t));
482         if (ret != 0)
483                 return (P2T(ret));
484         ret = ps_pread(ta->ph, th->th_thread + ta->thread_off_tcb,
485                 &info->ti_tls, sizeof(void *));
486         info->ti_lid = th->th_tid;
487         info->ti_tid = th->th_tid;
488         info->ti_thread = th->th_thread;
489         info->ti_ta_p = th->th_ta;
490         ret = ps_linfo(ta->ph, th->th_tid, &linfo);
491         if (ret == PS_OK) {
492                 info->ti_sigmask = linfo.pl_sigmask;
493                 info->ti_pending = linfo.pl_siglist;
494                 if (!old) {
495                         if ((linfo.pl_flags & PL_FLAG_SI) != 0)
496                                 info->ti_siginfo = linfo.pl_siginfo;
497                         else
498                                 bzero(&info->ti_siginfo,
499                                     sizeof(info->ti_siginfo));
500                 }
501         } else
502                 return (ret);
503         if (state == ta->thread_state_running)
504                 info->ti_state = TD_THR_RUN;
505         else if (state == ta->thread_state_zoombie)
506                 info->ti_state = TD_THR_ZOMBIE;
507         else
508                 info->ti_state = TD_THR_SLEEP;
509         info->ti_type = TD_THR_USER;
510         return (0);
511 }
512
513 static td_err_e
514 pt_thr_old_get_info(const td_thrhandle_t *th, td_old_thrinfo_t *info)
515 {
516
517         return (pt_thr_get_info_common(th, (td_thrinfo_t *)info, 1));
518 }
519
520 static td_err_e
521 pt_thr_get_info(const td_thrhandle_t *th, td_thrinfo_t *info)
522 {
523
524         return (pt_thr_get_info_common(th, info, 0));
525 }
526
527 #ifdef __i386__
528 static td_err_e
529 pt_thr_getxmmregs(const td_thrhandle_t *th, char *fxsave)
530 {
531         const td_thragent_t *ta = th->th_ta;
532         int ret;
533
534         TDBG_FUNC();
535
536         ret = pt_validate(th);
537         if (ret)
538                 return (ret);
539
540         ret = ps_lgetxmmregs(ta->ph, th->th_tid, fxsave);
541         return (P2T(ret));
542 }
543 #endif
544
545 static td_err_e
546 pt_thr_getfpregs(const td_thrhandle_t *th, prfpregset_t *fpregs)
547 {
548         const td_thragent_t *ta = th->th_ta;
549         int ret;
550
551         TDBG_FUNC();
552
553         ret = pt_validate(th);
554         if (ret)
555                 return (ret);
556
557         ret = ps_lgetfpregs(ta->ph, th->th_tid, fpregs);
558         return (P2T(ret));
559 }
560
561 static td_err_e
562 pt_thr_getgregs(const td_thrhandle_t *th, prgregset_t gregs)
563 {
564         const td_thragent_t *ta = th->th_ta;
565         int ret;
566
567         TDBG_FUNC();
568
569         ret = pt_validate(th);
570         if (ret)
571                 return (ret);
572
573         ret = ps_lgetregs(ta->ph, th->th_tid, gregs);
574         return (P2T(ret));
575 }
576
577 #ifdef __i386__
578 static td_err_e
579 pt_thr_setxmmregs(const td_thrhandle_t *th, const char *fxsave)
580 {
581         const td_thragent_t *ta = th->th_ta;
582         int ret;
583
584         TDBG_FUNC();
585
586         ret = pt_validate(th);
587         if (ret)
588                 return (ret);
589
590         ret = ps_lsetxmmregs(ta->ph, th->th_tid, fxsave);
591         return (P2T(ret));
592 }
593 #endif
594
595 static td_err_e
596 pt_thr_setfpregs(const td_thrhandle_t *th, const prfpregset_t *fpregs)
597 {
598         const td_thragent_t *ta = th->th_ta;
599         int ret;
600
601         TDBG_FUNC();
602
603         ret = pt_validate(th);
604         if (ret)
605                 return (ret);
606
607         ret = ps_lsetfpregs(ta->ph, th->th_tid, fpregs);
608         return (P2T(ret));
609 }
610
611 static td_err_e
612 pt_thr_setgregs(const td_thrhandle_t *th, const prgregset_t gregs)
613 {
614         const td_thragent_t *ta = th->th_ta;
615         int ret;
616
617         TDBG_FUNC();
618
619         ret = pt_validate(th);
620         if (ret)
621                 return (ret);
622
623         ret = ps_lsetregs(ta->ph, th->th_tid, gregs);
624         return (P2T(ret));
625 }
626
627 static td_err_e
628 pt_thr_event_enable(const td_thrhandle_t *th, int en)
629 {
630         const td_thragent_t *ta = th->th_ta;
631         int ret;
632
633         TDBG_FUNC();
634         ret = ps_pwrite(ta->ph, th->th_thread + ta->thread_off_report_events,
635                 &en, sizeof(int));
636         return (P2T(ret));
637 }
638
639 static td_err_e
640 pt_thr_set_event(const td_thrhandle_t *th, td_thr_events_t *setp)
641 {
642         const td_thragent_t *ta = th->th_ta;
643         td_thr_events_t mask;
644         int ret;
645
646         TDBG_FUNC();
647         ret = ps_pread(ta->ph, th->th_thread + ta->thread_off_event_mask,
648                         &mask, sizeof(mask));
649         mask |= *setp;
650         ret = ps_pwrite(ta->ph, th->th_thread + ta->thread_off_event_mask,
651                         &mask, sizeof(mask));
652         return (P2T(ret));
653 }
654
655 static td_err_e
656 pt_thr_clear_event(const td_thrhandle_t *th, td_thr_events_t *setp)
657 {
658         const td_thragent_t *ta = th->th_ta;
659         td_thr_events_t mask;
660         int ret;
661
662         TDBG_FUNC();
663         ret = ps_pread(ta->ph, th->th_thread + ta->thread_off_event_mask,
664                         &mask, sizeof(mask));
665         mask &= ~*setp;
666         ret = ps_pwrite(ta->ph, th->th_thread + ta->thread_off_event_mask,
667                         &mask, sizeof(mask));
668         return (P2T(ret));
669 }
670
671 static td_err_e
672 pt_thr_event_getmsg(const td_thrhandle_t *th, td_event_msg_t *msg)
673 {
674         static td_thrhandle_t handle;
675         const td_thragent_t *ta = th->th_ta;
676         psaddr_t pt, pt_temp;
677         int64_t lwp;
678         int ret;
679         td_thr_events_e tmp;
680
681         TDBG_FUNC();
682         pt = th->th_thread;
683         ret = thr_pread_ptr(ta, ta->thread_last_event_addr, &pt_temp);
684         if (ret != 0)
685                 return (TD_ERR);
686         /* Get event */
687         ret = ps_pread(ta->ph, pt + ta->thread_off_event_buf, msg, sizeof(*msg));
688         if (ret != 0)
689                 return (P2T(ret));
690         if (msg->event == 0)
691                 return (TD_NOMSG);
692         /*
693          * Take the event pointer, at the time, libthr only reports event
694          * once a time, so it is not a link list.
695          */
696         if (pt == pt_temp)
697                 thr_pwrite_ptr(ta, ta->thread_last_event_addr, 0);
698
699         /* Clear event */
700         tmp = 0;
701         ps_pwrite(ta->ph, pt + ta->thread_off_event_buf, &tmp, sizeof(tmp));
702         /* Convert event */
703         pt = msg->th_p;
704         ret = thr_pread_long(ta, pt + ta->thread_off_tid, &lwp);
705         if (ret != 0)
706                 return (TD_ERR);
707         handle.th_ta = ta;
708         handle.th_tid = lwp;
709         handle.th_thread = pt;
710         msg->th_p = (uintptr_t)&handle;
711         return (0);
712 }
713
714 static td_err_e
715 pt_thr_sstep(const td_thrhandle_t *th, int step __unused)
716 {
717         TDBG_FUNC();
718
719         return pt_validate(th);
720 }
721
722 static int
723 pt_validate(const td_thrhandle_t *th)
724 {
725
726         if (th->th_tid == 0 || th->th_thread == 0)
727                 return (TD_ERR);
728         return (TD_OK);
729 }
730
731 static td_err_e
732 pt_thr_tls_get_addr(const td_thrhandle_t *th, psaddr_t _linkmap, size_t offset,
733     psaddr_t *address)
734 {
735         const td_thragent_t *ta = th->th_ta;
736         psaddr_t dtv_addr, obj_entry, tcb_addr;
737         int tls_index, ret;
738
739         /* linkmap is a member of Obj_Entry */
740         obj_entry = _linkmap - ta->thread_off_linkmap;
741
742         /* get tlsindex of the object file */
743         ret = ps_pread(ta->ph,
744                 obj_entry + ta->thread_off_tlsindex,
745                 &tls_index, sizeof(tls_index));
746         if (ret != 0)
747                 return (P2T(ret));
748
749         /* get thread tcb */
750         ret = ps_pread(ta->ph, th->th_thread + ta->thread_off_tcb,
751                 &tcb_addr, sizeof(tcb_addr));
752         if (ret != 0)
753                 return (P2T(ret));
754
755         /* get dtv array address */
756         ret = ps_pread(ta->ph, tcb_addr + ta->thread_off_dtv,
757                 &dtv_addr, sizeof(dtv_addr));
758         if (ret != 0)
759                 return (P2T(ret));
760         /* now get the object's tls block base address */
761         ret = ps_pread(ta->ph, dtv_addr + sizeof(void *) * (tls_index+1),
762             address, sizeof(*address));
763         if (ret != 0)
764                 return (P2T(ret));
765
766         *address += offset;
767         return (TD_OK);
768 }
769
770 static struct ta_ops libthr_db_ops = {
771         .to_init                = pt_init,
772         .to_ta_clear_event      = pt_ta_clear_event,
773         .to_ta_delete           = pt_ta_delete,
774         .to_ta_event_addr       = pt_ta_event_addr,
775         .to_ta_event_getmsg     = pt_ta_event_getmsg,
776         .to_ta_map_id2thr       = pt_ta_map_id2thr,
777         .to_ta_map_lwp2thr      = pt_ta_map_lwp2thr,
778         .to_ta_new              = pt_ta_new,
779         .to_ta_set_event        = pt_ta_set_event,
780         .to_ta_thr_iter         = pt_ta_thr_iter,
781         .to_ta_tsd_iter         = pt_ta_tsd_iter,
782         .to_thr_clear_event     = pt_thr_clear_event,
783         .to_thr_dbresume        = pt_thr_dbresume,
784         .to_thr_dbsuspend       = pt_thr_dbsuspend,
785         .to_thr_event_enable    = pt_thr_event_enable,
786         .to_thr_event_getmsg    = pt_thr_event_getmsg,
787         .to_thr_old_get_info    = pt_thr_old_get_info,
788         .to_thr_get_info        = pt_thr_get_info,
789         .to_thr_getfpregs       = pt_thr_getfpregs,
790         .to_thr_getgregs        = pt_thr_getgregs,
791         .to_thr_set_event       = pt_thr_set_event,
792         .to_thr_setfpregs       = pt_thr_setfpregs,
793         .to_thr_setgregs        = pt_thr_setgregs,
794         .to_thr_validate        = pt_thr_validate,
795         .to_thr_tls_get_addr    = pt_thr_tls_get_addr,
796
797         /* FreeBSD specific extensions. */
798         .to_thr_sstep           = pt_thr_sstep,
799 #ifdef __i386__
800         .to_thr_getxmmregs      = pt_thr_getxmmregs,
801         .to_thr_setxmmregs      = pt_thr_setxmmregs,
802 #endif
803 };
804
805 DATA_SET(__ta_ops, libthr_db_ops);