1132332Smarcel/*
2132332Smarcel * Copyright (c) 2004 David Xu <davidxu@freebsd.org>
3132332Smarcel * All rights reserved.
4132332Smarcel *
5132332Smarcel * Redistribution and use in source and binary forms, with or without
6132332Smarcel * modification, are permitted provided that the following conditions
7132332Smarcel * are met:
8132332Smarcel * 1. Redistributions of source code must retain the above copyright
9132332Smarcel *    notice, this list of conditions and the following disclaimer.
10132332Smarcel * 2. Redistributions in binary form must reproduce the above copyright
11132332Smarcel *    notice, this list of conditions and the following disclaimer in the
12132332Smarcel *    documentation and/or other materials provided with the distribution.
13132332Smarcel *
14132332Smarcel * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
15132332Smarcel * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
16132332Smarcel * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
17132332Smarcel * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
18132332Smarcel * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
19132332Smarcel * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
20132332Smarcel * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
21132332Smarcel * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
22132332Smarcel * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
23132332Smarcel * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
24132332Smarcel * SUCH DAMAGE.
25132332Smarcel */
26132332Smarcel
27132332Smarcel#include <sys/cdefs.h>
28132332Smarcel__FBSDID("$FreeBSD$");
29132332Smarcel
30132332Smarcel#include <proc_service.h>
31132332Smarcel#include <stddef.h>
32132332Smarcel#include <thread_db.h>
33132332Smarcel#include <unistd.h>
34177490Sdavidxu#include <sys/cdefs.h>
35181065Smarcel#include <sys/endian.h>
36181065Smarcel#include <sys/errno.h>
37177490Sdavidxu#include <sys/linker_set.h>
38132332Smarcel
39132332Smarcel#include "thread_db_int.h"
40132332Smarcel
41132332Smarcelstruct td_thragent
42132332Smarcel{
43132332Smarcel	TD_THRAGENT_FIELDS;
44132332Smarcel};
45132332Smarcel
46132332Smarcelstatic TAILQ_HEAD(, td_thragent) proclist = TAILQ_HEAD_INITIALIZER(proclist);
47132332Smarcel
48177490SdavidxuSET_DECLARE(__ta_ops, struct ta_ops);
49132332Smarcel
50132332Smarceltd_err_e
51132332Smarceltd_init(void)
52132332Smarcel{
53132332Smarcel	td_err_e ret, tmp;
54177490Sdavidxu	struct ta_ops *ops_p, **ops_pp;
55132332Smarcel
56132332Smarcel	ret = 0;
57177490Sdavidxu	SET_FOREACH(ops_pp, __ta_ops) {
58177490Sdavidxu		ops_p = *ops_pp;
59177490Sdavidxu		if (ops_p->to_init != NULL) {
60177490Sdavidxu			tmp = ops_p->to_init();
61132332Smarcel			if (tmp != TD_OK)
62132332Smarcel				ret = tmp;
63132332Smarcel		}
64132332Smarcel	}
65132332Smarcel	return (ret);
66132332Smarcel}
67132332Smarcel
68132332Smarceltd_err_e
69132332Smarceltd_ta_clear_event(const td_thragent_t *ta, td_thr_events_t *events)
70132332Smarcel{
71132332Smarcel	return (ta->ta_ops->to_ta_clear_event(ta, events));
72132332Smarcel}
73132332Smarcel
74132332Smarceltd_err_e
75132332Smarceltd_ta_delete(td_thragent_t *ta)
76132332Smarcel{
77132332Smarcel	TAILQ_REMOVE(&proclist, ta, ta_next);
78132332Smarcel	return (ta->ta_ops->to_ta_delete(ta));
79132332Smarcel}
80132332Smarcel
81132332Smarceltd_err_e
82132332Smarceltd_ta_event_addr(const td_thragent_t *ta, td_event_e event, td_notify_t *ptr)
83132332Smarcel{
84132332Smarcel	return (ta->ta_ops->to_ta_event_addr(ta, event, ptr));
85132332Smarcel}
86132332Smarcel
87132332Smarceltd_err_e
88132332Smarceltd_ta_event_getmsg(const td_thragent_t *ta, td_event_msg_t *msg)
89132332Smarcel{
90132332Smarcel	return (ta->ta_ops->to_ta_event_getmsg(ta, msg));
91132332Smarcel}
92132332Smarcel
93132332Smarceltd_err_e
94132332Smarceltd_ta_map_id2thr(const td_thragent_t *ta, thread_t id, td_thrhandle_t *th)
95132332Smarcel{
96132332Smarcel	return (ta->ta_ops->to_ta_map_id2thr(ta, id, th));
97132332Smarcel}
98132332Smarcel
99132332Smarceltd_err_e
100132332Smarceltd_ta_map_lwp2thr(const td_thragent_t *ta, lwpid_t lwpid, td_thrhandle_t *th)
101132332Smarcel{
102132332Smarcel	return (ta->ta_ops->to_ta_map_lwp2thr(ta, lwpid, th));
103132332Smarcel}
104132332Smarcel
105132332Smarceltd_err_e
106132332Smarceltd_ta_new(struct ps_prochandle *ph, td_thragent_t **pta)
107132332Smarcel{
108177490Sdavidxu	struct ta_ops *ops_p, **ops_pp;
109132332Smarcel
110177490Sdavidxu	SET_FOREACH(ops_pp, __ta_ops) {
111177490Sdavidxu		ops_p = *ops_pp;
112177490Sdavidxu		if (ops_p->to_ta_new(ph, pta) == TD_OK) {
113132332Smarcel			TAILQ_INSERT_HEAD(&proclist, *pta, ta_next);
114177490Sdavidxu			(*pta)->ta_ops = ops_p;
115132332Smarcel			return (TD_OK);
116132332Smarcel		}
117132332Smarcel	}
118132332Smarcel	return (TD_NOLIBTHREAD);
119132332Smarcel}
120132332Smarcel
121132332Smarceltd_err_e
122132332Smarceltd_ta_set_event(const td_thragent_t *ta, td_thr_events_t *events)
123132332Smarcel{
124132332Smarcel	return (ta->ta_ops->to_ta_set_event(ta, events));
125132332Smarcel}
126132332Smarcel
127132332Smarceltd_err_e
128132332Smarceltd_ta_thr_iter(const td_thragent_t *ta, td_thr_iter_f *callback,
129132332Smarcel    void *cbdata_p, td_thr_state_e state, int ti_pri, sigset_t *ti_sigmask_p,
130132332Smarcel    unsigned int ti_user_flags)
131132332Smarcel{
132132332Smarcel	return (ta->ta_ops->to_ta_thr_iter(ta, callback, cbdata_p, state,
133132332Smarcel		    ti_pri, ti_sigmask_p, ti_user_flags));
134132332Smarcel}
135132332Smarcel
136132332Smarceltd_err_e
137132332Smarceltd_ta_tsd_iter(const td_thragent_t *ta, td_key_iter_f *callback,
138132332Smarcel    void *cbdata_p)
139132332Smarcel{
140132332Smarcel	return (ta->ta_ops->to_ta_tsd_iter(ta, callback, cbdata_p));
141132332Smarcel}
142132332Smarcel
143132332Smarceltd_err_e
144132332Smarceltd_thr_clear_event(const td_thrhandle_t *th, td_thr_events_t *events)
145132332Smarcel{
146132332Smarcel	const td_thragent_t *ta = th->th_ta;
147132332Smarcel	return (ta->ta_ops->to_thr_clear_event(th, events));
148132332Smarcel}
149132332Smarcel
150132332Smarceltd_err_e
151132332Smarceltd_thr_dbresume(const td_thrhandle_t *th)
152132332Smarcel{
153132332Smarcel	const td_thragent_t *ta = th->th_ta;
154132332Smarcel	return (ta->ta_ops->to_thr_dbresume(th));
155132332Smarcel}
156132332Smarcel
157132332Smarceltd_err_e
158132332Smarceltd_thr_dbsuspend(const td_thrhandle_t *th)
159132332Smarcel{
160132332Smarcel	const td_thragent_t *ta = th->th_ta;
161132332Smarcel	return (ta->ta_ops->to_thr_dbsuspend(th));
162132332Smarcel}
163132332Smarcel
164132332Smarceltd_err_e
165132332Smarceltd_thr_event_enable(const td_thrhandle_t *th, int en)
166132332Smarcel{
167132332Smarcel	const td_thragent_t *ta = th->th_ta;
168132332Smarcel	return (ta->ta_ops->to_thr_event_enable(th, en));
169132332Smarcel}
170132332Smarcel
171132332Smarceltd_err_e
172132332Smarceltd_thr_event_getmsg(const td_thrhandle_t *th, td_event_msg_t *msg)
173132332Smarcel{
174132332Smarcel	const td_thragent_t *ta = th->th_ta;
175132332Smarcel	return (ta->ta_ops->to_thr_event_getmsg(th, msg));
176132332Smarcel}
177132332Smarcel
178132332Smarceltd_err_e
179209689Skibtd_thr_old_get_info(const td_thrhandle_t *th, td_old_thrinfo_t *info)
180209689Skib{
181209689Skib	const td_thragent_t *ta = th->th_ta;
182209689Skib	return (ta->ta_ops->to_thr_old_get_info(th, info));
183209689Skib}
184209689Skib__sym_compat(td_thr_get_info, td_thr_old_get_info, FBSD_1.0);
185209689Skib
186209689Skibtd_err_e
187132332Smarceltd_thr_get_info(const td_thrhandle_t *th, td_thrinfo_t *info)
188132332Smarcel{
189132332Smarcel	const td_thragent_t *ta = th->th_ta;
190132332Smarcel	return (ta->ta_ops->to_thr_get_info(th, info));
191132332Smarcel}
192132332Smarcel
193146818Sdfr#ifdef __i386__
194132332Smarceltd_err_e
195146818Sdfrtd_thr_getxmmregs(const td_thrhandle_t *th, char *fxsave)
196146818Sdfr{
197146818Sdfr	const td_thragent_t *ta = th->th_ta;
198146818Sdfr	return (ta->ta_ops->to_thr_getxmmregs(th, fxsave));
199146818Sdfr}
200146818Sdfr#endif
201146818Sdfr
202146818Sdfr
203146818Sdfrtd_err_e
204132332Smarceltd_thr_getfpregs(const td_thrhandle_t *th, prfpregset_t *fpregset)
205132332Smarcel{
206132332Smarcel	const td_thragent_t *ta = th->th_ta;
207132332Smarcel	return (ta->ta_ops->to_thr_getfpregs(th, fpregset));
208132332Smarcel}
209132332Smarcel
210132332Smarceltd_err_e
211132332Smarceltd_thr_getgregs(const td_thrhandle_t *th, prgregset_t gregs)
212132332Smarcel{
213132332Smarcel	const td_thragent_t *ta = th->th_ta;
214132332Smarcel	return (ta->ta_ops->to_thr_getgregs(th, gregs));
215132332Smarcel}
216132332Smarcel
217132332Smarceltd_err_e
218132332Smarceltd_thr_set_event(const td_thrhandle_t *th, td_thr_events_t *events)
219132332Smarcel{
220132332Smarcel	const td_thragent_t *ta = th->th_ta;
221132332Smarcel	return (ta->ta_ops->to_thr_set_event(th, events));
222132332Smarcel}
223132332Smarcel
224146818Sdfr#ifdef __i386__
225132332Smarceltd_err_e
226146818Sdfrtd_thr_setxmmregs(const td_thrhandle_t *th, const char *fxsave)
227146818Sdfr{
228146818Sdfr	const td_thragent_t *ta = th->th_ta;
229146818Sdfr	return (ta->ta_ops->to_thr_setxmmregs(th, fxsave));
230146818Sdfr}
231146818Sdfr#endif
232146818Sdfr
233146818Sdfrtd_err_e
234132332Smarceltd_thr_setfpregs(const td_thrhandle_t *th, const prfpregset_t *fpregs)
235132332Smarcel{
236132332Smarcel	const td_thragent_t *ta = th->th_ta;
237132332Smarcel	return (ta->ta_ops->to_thr_setfpregs(th, fpregs));
238132332Smarcel}
239132332Smarcel
240132332Smarceltd_err_e
241132332Smarceltd_thr_setgregs(const td_thrhandle_t *th, const prgregset_t gregs)
242132332Smarcel{
243132332Smarcel	const td_thragent_t *ta = th->th_ta;
244132332Smarcel	return (ta->ta_ops->to_thr_setgregs(th, gregs));
245132332Smarcel}
246132332Smarcel
247132332Smarceltd_err_e
248132332Smarceltd_thr_validate(const td_thrhandle_t *th)
249132332Smarcel{
250132332Smarcel	const td_thragent_t *ta = th->th_ta;
251132332Smarcel	return (ta->ta_ops->to_thr_validate(th));
252132332Smarcel}
253132332Smarcel
254133342Sdavidxutd_err_e
255180982Smarceltd_thr_tls_get_addr(const td_thrhandle_t *th, psaddr_t linkmap, size_t offset,
256180982Smarcel    psaddr_t *address)
257133342Sdavidxu{
258133342Sdavidxu	const td_thragent_t *ta = th->th_ta;
259133342Sdavidxu	return (ta->ta_ops->to_thr_tls_get_addr(th, linkmap, offset, address));
260133342Sdavidxu}
261133342Sdavidxu
262132332Smarcel/* FreeBSD specific extensions. */
263132332Smarcel
264132332Smarceltd_err_e
265132332Smarceltd_thr_sstep(const td_thrhandle_t *th, int step)
266132332Smarcel{
267132332Smarcel	const td_thragent_t *ta = th->th_ta;
268132332Smarcel	return (ta->ta_ops->to_thr_sstep(th, step));
269132332Smarcel}
270181065Smarcel
271181065Smarcel/*
272181065Smarcel * Support functions for reading from and writing to the target
273181065Smarcel * address space.
274181065Smarcel */
275181065Smarcel
276181065Smarcelstatic int
277181065Smarcelthr_pread(struct ps_prochandle *ph, psaddr_t addr, uint64_t *val,
278181065Smarcel    u_int size, u_int byteorder)
279181065Smarcel{
280181065Smarcel	uint8_t buf[sizeof(*val)];
281181065Smarcel	ps_err_e err;
282181065Smarcel
283181065Smarcel	if (size > sizeof(buf))
284181065Smarcel		return (EOVERFLOW);
285181065Smarcel
286181065Smarcel	err = ps_pread(ph, addr, buf, size);
287181065Smarcel	if (err != PS_OK)
288181065Smarcel		return (EFAULT);
289181065Smarcel
290181065Smarcel	switch (byteorder) {
291181065Smarcel	case BIG_ENDIAN:
292181065Smarcel		switch (size) {
293181065Smarcel		case 1:
294181065Smarcel			*val = buf[0];
295181065Smarcel			break;
296181065Smarcel		case 2:
297181065Smarcel			*val = be16dec(buf);
298181065Smarcel			break;
299181065Smarcel		case 4:
300181065Smarcel			*val = be32dec(buf);
301181065Smarcel			break;
302181065Smarcel		case 8:
303181065Smarcel			*val = be64dec(buf);
304181065Smarcel			break;
305181065Smarcel		default:
306181065Smarcel			return (EINVAL);
307181065Smarcel		}
308181065Smarcel		break;
309181065Smarcel	case LITTLE_ENDIAN:
310181065Smarcel		switch (size) {
311181065Smarcel		case 1:
312181065Smarcel			*val = buf[0];
313181065Smarcel			break;
314181065Smarcel		case 2:
315181065Smarcel			*val = le16dec(buf);
316181065Smarcel			break;
317181065Smarcel		case 4:
318181065Smarcel			*val = le32dec(buf);
319181065Smarcel			break;
320181065Smarcel		case 8:
321181065Smarcel			*val = le64dec(buf);
322181065Smarcel			break;
323181065Smarcel		default:
324181065Smarcel			return (EINVAL);
325181065Smarcel		}
326181065Smarcel		break;
327181065Smarcel	default:
328181065Smarcel		return (EINVAL);
329181065Smarcel	}
330181065Smarcel
331181065Smarcel	return (0);
332181065Smarcel}
333181065Smarcel
334181065Smarcelint
335183021Smarcelthr_pread_int(const struct td_thragent *ta, psaddr_t addr, uint32_t *val)
336181065Smarcel{
337181065Smarcel	uint64_t tmp;
338181065Smarcel	int error;
339181065Smarcel
340181065Smarcel	error = thr_pread(ta->ph, addr, &tmp, sizeof(int), BYTE_ORDER);
341181065Smarcel	if (!error)
342181065Smarcel		*val = tmp;
343181065Smarcel
344181065Smarcel	return (error);
345181065Smarcel}
346181065Smarcel
347181065Smarcelint
348183021Smarcelthr_pread_long(const struct td_thragent *ta, psaddr_t addr, uint64_t *val)
349181065Smarcel{
350181065Smarcel
351181065Smarcel	return (thr_pread(ta->ph, addr, val, sizeof(long), BYTE_ORDER));
352181065Smarcel}
353181065Smarcel
354181065Smarcelint
355183021Smarcelthr_pread_ptr(const struct td_thragent *ta, psaddr_t addr, psaddr_t *val)
356181065Smarcel{
357183021Smarcel	uint64_t tmp;
358183021Smarcel	int error;
359181065Smarcel
360183021Smarcel	error = thr_pread(ta->ph, addr, &tmp, sizeof(void *), BYTE_ORDER);
361183021Smarcel	if (!error)
362183021Smarcel		*val = tmp;
363183021Smarcel
364183021Smarcel	return (error);
365181065Smarcel}
366181065Smarcel
367181065Smarcelstatic int
368181065Smarcelthr_pwrite(struct ps_prochandle *ph, psaddr_t addr, uint64_t val,
369181065Smarcel    u_int size, u_int byteorder)
370181065Smarcel{
371181065Smarcel	uint8_t buf[sizeof(val)];
372181065Smarcel	ps_err_e err;
373181065Smarcel
374181065Smarcel	if (size > sizeof(buf))
375181065Smarcel		return (EOVERFLOW);
376181065Smarcel
377181065Smarcel	switch (byteorder) {
378181065Smarcel	case BIG_ENDIAN:
379181065Smarcel		switch (size) {
380181065Smarcel		case 1:
381181065Smarcel			buf[0] = (uint8_t)val;
382181065Smarcel			break;
383181065Smarcel		case 2:
384181065Smarcel			be16enc(buf, (uint16_t)val);
385181065Smarcel			break;
386181065Smarcel		case 4:
387181065Smarcel			be32enc(buf, (uint32_t)val);
388181065Smarcel			break;
389181065Smarcel		case 8:
390181065Smarcel			be64enc(buf, (uint64_t)val);
391181065Smarcel			break;
392181065Smarcel		default:
393181065Smarcel			return (EINVAL);
394181065Smarcel		}
395181065Smarcel		break;
396181065Smarcel	case LITTLE_ENDIAN:
397181065Smarcel		switch (size) {
398181065Smarcel		case 1:
399181065Smarcel			buf[0] = (uint8_t)val;
400181065Smarcel			break;
401181065Smarcel		case 2:
402181065Smarcel			le16enc(buf, (uint16_t)val);
403181065Smarcel			break;
404181065Smarcel		case 4:
405181065Smarcel			le32enc(buf, (uint32_t)val);
406181065Smarcel			break;
407181065Smarcel		case 8:
408181065Smarcel			le64enc(buf, (uint64_t)val);
409181065Smarcel			break;
410181065Smarcel		default:
411181065Smarcel			return (EINVAL);
412181065Smarcel		}
413181065Smarcel		break;
414181065Smarcel	default:
415181065Smarcel		return (EINVAL);
416181065Smarcel	}
417181065Smarcel
418181065Smarcel	err = ps_pwrite(ph, addr, buf, size);
419181065Smarcel	return ((err != PS_OK) ? EFAULT : 0);
420181065Smarcel}
421181065Smarcel
422181065Smarcelint
423183021Smarcelthr_pwrite_int(const struct td_thragent *ta, psaddr_t addr, uint32_t val)
424181065Smarcel{
425181065Smarcel
426181065Smarcel	return (thr_pwrite(ta->ph, addr, val, sizeof(int), BYTE_ORDER));
427181065Smarcel}
428181065Smarcel
429181065Smarcelint
430183021Smarcelthr_pwrite_long(const struct td_thragent *ta, psaddr_t addr, uint64_t val)
431181065Smarcel{
432181065Smarcel
433181065Smarcel	return (thr_pwrite(ta->ph, addr, val, sizeof(long), BYTE_ORDER));
434181065Smarcel}
435181065Smarcel
436181065Smarcelint
437183021Smarcelthr_pwrite_ptr(const struct td_thragent *ta, psaddr_t addr, psaddr_t val)
438181065Smarcel{
439181065Smarcel
440181065Smarcel	return (thr_pwrite(ta->ph, addr, val, sizeof(void *), BYTE_ORDER));
441181065Smarcel}
442181065Smarcel
443