15e53a4f9SPedro F. Giffuni /*-
2*4d846d26SWarner Losh * SPDX-License-Identifier: BSD-2-Clause
35e53a4f9SPedro F. Giffuni *
43c1e38eaSMarcel Moolenaar * Copyright (c) 2004 Marcel Moolenaar
5e65421baSDavid Xu * Copyright (c) 2005 David Xu
63c1e38eaSMarcel Moolenaar * All rights reserved.
73c1e38eaSMarcel Moolenaar *
83c1e38eaSMarcel Moolenaar * Redistribution and use in source and binary forms, with or without
93c1e38eaSMarcel Moolenaar * modification, are permitted provided that the following conditions
103c1e38eaSMarcel Moolenaar * are met:
113c1e38eaSMarcel Moolenaar *
123c1e38eaSMarcel Moolenaar * 1. Redistributions of source code must retain the above copyright
133c1e38eaSMarcel Moolenaar * notice, this list of conditions and the following disclaimer.
143c1e38eaSMarcel Moolenaar * 2. Redistributions in binary form must reproduce the above copyright
153c1e38eaSMarcel Moolenaar * notice, this list of conditions and the following disclaimer in the
163c1e38eaSMarcel Moolenaar * documentation and/or other materials provided with the distribution.
173c1e38eaSMarcel Moolenaar *
183c1e38eaSMarcel Moolenaar * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
193c1e38eaSMarcel Moolenaar * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
203c1e38eaSMarcel Moolenaar * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
213c1e38eaSMarcel Moolenaar * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
223c1e38eaSMarcel Moolenaar * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
233c1e38eaSMarcel Moolenaar * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
243c1e38eaSMarcel Moolenaar * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
253c1e38eaSMarcel Moolenaar * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
263c1e38eaSMarcel Moolenaar * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
273c1e38eaSMarcel Moolenaar * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
283c1e38eaSMarcel Moolenaar */
293c1e38eaSMarcel Moolenaar
303c1e38eaSMarcel Moolenaar #include <sys/cdefs.h>
313c1e38eaSMarcel Moolenaar #include <proc_service.h>
32e65421baSDavid Xu #include <stddef.h>
333c1e38eaSMarcel Moolenaar #include <stdlib.h>
34e65421baSDavid Xu #include <string.h>
35e65421baSDavid Xu #include <sys/types.h>
3620b94d80SDavid Xu #include <sys/linker_set.h>
37e65421baSDavid Xu #include <sys/ptrace.h>
383c1e38eaSMarcel Moolenaar #include <thread_db.h>
39e65421baSDavid Xu #include <unistd.h>
403c1e38eaSMarcel Moolenaar
413c1e38eaSMarcel Moolenaar #include "thread_db_int.h"
423c1e38eaSMarcel Moolenaar
43a80845eaSDavid Xu #define TERMINATED 1
44a80845eaSDavid Xu
45e65421baSDavid Xu struct td_thragent {
46e65421baSDavid Xu TD_THRAGENT_FIELDS;
47e65421baSDavid Xu psaddr_t libthr_debug_addr;
48e65421baSDavid Xu psaddr_t thread_list_addr;
49e65421baSDavid Xu psaddr_t thread_active_threads_addr;
50e65421baSDavid Xu psaddr_t thread_keytable_addr;
51a80845eaSDavid Xu psaddr_t thread_last_event_addr;
52a80845eaSDavid Xu psaddr_t thread_event_mask_addr;
53a80845eaSDavid Xu psaddr_t thread_bp_create_addr;
54a80845eaSDavid Xu psaddr_t thread_bp_death_addr;
55e65421baSDavid Xu int thread_off_dtv;
56e65421baSDavid Xu int thread_off_tlsindex;
57e65421baSDavid Xu int thread_off_attr_flags;
58e65421baSDavid Xu int thread_size_key;
59e65421baSDavid Xu int thread_off_tcb;
60e65421baSDavid Xu int thread_off_linkmap;
61e65421baSDavid Xu int thread_off_next;
62e65421baSDavid Xu int thread_off_state;
63e65421baSDavid Xu int thread_off_tid;
64e65421baSDavid Xu int thread_max_keys;
65e65421baSDavid Xu int thread_off_key_allocated;
66e65421baSDavid Xu int thread_off_key_destructor;
67a80845eaSDavid Xu int thread_off_report_events;
68a80845eaSDavid Xu int thread_off_event_mask;
69a80845eaSDavid Xu int thread_off_event_buf;
70e65421baSDavid Xu int thread_state_zoombie;
71e65421baSDavid Xu int thread_state_running;
72e65421baSDavid Xu };
73e65421baSDavid Xu
74e65421baSDavid Xu #define P2T(c) ps2td(c)
75e65421baSDavid Xu
76e65421baSDavid Xu static int pt_validate(const td_thrhandle_t *th);
77e65421baSDavid Xu
78e65421baSDavid Xu static int
ps2td(int c)79e65421baSDavid Xu ps2td(int c)
803c1e38eaSMarcel Moolenaar {
81e65421baSDavid Xu switch (c) {
82e65421baSDavid Xu case PS_OK:
83e65421baSDavid Xu return TD_OK;
84e65421baSDavid Xu case PS_ERR:
85e65421baSDavid Xu return TD_ERR;
86e65421baSDavid Xu case PS_BADPID:
87e65421baSDavid Xu return TD_BADPH;
88e65421baSDavid Xu case PS_BADLID:
89e65421baSDavid Xu return TD_NOLWP;
90e65421baSDavid Xu case PS_BADADDR:
91e65421baSDavid Xu return TD_ERR;
92e65421baSDavid Xu case PS_NOSYM:
93e65421baSDavid Xu return TD_NOLIBTHREAD;
94e65421baSDavid Xu case PS_NOFREGS:
95e65421baSDavid Xu return TD_NOFPREGS;
96e65421baSDavid Xu default:
97e65421baSDavid Xu return TD_ERR;
98e65421baSDavid Xu }
99e65421baSDavid Xu }
100e65421baSDavid Xu
1013c1e38eaSMarcel Moolenaar static td_err_e
pt_init(void)102e65421baSDavid Xu pt_init(void)
1033c1e38eaSMarcel Moolenaar {
104e65421baSDavid Xu return (0);
1053c1e38eaSMarcel Moolenaar }
1063c1e38eaSMarcel Moolenaar
1073c1e38eaSMarcel Moolenaar static td_err_e
pt_ta_new(struct ps_prochandle * ph,td_thragent_t ** pta)108e65421baSDavid Xu pt_ta_new(struct ps_prochandle *ph, td_thragent_t **pta)
1093c1e38eaSMarcel Moolenaar {
110e65421baSDavid Xu #define LOOKUP_SYM(proc, sym, addr) \
111e65421baSDavid Xu ret = ps_pglobal_lookup(proc, NULL, sym, addr); \
112e65421baSDavid Xu if (ret != 0) { \
113e65421baSDavid Xu TDBG("can not find symbol: %s\n", sym); \
114e65421baSDavid Xu ret = TD_NOLIBTHREAD; \
115e65421baSDavid Xu goto error; \
1163c1e38eaSMarcel Moolenaar }
1173c1e38eaSMarcel Moolenaar
118e65421baSDavid Xu #define LOOKUP_VAL(proc, sym, val) \
119e65421baSDavid Xu ret = ps_pglobal_lookup(proc, NULL, sym, &vaddr);\
120e65421baSDavid Xu if (ret != 0) { \
121e65421baSDavid Xu TDBG("can not find symbol: %s\n", sym); \
122e65421baSDavid Xu ret = TD_NOLIBTHREAD; \
123e65421baSDavid Xu goto error; \
124e65421baSDavid Xu } \
125e65421baSDavid Xu ret = ps_pread(proc, vaddr, val, sizeof(int)); \
126e65421baSDavid Xu if (ret != 0) { \
127e65421baSDavid Xu TDBG("can not read value of %s\n", sym);\
128e65421baSDavid Xu ret = TD_NOLIBTHREAD; \
129e65421baSDavid Xu goto error; \
1303c1e38eaSMarcel Moolenaar }
1313c1e38eaSMarcel Moolenaar
1323c1e38eaSMarcel Moolenaar td_thragent_t *ta;
133e65421baSDavid Xu psaddr_t vaddr;
134e65421baSDavid Xu int dbg;
135e65421baSDavid Xu int ret;
1363c1e38eaSMarcel Moolenaar
137e65421baSDavid Xu TDBG_FUNC();
1383c1e38eaSMarcel Moolenaar
1393c1e38eaSMarcel Moolenaar ta = malloc(sizeof(td_thragent_t));
1403c1e38eaSMarcel Moolenaar if (ta == NULL)
1413c1e38eaSMarcel Moolenaar return (TD_MALLOC);
1423c1e38eaSMarcel Moolenaar
143e65421baSDavid Xu ta->ph = ph;
1443c1e38eaSMarcel Moolenaar
145e65421baSDavid Xu LOOKUP_SYM(ph, "_libthr_debug", &ta->libthr_debug_addr);
146e65421baSDavid Xu LOOKUP_SYM(ph, "_thread_list", &ta->thread_list_addr);
147e65421baSDavid Xu LOOKUP_SYM(ph, "_thread_active_threads",&ta->thread_active_threads_addr);
148e65421baSDavid Xu LOOKUP_SYM(ph, "_thread_keytable", &ta->thread_keytable_addr);
149a80845eaSDavid Xu LOOKUP_SYM(ph, "_thread_last_event", &ta->thread_last_event_addr);
150a80845eaSDavid Xu LOOKUP_SYM(ph, "_thread_event_mask", &ta->thread_event_mask_addr);
151a80845eaSDavid Xu LOOKUP_SYM(ph, "_thread_bp_create", &ta->thread_bp_create_addr);
152a80845eaSDavid Xu LOOKUP_SYM(ph, "_thread_bp_death", &ta->thread_bp_death_addr);
153e65421baSDavid Xu LOOKUP_VAL(ph, "_thread_off_dtv", &ta->thread_off_dtv);
154e65421baSDavid Xu LOOKUP_VAL(ph, "_thread_off_tlsindex", &ta->thread_off_tlsindex);
155e65421baSDavid Xu LOOKUP_VAL(ph, "_thread_off_attr_flags", &ta->thread_off_attr_flags);
156e65421baSDavid Xu LOOKUP_VAL(ph, "_thread_size_key", &ta->thread_size_key);
157e65421baSDavid Xu LOOKUP_VAL(ph, "_thread_off_tcb", &ta->thread_off_tcb);
158e65421baSDavid Xu LOOKUP_VAL(ph, "_thread_off_tid", &ta->thread_off_tid);
159e65421baSDavid Xu LOOKUP_VAL(ph, "_thread_off_linkmap", &ta->thread_off_linkmap);
160e65421baSDavid Xu LOOKUP_VAL(ph, "_thread_off_next", &ta->thread_off_next);
161e65421baSDavid Xu LOOKUP_VAL(ph, "_thread_off_state", &ta->thread_off_state);
162e65421baSDavid Xu LOOKUP_VAL(ph, "_thread_max_keys", &ta->thread_max_keys);
163e65421baSDavid Xu LOOKUP_VAL(ph, "_thread_off_key_allocated", &ta->thread_off_key_allocated);
164e65421baSDavid Xu LOOKUP_VAL(ph, "_thread_off_key_destructor", &ta->thread_off_key_destructor);
165e65421baSDavid Xu LOOKUP_VAL(ph, "_thread_state_running", &ta->thread_state_running);
166e65421baSDavid Xu LOOKUP_VAL(ph, "_thread_state_zoombie", &ta->thread_state_zoombie);
167a80845eaSDavid Xu LOOKUP_VAL(ph, "_thread_off_report_events", &ta->thread_off_report_events);
168a80845eaSDavid Xu LOOKUP_VAL(ph, "_thread_off_event_mask", &ta->thread_off_event_mask);
169a80845eaSDavid Xu LOOKUP_VAL(ph, "_thread_off_event_buf", &ta->thread_off_event_buf);
170e65421baSDavid Xu dbg = getpid();
171e65421baSDavid Xu /*
172e65421baSDavid Xu * If this fails it probably means we're debugging a core file and
173e65421baSDavid Xu * can't write to it.
174e65421baSDavid Xu */
175e65421baSDavid Xu ps_pwrite(ph, ta->libthr_debug_addr, &dbg, sizeof(int));
176e65421baSDavid Xu *pta = ta;
177e65421baSDavid Xu return (0);
1783c1e38eaSMarcel Moolenaar
179e65421baSDavid Xu error:
1803c1e38eaSMarcel Moolenaar free(ta);
181e65421baSDavid Xu return (ret);
1823c1e38eaSMarcel Moolenaar }
1833c1e38eaSMarcel Moolenaar
1843c1e38eaSMarcel Moolenaar static td_err_e
pt_ta_delete(td_thragent_t * ta)185e65421baSDavid Xu pt_ta_delete(td_thragent_t *ta)
1863c1e38eaSMarcel Moolenaar {
187e65421baSDavid Xu int dbg;
188e65421baSDavid Xu
189e65421baSDavid Xu TDBG_FUNC();
190e65421baSDavid Xu
191e65421baSDavid Xu dbg = 0;
192e65421baSDavid Xu /*
193e65421baSDavid Xu * Error returns from this write are not really a problem;
194e65421baSDavid Xu * the process doesn't exist any more.
195e65421baSDavid Xu */
196e65421baSDavid Xu ps_pwrite(ta->ph, ta->libthr_debug_addr, &dbg, sizeof(int));
197e65421baSDavid Xu free(ta);
198e65421baSDavid Xu return (TD_OK);
1993c1e38eaSMarcel Moolenaar }
2003c1e38eaSMarcel Moolenaar
2013c1e38eaSMarcel Moolenaar static td_err_e
pt_ta_map_id2thr(const td_thragent_t * ta,thread_t id,td_thrhandle_t * th)202e65421baSDavid Xu pt_ta_map_id2thr(const td_thragent_t *ta, thread_t id, td_thrhandle_t *th)
2033c1e38eaSMarcel Moolenaar {
204e65421baSDavid Xu psaddr_t pt;
205ef6f47c4SMarius Strobl int64_t lwp;
206787e88a3SDavid Xu int ret;
207e65421baSDavid Xu
208e65421baSDavid Xu TDBG_FUNC();
209e65421baSDavid Xu
210787e88a3SDavid Xu if (id == 0)
211e65421baSDavid Xu return (TD_NOTHR);
21203fad2adSMarcel Moolenaar ret = thr_pread_ptr(ta, ta->thread_list_addr, &pt);
213e65421baSDavid Xu if (ret != 0)
21403fad2adSMarcel Moolenaar return (TD_ERR);
215787e88a3SDavid Xu /* Iterate through thread list to find pthread */
21616b0c20cSMarcel Moolenaar while (pt != 0) {
217e31fe879SMarius Strobl ret = thr_pread_long(ta, pt + ta->thread_off_tid, &lwp);
218787e88a3SDavid Xu if (ret != 0)
21903fad2adSMarcel Moolenaar return (TD_ERR);
220787e88a3SDavid Xu if (lwp == id)
221787e88a3SDavid Xu break;
222e65421baSDavid Xu /* get next thread */
22303fad2adSMarcel Moolenaar ret = thr_pread_ptr(ta, pt + ta->thread_off_next, &pt);
224e65421baSDavid Xu if (ret != 0)
22503fad2adSMarcel Moolenaar return (TD_ERR);
226e65421baSDavid Xu }
22716b0c20cSMarcel Moolenaar if (pt == 0)
228e65421baSDavid Xu return (TD_NOTHR);
229e65421baSDavid Xu th->th_ta = ta;
230e65421baSDavid Xu th->th_tid = id;
2312ec2da86SDavid Xu th->th_thread = pt;
232e65421baSDavid Xu return (TD_OK);
233e65421baSDavid Xu }
234e65421baSDavid Xu
235e65421baSDavid Xu static td_err_e
pt_ta_map_lwp2thr(const td_thragent_t * ta,lwpid_t lwp,td_thrhandle_t * th)236e65421baSDavid Xu pt_ta_map_lwp2thr(const td_thragent_t *ta, lwpid_t lwp, td_thrhandle_t *th)
237e65421baSDavid Xu {
238787e88a3SDavid Xu return (pt_ta_map_id2thr(ta, lwp, th));
239e65421baSDavid Xu }
240e65421baSDavid Xu
241e65421baSDavid Xu 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)242f60a5b31SMarcel Moolenaar pt_ta_thr_iter(const td_thragent_t *ta, td_thr_iter_f *callback,
243f60a5b31SMarcel Moolenaar void *cbdata_p, td_thr_state_e state __unused, int ti_pri __unused,
244f60a5b31SMarcel Moolenaar sigset_t *ti_sigmask_p __unused, unsigned int ti_user_flags __unused)
245e65421baSDavid Xu {
2463c1e38eaSMarcel Moolenaar td_thrhandle_t th;
247e65421baSDavid Xu psaddr_t pt;
248ef6f47c4SMarius Strobl int64_t lwp;
249787e88a3SDavid Xu int ret;
2503c1e38eaSMarcel Moolenaar
251e65421baSDavid Xu TDBG_FUNC();
252e65421baSDavid Xu
25303fad2adSMarcel Moolenaar ret = thr_pread_ptr(ta, ta->thread_list_addr, &pt);
254e65421baSDavid Xu if (ret != 0)
25503fad2adSMarcel Moolenaar return (TD_ERR);
256e65421baSDavid Xu while (pt != 0) {
257e31fe879SMarius Strobl ret = thr_pread_long(ta, pt + ta->thread_off_tid, &lwp);
258e65421baSDavid Xu if (ret != 0)
25903fad2adSMarcel Moolenaar return (TD_ERR);
260787e88a3SDavid Xu if (lwp != 0 && lwp != TERMINATED) {
2613c1e38eaSMarcel Moolenaar th.th_ta = ta;
262787e88a3SDavid Xu th.th_tid = (thread_t)lwp;
2632ec2da86SDavid Xu th.th_thread = pt;
264e65421baSDavid Xu if ((*callback)(&th, cbdata_p))
265e65421baSDavid Xu return (TD_DBERR);
266e65421baSDavid Xu }
267e65421baSDavid Xu /* get next thread */
26803fad2adSMarcel Moolenaar ret = thr_pread_ptr(ta, pt + ta->thread_off_next, &pt);
269e65421baSDavid Xu if (ret != 0)
27003fad2adSMarcel Moolenaar return (TD_ERR);
2713c1e38eaSMarcel Moolenaar }
2723c1e38eaSMarcel Moolenaar return (TD_OK);
2733c1e38eaSMarcel Moolenaar }
2743c1e38eaSMarcel Moolenaar
2753c1e38eaSMarcel Moolenaar static td_err_e
pt_ta_tsd_iter(const td_thragent_t * ta,td_key_iter_f * ki,void * arg)276e65421baSDavid Xu pt_ta_tsd_iter(const td_thragent_t *ta, td_key_iter_f *ki, void *arg)
2773c1e38eaSMarcel Moolenaar {
278f60a5b31SMarcel Moolenaar void *keytable;
279e65421baSDavid Xu void *destructor;
280e65421baSDavid Xu int i, ret, allocated;
281e65421baSDavid Xu
282e65421baSDavid Xu TDBG_FUNC();
283e65421baSDavid Xu
284e65421baSDavid Xu keytable = malloc(ta->thread_max_keys * ta->thread_size_key);
285e65421baSDavid Xu if (keytable == NULL)
286e65421baSDavid Xu return (TD_MALLOC);
287e65421baSDavid Xu ret = ps_pread(ta->ph, (psaddr_t)ta->thread_keytable_addr, keytable,
288e65421baSDavid Xu ta->thread_max_keys * ta->thread_size_key);
289e65421baSDavid Xu if (ret != 0) {
290e65421baSDavid Xu free(keytable);
291e65421baSDavid Xu return (P2T(ret));
292e65421baSDavid Xu }
293e65421baSDavid Xu for (i = 0; i < ta->thread_max_keys; i++) {
294f60a5b31SMarcel Moolenaar allocated = *(int *)(void *)((uintptr_t)keytable +
295f60a5b31SMarcel Moolenaar i * ta->thread_size_key + ta->thread_off_key_allocated);
296f60a5b31SMarcel Moolenaar destructor = *(void **)(void *)((uintptr_t)keytable +
297f60a5b31SMarcel Moolenaar i * ta->thread_size_key + ta->thread_off_key_destructor);
298e65421baSDavid Xu if (allocated) {
299e65421baSDavid Xu ret = (ki)(i, destructor, arg);
300e65421baSDavid Xu if (ret != 0) {
301e65421baSDavid Xu free(keytable);
302e65421baSDavid Xu return (TD_DBERR);
303e65421baSDavid Xu }
304e65421baSDavid Xu }
305e65421baSDavid Xu }
306e65421baSDavid Xu free(keytable);
307e65421baSDavid Xu return (TD_OK);
308e65421baSDavid Xu }
309e65421baSDavid Xu
310e65421baSDavid Xu static td_err_e
pt_ta_event_addr(const td_thragent_t * ta,td_event_e event,td_notify_t * ptr)311e65421baSDavid Xu pt_ta_event_addr(const td_thragent_t *ta, td_event_e event, td_notify_t *ptr)
312e65421baSDavid Xu {
313787e88a3SDavid Xu
314e65421baSDavid Xu TDBG_FUNC();
315a80845eaSDavid Xu
316a80845eaSDavid Xu switch (event) {
317a80845eaSDavid Xu case TD_CREATE:
318a80845eaSDavid Xu ptr->type = NOTIFY_BPT;
319a80845eaSDavid Xu ptr->u.bptaddr = ta->thread_bp_create_addr;
320a80845eaSDavid Xu return (0);
321a80845eaSDavid Xu case TD_DEATH:
322a80845eaSDavid Xu ptr->type = NOTIFY_BPT;
323a80845eaSDavid Xu ptr->u.bptaddr = ta->thread_bp_death_addr;
324a80845eaSDavid Xu return (0);
325a80845eaSDavid Xu default:
326a80845eaSDavid Xu return (TD_ERR);
327a80845eaSDavid Xu }
328e65421baSDavid Xu }
329e65421baSDavid Xu
330e65421baSDavid Xu static td_err_e
pt_ta_set_event(const td_thragent_t * ta,td_thr_events_t * events)331e65421baSDavid Xu pt_ta_set_event(const td_thragent_t *ta, td_thr_events_t *events)
332e65421baSDavid Xu {
333a80845eaSDavid Xu td_thr_events_t mask;
334787e88a3SDavid Xu int ret;
335a80845eaSDavid Xu
336e65421baSDavid Xu TDBG_FUNC();
337a80845eaSDavid Xu ret = ps_pread(ta->ph, ta->thread_event_mask_addr, &mask,
338a80845eaSDavid Xu sizeof(mask));
339a80845eaSDavid Xu if (ret != 0)
340a80845eaSDavid Xu return (P2T(ret));
341a80845eaSDavid Xu mask |= *events;
342a80845eaSDavid Xu ret = ps_pwrite(ta->ph, ta->thread_event_mask_addr, &mask,
343a80845eaSDavid Xu sizeof(mask));
344a80845eaSDavid Xu return (P2T(ret));
3453c1e38eaSMarcel Moolenaar }
3463c1e38eaSMarcel Moolenaar
3473c1e38eaSMarcel Moolenaar static td_err_e
pt_ta_clear_event(const td_thragent_t * ta,td_thr_events_t * events)348e65421baSDavid Xu pt_ta_clear_event(const td_thragent_t *ta, td_thr_events_t *events)
349d4ee7126SDavid Xu {
350a80845eaSDavid Xu td_thr_events_t mask;
351787e88a3SDavid Xu int ret;
352a80845eaSDavid Xu
353e65421baSDavid Xu TDBG_FUNC();
354a80845eaSDavid Xu ret = ps_pread(ta->ph, ta->thread_event_mask_addr, &mask,
355a80845eaSDavid Xu sizeof(mask));
356a80845eaSDavid Xu if (ret != 0)
357a80845eaSDavid Xu return (P2T(ret));
358a80845eaSDavid Xu mask &= ~*events;
359a80845eaSDavid Xu ret = ps_pwrite(ta->ph, ta->thread_event_mask_addr, &mask,
360a80845eaSDavid Xu sizeof(mask));
361a80845eaSDavid Xu return (P2T(ret));
3623c1e38eaSMarcel Moolenaar }
3633c1e38eaSMarcel Moolenaar
3643c1e38eaSMarcel Moolenaar static td_err_e
pt_ta_event_getmsg(const td_thragent_t * ta,td_event_msg_t * msg)365e65421baSDavid Xu pt_ta_event_getmsg(const td_thragent_t *ta, td_event_msg_t *msg)
3663c1e38eaSMarcel Moolenaar {
367a80845eaSDavid Xu static td_thrhandle_t handle;
368a80845eaSDavid Xu
36903fad2adSMarcel Moolenaar psaddr_t pt;
370787e88a3SDavid Xu td_thr_events_e tmp;
371ef6f47c4SMarius Strobl int64_t lwp;
372a80845eaSDavid Xu int ret;
373a80845eaSDavid Xu
374e65421baSDavid Xu TDBG_FUNC();
375a80845eaSDavid Xu
37603fad2adSMarcel Moolenaar ret = thr_pread_ptr(ta, ta->thread_last_event_addr, &pt);
377a80845eaSDavid Xu if (ret != 0)
37803fad2adSMarcel Moolenaar return (TD_ERR);
37916b0c20cSMarcel Moolenaar if (pt == 0)
380e65421baSDavid Xu return (TD_NOMSG);
381787e88a3SDavid Xu /*
382787e88a3SDavid Xu * Take the event pointer, at the time, libthr only reports event
383787e88a3SDavid Xu * once a time, so it is not a link list.
384787e88a3SDavid Xu */
38503fad2adSMarcel Moolenaar thr_pwrite_ptr(ta, ta->thread_last_event_addr, 0);
386a80845eaSDavid Xu
387787e88a3SDavid Xu /* Read event info */
388a80845eaSDavid Xu ret = ps_pread(ta->ph, pt + ta->thread_off_event_buf, msg, sizeof(*msg));
389a80845eaSDavid Xu if (ret != 0)
390a80845eaSDavid Xu return (P2T(ret));
391a80845eaSDavid Xu if (msg->event == 0)
392a80845eaSDavid Xu return (TD_NOMSG);
393787e88a3SDavid Xu /* Clear event */
394a80845eaSDavid Xu tmp = 0;
395a80845eaSDavid Xu ps_pwrite(ta->ph, pt + ta->thread_off_event_buf, &tmp, sizeof(tmp));
396787e88a3SDavid Xu /* Convert event */
39703fad2adSMarcel Moolenaar pt = msg->th_p;
398e31fe879SMarius Strobl ret = thr_pread_long(ta, pt + ta->thread_off_tid, &lwp);
399a80845eaSDavid Xu if (ret != 0)
40003fad2adSMarcel Moolenaar return (TD_ERR);
401a80845eaSDavid Xu handle.th_ta = ta;
402787e88a3SDavid Xu handle.th_tid = lwp;
403a80845eaSDavid Xu handle.th_thread = pt;
40403fad2adSMarcel Moolenaar msg->th_p = (uintptr_t)&handle;
405a80845eaSDavid Xu return (0);
406e65421baSDavid Xu }
407e65421baSDavid Xu
408e65421baSDavid Xu static td_err_e
pt_dbsuspend(const td_thrhandle_t * th,int suspend)409e65421baSDavid Xu pt_dbsuspend(const td_thrhandle_t *th, int suspend)
410e65421baSDavid Xu {
411f60a5b31SMarcel Moolenaar const td_thragent_t *ta = th->th_ta;
412e65421baSDavid Xu int ret;
413e65421baSDavid Xu
414e65421baSDavid Xu TDBG_FUNC();
415e65421baSDavid Xu
416e65421baSDavid Xu ret = pt_validate(th);
417e65421baSDavid Xu if (ret)
418e65421baSDavid Xu return (ret);
419e65421baSDavid Xu
420e65421baSDavid Xu if (suspend)
421787e88a3SDavid Xu ret = ps_lstop(ta->ph, th->th_tid);
422e65421baSDavid Xu else
423787e88a3SDavid Xu ret = ps_lcontinue(ta->ph, th->th_tid);
424e65421baSDavid Xu return (P2T(ret));
425e65421baSDavid Xu }
426e65421baSDavid Xu
427e65421baSDavid Xu static td_err_e
pt_thr_dbresume(const td_thrhandle_t * th)428e65421baSDavid Xu pt_thr_dbresume(const td_thrhandle_t *th)
429e65421baSDavid Xu {
430e65421baSDavid Xu TDBG_FUNC();
431e65421baSDavid Xu
432e65421baSDavid Xu return pt_dbsuspend(th, 0);
433e65421baSDavid Xu }
434e65421baSDavid Xu
435e65421baSDavid Xu static td_err_e
pt_thr_dbsuspend(const td_thrhandle_t * th)436e65421baSDavid Xu pt_thr_dbsuspend(const td_thrhandle_t *th)
437e65421baSDavid Xu {
438e65421baSDavid Xu TDBG_FUNC();
439e65421baSDavid Xu
440e65421baSDavid Xu return pt_dbsuspend(th, 1);
441e65421baSDavid Xu }
442e65421baSDavid Xu
443e65421baSDavid Xu static td_err_e
pt_thr_validate(const td_thrhandle_t * th)444e65421baSDavid Xu pt_thr_validate(const td_thrhandle_t *th)
445e65421baSDavid Xu {
446e65421baSDavid Xu td_thrhandle_t temp;
447e65421baSDavid Xu int ret;
448e65421baSDavid Xu
449e65421baSDavid Xu TDBG_FUNC();
450e65421baSDavid Xu
451787e88a3SDavid Xu ret = pt_ta_map_id2thr(th->th_ta, th->th_tid, &temp);
452e65421baSDavid Xu return (ret);
453e65421baSDavid Xu }
454e65421baSDavid Xu
455e65421baSDavid Xu static td_err_e
pt_thr_get_info_common(const td_thrhandle_t * th,td_thrinfo_t * info,int old)456098d0537SKonstantin Belousov pt_thr_get_info_common(const td_thrhandle_t *th, td_thrinfo_t *info, int old)
457e65421baSDavid Xu {
458e65421baSDavid Xu const td_thragent_t *ta = th->th_ta;
4594f7b0f0eSDavid Xu struct ptrace_lwpinfo linfo;
46018860a1cSDag-Erling Smørgrav int traceme;
461e65421baSDavid Xu int state;
462e65421baSDavid Xu int ret;
463e65421baSDavid Xu
464e65421baSDavid Xu TDBG_FUNC();
465e65421baSDavid Xu
46683154c48SDavid Xu bzero(info, sizeof(*info));
467e65421baSDavid Xu ret = pt_validate(th);
468e65421baSDavid Xu if (ret)
469e65421baSDavid Xu return (ret);
47003fad2adSMarcel Moolenaar ret = thr_pread_int(ta, th->th_thread + ta->thread_off_state, &state);
471e65421baSDavid Xu if (ret != 0)
47203fad2adSMarcel Moolenaar return (TD_ERR);
47303fad2adSMarcel Moolenaar ret = thr_pread_int(ta, th->th_thread + ta->thread_off_report_events,
47418860a1cSDag-Erling Smørgrav &traceme);
47518860a1cSDag-Erling Smørgrav info->ti_traceme = traceme;
476b9da3fd7SDavid Xu if (ret != 0)
47703fad2adSMarcel Moolenaar return (TD_ERR);
478787e88a3SDavid Xu ret = ps_pread(ta->ph, th->th_thread + ta->thread_off_event_mask,
479b9da3fd7SDavid Xu &info->ti_events, sizeof(td_thr_events_t));
480b9da3fd7SDavid Xu if (ret != 0)
481b9da3fd7SDavid Xu return (P2T(ret));
482787e88a3SDavid Xu ret = ps_pread(ta->ph, th->th_thread + ta->thread_off_tcb,
483787e88a3SDavid Xu &info->ti_tls, sizeof(void *));
484787e88a3SDavid Xu info->ti_lid = th->th_tid;
485e65421baSDavid Xu info->ti_tid = th->th_tid;
486787e88a3SDavid Xu info->ti_thread = th->th_thread;
487e65421baSDavid Xu info->ti_ta_p = th->th_ta;
4884f7b0f0eSDavid Xu ret = ps_linfo(ta->ph, th->th_tid, &linfo);
4894f7b0f0eSDavid Xu if (ret == PS_OK) {
4904f7b0f0eSDavid Xu info->ti_sigmask = linfo.pl_sigmask;
4914f7b0f0eSDavid Xu info->ti_pending = linfo.pl_siglist;
492098d0537SKonstantin Belousov if (!old) {
493098d0537SKonstantin Belousov if ((linfo.pl_flags & PL_FLAG_SI) != 0)
494098d0537SKonstantin Belousov info->ti_siginfo = linfo.pl_siginfo;
495098d0537SKonstantin Belousov else
496098d0537SKonstantin Belousov bzero(&info->ti_siginfo,
497098d0537SKonstantin Belousov sizeof(info->ti_siginfo));
498098d0537SKonstantin Belousov }
499ef39743bSDavid Xu } else
500ef39743bSDavid Xu return (ret);
501e65421baSDavid Xu if (state == ta->thread_state_running)
502e65421baSDavid Xu info->ti_state = TD_THR_RUN;
503e65421baSDavid Xu else if (state == ta->thread_state_zoombie)
504e65421baSDavid Xu info->ti_state = TD_THR_ZOMBIE;
505e65421baSDavid Xu else
506e65421baSDavid Xu info->ti_state = TD_THR_SLEEP;
507e65421baSDavid Xu info->ti_type = TD_THR_USER;
508e65421baSDavid Xu return (0);
509e65421baSDavid Xu }
510e65421baSDavid Xu
511098d0537SKonstantin Belousov static td_err_e
pt_thr_old_get_info(const td_thrhandle_t * th,td_old_thrinfo_t * info)512098d0537SKonstantin Belousov pt_thr_old_get_info(const td_thrhandle_t *th, td_old_thrinfo_t *info)
513098d0537SKonstantin Belousov {
514098d0537SKonstantin Belousov
515098d0537SKonstantin Belousov return (pt_thr_get_info_common(th, (td_thrinfo_t *)info, 1));
516098d0537SKonstantin Belousov }
517098d0537SKonstantin Belousov
518098d0537SKonstantin Belousov static td_err_e
pt_thr_get_info(const td_thrhandle_t * th,td_thrinfo_t * info)519098d0537SKonstantin Belousov pt_thr_get_info(const td_thrhandle_t *th, td_thrinfo_t *info)
520098d0537SKonstantin Belousov {
521098d0537SKonstantin Belousov
522098d0537SKonstantin Belousov return (pt_thr_get_info_common(th, info, 0));
523098d0537SKonstantin Belousov }
524098d0537SKonstantin Belousov
5258d7681bbSDoug Rabson #ifdef __i386__
5268d7681bbSDoug Rabson static td_err_e
pt_thr_getxmmregs(const td_thrhandle_t * th,char * fxsave)5278d7681bbSDoug Rabson pt_thr_getxmmregs(const td_thrhandle_t *th, char *fxsave)
5288d7681bbSDoug Rabson {
5298d7681bbSDoug Rabson const td_thragent_t *ta = th->th_ta;
5308d7681bbSDoug Rabson int ret;
5318d7681bbSDoug Rabson
5328d7681bbSDoug Rabson TDBG_FUNC();
5338d7681bbSDoug Rabson
5348d7681bbSDoug Rabson ret = pt_validate(th);
5358d7681bbSDoug Rabson if (ret)
5368d7681bbSDoug Rabson return (ret);
5378d7681bbSDoug Rabson
5388d7681bbSDoug Rabson ret = ps_lgetxmmregs(ta->ph, th->th_tid, fxsave);
5398d7681bbSDoug Rabson return (P2T(ret));
5408d7681bbSDoug Rabson }
5418d7681bbSDoug Rabson #endif
5428d7681bbSDoug Rabson
543e65421baSDavid Xu static td_err_e
pt_thr_getfpregs(const td_thrhandle_t * th,prfpregset_t * fpregs)544e65421baSDavid Xu pt_thr_getfpregs(const td_thrhandle_t *th, prfpregset_t *fpregs)
545e65421baSDavid Xu {
546e65421baSDavid Xu const td_thragent_t *ta = th->th_ta;
547e65421baSDavid Xu int ret;
548e65421baSDavid Xu
549e65421baSDavid Xu TDBG_FUNC();
550e65421baSDavid Xu
551e65421baSDavid Xu ret = pt_validate(th);
552e65421baSDavid Xu if (ret)
553e65421baSDavid Xu return (ret);
554e65421baSDavid Xu
555787e88a3SDavid Xu ret = ps_lgetfpregs(ta->ph, th->th_tid, fpregs);
556e65421baSDavid Xu return (P2T(ret));
557e65421baSDavid Xu }
558e65421baSDavid Xu
559e65421baSDavid Xu static td_err_e
pt_thr_getgregs(const td_thrhandle_t * th,prgregset_t gregs)560e65421baSDavid Xu pt_thr_getgregs(const td_thrhandle_t *th, prgregset_t gregs)
561e65421baSDavid Xu {
562e65421baSDavid Xu const td_thragent_t *ta = th->th_ta;
563e65421baSDavid Xu int ret;
564e65421baSDavid Xu
565e65421baSDavid Xu TDBG_FUNC();
566e65421baSDavid Xu
567e65421baSDavid Xu ret = pt_validate(th);
568e65421baSDavid Xu if (ret)
569e65421baSDavid Xu return (ret);
570e65421baSDavid Xu
571787e88a3SDavid Xu ret = ps_lgetregs(ta->ph, th->th_tid, gregs);
572e65421baSDavid Xu return (P2T(ret));
573e65421baSDavid Xu }
574e65421baSDavid Xu
5758d7681bbSDoug Rabson #ifdef __i386__
5768d7681bbSDoug Rabson static td_err_e
pt_thr_setxmmregs(const td_thrhandle_t * th,const char * fxsave)5778d7681bbSDoug Rabson pt_thr_setxmmregs(const td_thrhandle_t *th, const char *fxsave)
5788d7681bbSDoug Rabson {
5798d7681bbSDoug Rabson const td_thragent_t *ta = th->th_ta;
5808d7681bbSDoug Rabson int ret;
5818d7681bbSDoug Rabson
5828d7681bbSDoug Rabson TDBG_FUNC();
5838d7681bbSDoug Rabson
5848d7681bbSDoug Rabson ret = pt_validate(th);
5858d7681bbSDoug Rabson if (ret)
5868d7681bbSDoug Rabson return (ret);
5878d7681bbSDoug Rabson
5888d7681bbSDoug Rabson ret = ps_lsetxmmregs(ta->ph, th->th_tid, fxsave);
5898d7681bbSDoug Rabson return (P2T(ret));
5908d7681bbSDoug Rabson }
5918d7681bbSDoug Rabson #endif
5928d7681bbSDoug Rabson
593e65421baSDavid Xu static td_err_e
pt_thr_setfpregs(const td_thrhandle_t * th,const prfpregset_t * fpregs)594e65421baSDavid Xu pt_thr_setfpregs(const td_thrhandle_t *th, const prfpregset_t *fpregs)
595e65421baSDavid Xu {
596e65421baSDavid Xu const td_thragent_t *ta = th->th_ta;
597e65421baSDavid Xu int ret;
598e65421baSDavid Xu
599e65421baSDavid Xu TDBG_FUNC();
600e65421baSDavid Xu
601e65421baSDavid Xu ret = pt_validate(th);
602e65421baSDavid Xu if (ret)
603e65421baSDavid Xu return (ret);
604e65421baSDavid Xu
605787e88a3SDavid Xu ret = ps_lsetfpregs(ta->ph, th->th_tid, fpregs);
606e65421baSDavid Xu return (P2T(ret));
607e65421baSDavid Xu }
608e65421baSDavid Xu
609e65421baSDavid Xu static td_err_e
pt_thr_setgregs(const td_thrhandle_t * th,const prgregset_t gregs)610e65421baSDavid Xu pt_thr_setgregs(const td_thrhandle_t *th, const prgregset_t gregs)
611e65421baSDavid Xu {
612e65421baSDavid Xu const td_thragent_t *ta = th->th_ta;
613e65421baSDavid Xu int ret;
614e65421baSDavid Xu
615e65421baSDavid Xu TDBG_FUNC();
616e65421baSDavid Xu
617e65421baSDavid Xu ret = pt_validate(th);
618e65421baSDavid Xu if (ret)
619e65421baSDavid Xu return (ret);
620e65421baSDavid Xu
621787e88a3SDavid Xu ret = ps_lsetregs(ta->ph, th->th_tid, gregs);
622e65421baSDavid Xu return (P2T(ret));
623e65421baSDavid Xu }
624e65421baSDavid Xu
625e65421baSDavid Xu static td_err_e
pt_thr_event_enable(const td_thrhandle_t * th,int en)626e65421baSDavid Xu pt_thr_event_enable(const td_thrhandle_t *th, int en)
627e65421baSDavid Xu {
628a80845eaSDavid Xu const td_thragent_t *ta = th->th_ta;
629a80845eaSDavid Xu int ret;
630a80845eaSDavid Xu
631e65421baSDavid Xu TDBG_FUNC();
632a80845eaSDavid Xu ret = ps_pwrite(ta->ph, th->th_thread + ta->thread_off_report_events,
633a80845eaSDavid Xu &en, sizeof(int));
634a80845eaSDavid Xu return (P2T(ret));
6353c1e38eaSMarcel Moolenaar }
6363c1e38eaSMarcel Moolenaar
6373c1e38eaSMarcel Moolenaar static td_err_e
pt_thr_set_event(const td_thrhandle_t * th,td_thr_events_t * setp)638e65421baSDavid Xu pt_thr_set_event(const td_thrhandle_t *th, td_thr_events_t *setp)
6393c1e38eaSMarcel Moolenaar {
640a80845eaSDavid Xu const td_thragent_t *ta = th->th_ta;
641a80845eaSDavid Xu td_thr_events_t mask;
642a80845eaSDavid Xu int ret;
643a80845eaSDavid Xu
644e65421baSDavid Xu TDBG_FUNC();
645a80845eaSDavid Xu ret = ps_pread(ta->ph, th->th_thread + ta->thread_off_event_mask,
646a80845eaSDavid Xu &mask, sizeof(mask));
647a80845eaSDavid Xu mask |= *setp;
648a80845eaSDavid Xu ret = ps_pwrite(ta->ph, th->th_thread + ta->thread_off_event_mask,
649a80845eaSDavid Xu &mask, sizeof(mask));
650a80845eaSDavid Xu return (P2T(ret));
6513c1e38eaSMarcel Moolenaar }
6523c1e38eaSMarcel Moolenaar
6533c1e38eaSMarcel Moolenaar static td_err_e
pt_thr_clear_event(const td_thrhandle_t * th,td_thr_events_t * setp)654e65421baSDavid Xu pt_thr_clear_event(const td_thrhandle_t *th, td_thr_events_t *setp)
6553c1e38eaSMarcel Moolenaar {
656a80845eaSDavid Xu const td_thragent_t *ta = th->th_ta;
657a80845eaSDavid Xu td_thr_events_t mask;
658a80845eaSDavid Xu int ret;
659a80845eaSDavid Xu
660e65421baSDavid Xu TDBG_FUNC();
661a80845eaSDavid Xu ret = ps_pread(ta->ph, th->th_thread + ta->thread_off_event_mask,
662a80845eaSDavid Xu &mask, sizeof(mask));
663a80845eaSDavid Xu mask &= ~*setp;
664a80845eaSDavid Xu ret = ps_pwrite(ta->ph, th->th_thread + ta->thread_off_event_mask,
665a80845eaSDavid Xu &mask, sizeof(mask));
666a80845eaSDavid Xu return (P2T(ret));
6673c1e38eaSMarcel Moolenaar }
6683c1e38eaSMarcel Moolenaar
669d4ee7126SDavid Xu static td_err_e
pt_thr_event_getmsg(const td_thrhandle_t * th,td_event_msg_t * msg)670e65421baSDavid Xu pt_thr_event_getmsg(const td_thrhandle_t *th, td_event_msg_t *msg)
671d4ee7126SDavid Xu {
672a80845eaSDavid Xu static td_thrhandle_t handle;
673f60a5b31SMarcel Moolenaar const td_thragent_t *ta = th->th_ta;
674a80845eaSDavid Xu psaddr_t pt, pt_temp;
675ef6f47c4SMarius Strobl int64_t lwp;
676a80845eaSDavid Xu int ret;
677a80845eaSDavid Xu td_thr_events_e tmp;
678a80845eaSDavid Xu
679e65421baSDavid Xu TDBG_FUNC();
680a80845eaSDavid Xu pt = th->th_thread;
68103fad2adSMarcel Moolenaar ret = thr_pread_ptr(ta, ta->thread_last_event_addr, &pt_temp);
682a80845eaSDavid Xu if (ret != 0)
68303fad2adSMarcel Moolenaar return (TD_ERR);
684787e88a3SDavid Xu /* Get event */
685a80845eaSDavid Xu ret = ps_pread(ta->ph, pt + ta->thread_off_event_buf, msg, sizeof(*msg));
686a80845eaSDavid Xu if (ret != 0)
687a80845eaSDavid Xu return (P2T(ret));
688a80845eaSDavid Xu if (msg->event == 0)
689e65421baSDavid Xu return (TD_NOMSG);
690787e88a3SDavid Xu /*
691787e88a3SDavid Xu * Take the event pointer, at the time, libthr only reports event
692787e88a3SDavid Xu * once a time, so it is not a link list.
693787e88a3SDavid Xu */
69403fad2adSMarcel Moolenaar if (pt == pt_temp)
69503fad2adSMarcel Moolenaar thr_pwrite_ptr(ta, ta->thread_last_event_addr, 0);
69603fad2adSMarcel Moolenaar
697787e88a3SDavid Xu /* Clear event */
698a80845eaSDavid Xu tmp = 0;
699a80845eaSDavid Xu ps_pwrite(ta->ph, pt + ta->thread_off_event_buf, &tmp, sizeof(tmp));
700787e88a3SDavid Xu /* Convert event */
70103fad2adSMarcel Moolenaar pt = msg->th_p;
702e31fe879SMarius Strobl ret = thr_pread_long(ta, pt + ta->thread_off_tid, &lwp);
703a80845eaSDavid Xu if (ret != 0)
70403fad2adSMarcel Moolenaar return (TD_ERR);
705a80845eaSDavid Xu handle.th_ta = ta;
706787e88a3SDavid Xu handle.th_tid = lwp;
707a80845eaSDavid Xu handle.th_thread = pt;
70803fad2adSMarcel Moolenaar msg->th_p = (uintptr_t)&handle;
709a80845eaSDavid Xu return (0);
710e65421baSDavid Xu }
711e65421baSDavid Xu
712e65421baSDavid Xu static td_err_e
pt_thr_sstep(const td_thrhandle_t * th,int step __unused)713f60a5b31SMarcel Moolenaar pt_thr_sstep(const td_thrhandle_t *th, int step __unused)
714e65421baSDavid Xu {
715e65421baSDavid Xu TDBG_FUNC();
716e65421baSDavid Xu
717787e88a3SDavid Xu return pt_validate(th);
718e65421baSDavid Xu }
719e65421baSDavid Xu
720e65421baSDavid Xu static int
pt_validate(const td_thrhandle_t * th)721e65421baSDavid Xu pt_validate(const td_thrhandle_t *th)
722e65421baSDavid Xu {
723e65421baSDavid Xu
72416b0c20cSMarcel Moolenaar if (th->th_tid == 0 || th->th_thread == 0)
725787e88a3SDavid Xu return (TD_ERR);
726e65421baSDavid Xu return (TD_OK);
727e65421baSDavid Xu }
728e65421baSDavid Xu
729e65421baSDavid Xu static td_err_e
pt_thr_tls_get_addr(const td_thrhandle_t * th,psaddr_t _linkmap,size_t offset,psaddr_t * address)73016b0c20cSMarcel Moolenaar pt_thr_tls_get_addr(const td_thrhandle_t *th, psaddr_t _linkmap, size_t offset,
73116b0c20cSMarcel Moolenaar psaddr_t *address)
732e65421baSDavid Xu {
733e65421baSDavid Xu const td_thragent_t *ta = th->th_ta;
73416b0c20cSMarcel Moolenaar psaddr_t dtv_addr, obj_entry, tcb_addr;
735e65421baSDavid Xu int tls_index, ret;
736e65421baSDavid Xu
737e65421baSDavid Xu /* linkmap is a member of Obj_Entry */
73816b0c20cSMarcel Moolenaar obj_entry = _linkmap - ta->thread_off_linkmap;
739e65421baSDavid Xu
740e65421baSDavid Xu /* get tlsindex of the object file */
741e65421baSDavid Xu ret = ps_pread(ta->ph,
742e65421baSDavid Xu obj_entry + ta->thread_off_tlsindex,
743e65421baSDavid Xu &tls_index, sizeof(tls_index));
744e65421baSDavid Xu if (ret != 0)
745e65421baSDavid Xu return (P2T(ret));
746e65421baSDavid Xu
747e65421baSDavid Xu /* get thread tcb */
748787e88a3SDavid Xu ret = ps_pread(ta->ph, th->th_thread + ta->thread_off_tcb,
749e65421baSDavid Xu &tcb_addr, sizeof(tcb_addr));
750e65421baSDavid Xu if (ret != 0)
751e65421baSDavid Xu return (P2T(ret));
752e65421baSDavid Xu
753e65421baSDavid Xu /* get dtv array address */
754e65421baSDavid Xu ret = ps_pread(ta->ph, tcb_addr + ta->thread_off_dtv,
755e65421baSDavid Xu &dtv_addr, sizeof(dtv_addr));
756e65421baSDavid Xu if (ret != 0)
757e65421baSDavid Xu return (P2T(ret));
758e65421baSDavid Xu /* now get the object's tls block base address */
75916b0c20cSMarcel Moolenaar ret = ps_pread(ta->ph, dtv_addr + sizeof(void *) * (tls_index+1),
76016b0c20cSMarcel Moolenaar address, sizeof(*address));
761e65421baSDavid Xu if (ret != 0)
762e65421baSDavid Xu return (P2T(ret));
763e65421baSDavid Xu
764e65421baSDavid Xu *address += offset;
765d4ee7126SDavid Xu return (TD_OK);
766d4ee7126SDavid Xu }
767d4ee7126SDavid Xu
768ae824d80SEd Schouten static struct ta_ops libthr_db_ops = {
769e65421baSDavid Xu .to_init = pt_init,
770e65421baSDavid Xu .to_ta_clear_event = pt_ta_clear_event,
771e65421baSDavid Xu .to_ta_delete = pt_ta_delete,
772e65421baSDavid Xu .to_ta_event_addr = pt_ta_event_addr,
773e65421baSDavid Xu .to_ta_event_getmsg = pt_ta_event_getmsg,
774e65421baSDavid Xu .to_ta_map_id2thr = pt_ta_map_id2thr,
775e65421baSDavid Xu .to_ta_map_lwp2thr = pt_ta_map_lwp2thr,
776e65421baSDavid Xu .to_ta_new = pt_ta_new,
777e65421baSDavid Xu .to_ta_set_event = pt_ta_set_event,
778e65421baSDavid Xu .to_ta_thr_iter = pt_ta_thr_iter,
779e65421baSDavid Xu .to_ta_tsd_iter = pt_ta_tsd_iter,
780e65421baSDavid Xu .to_thr_clear_event = pt_thr_clear_event,
781e65421baSDavid Xu .to_thr_dbresume = pt_thr_dbresume,
782e65421baSDavid Xu .to_thr_dbsuspend = pt_thr_dbsuspend,
783e65421baSDavid Xu .to_thr_event_enable = pt_thr_event_enable,
784e65421baSDavid Xu .to_thr_event_getmsg = pt_thr_event_getmsg,
785098d0537SKonstantin Belousov .to_thr_old_get_info = pt_thr_old_get_info,
786e65421baSDavid Xu .to_thr_get_info = pt_thr_get_info,
787e65421baSDavid Xu .to_thr_getfpregs = pt_thr_getfpregs,
788e65421baSDavid Xu .to_thr_getgregs = pt_thr_getgregs,
789e65421baSDavid Xu .to_thr_set_event = pt_thr_set_event,
790e65421baSDavid Xu .to_thr_setfpregs = pt_thr_setfpregs,
791e65421baSDavid Xu .to_thr_setgregs = pt_thr_setgregs,
792e65421baSDavid Xu .to_thr_validate = pt_thr_validate,
793e65421baSDavid Xu .to_thr_tls_get_addr = pt_thr_tls_get_addr,
794d4ee7126SDavid Xu
795d4ee7126SDavid Xu /* FreeBSD specific extensions. */
796e65421baSDavid Xu .to_thr_sstep = pt_thr_sstep,
7978d7681bbSDoug Rabson #ifdef __i386__
7988d7681bbSDoug Rabson .to_thr_getxmmregs = pt_thr_getxmmregs,
7998d7681bbSDoug Rabson .to_thr_setxmmregs = pt_thr_setxmmregs,
8008d7681bbSDoug Rabson #endif
8013c1e38eaSMarcel Moolenaar };
80220b94d80SDavid Xu
80320b94d80SDavid Xu DATA_SET(__ta_ops, libthr_db_ops);
804