thread_db.c revision 181065
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: head/lib/libthread_db/thread_db.c 181065 2008-07-31 20:25:52Z marcel $");
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
179132332Smarceltd_thr_get_info(const td_thrhandle_t *th, td_thrinfo_t *info)
180132332Smarcel{
181132332Smarcel	const td_thragent_t *ta = th->th_ta;
182132332Smarcel	return (ta->ta_ops->to_thr_get_info(th, info));
183132332Smarcel}
184132332Smarcel
185146818Sdfr#ifdef __i386__
186132332Smarceltd_err_e
187146818Sdfrtd_thr_getxmmregs(const td_thrhandle_t *th, char *fxsave)
188146818Sdfr{
189146818Sdfr	const td_thragent_t *ta = th->th_ta;
190146818Sdfr	return (ta->ta_ops->to_thr_getxmmregs(th, fxsave));
191146818Sdfr}
192146818Sdfr#endif
193146818Sdfr
194146818Sdfr
195146818Sdfrtd_err_e
196132332Smarceltd_thr_getfpregs(const td_thrhandle_t *th, prfpregset_t *fpregset)
197132332Smarcel{
198132332Smarcel	const td_thragent_t *ta = th->th_ta;
199132332Smarcel	return (ta->ta_ops->to_thr_getfpregs(th, fpregset));
200132332Smarcel}
201132332Smarcel
202132332Smarceltd_err_e
203132332Smarceltd_thr_getgregs(const td_thrhandle_t *th, prgregset_t gregs)
204132332Smarcel{
205132332Smarcel	const td_thragent_t *ta = th->th_ta;
206132332Smarcel	return (ta->ta_ops->to_thr_getgregs(th, gregs));
207132332Smarcel}
208132332Smarcel
209132332Smarceltd_err_e
210132332Smarceltd_thr_set_event(const td_thrhandle_t *th, td_thr_events_t *events)
211132332Smarcel{
212132332Smarcel	const td_thragent_t *ta = th->th_ta;
213132332Smarcel	return (ta->ta_ops->to_thr_set_event(th, events));
214132332Smarcel}
215132332Smarcel
216146818Sdfr#ifdef __i386__
217132332Smarceltd_err_e
218146818Sdfrtd_thr_setxmmregs(const td_thrhandle_t *th, const char *fxsave)
219146818Sdfr{
220146818Sdfr	const td_thragent_t *ta = th->th_ta;
221146818Sdfr	return (ta->ta_ops->to_thr_setxmmregs(th, fxsave));
222146818Sdfr}
223146818Sdfr#endif
224146818Sdfr
225146818Sdfrtd_err_e
226132332Smarceltd_thr_setfpregs(const td_thrhandle_t *th, const prfpregset_t *fpregs)
227132332Smarcel{
228132332Smarcel	const td_thragent_t *ta = th->th_ta;
229132332Smarcel	return (ta->ta_ops->to_thr_setfpregs(th, fpregs));
230132332Smarcel}
231132332Smarcel
232132332Smarceltd_err_e
233132332Smarceltd_thr_setgregs(const td_thrhandle_t *th, const prgregset_t gregs)
234132332Smarcel{
235132332Smarcel	const td_thragent_t *ta = th->th_ta;
236132332Smarcel	return (ta->ta_ops->to_thr_setgregs(th, gregs));
237132332Smarcel}
238132332Smarcel
239132332Smarceltd_err_e
240132332Smarceltd_thr_validate(const td_thrhandle_t *th)
241132332Smarcel{
242132332Smarcel	const td_thragent_t *ta = th->th_ta;
243132332Smarcel	return (ta->ta_ops->to_thr_validate(th));
244132332Smarcel}
245132332Smarcel
246133342Sdavidxutd_err_e
247180982Smarceltd_thr_tls_get_addr(const td_thrhandle_t *th, psaddr_t linkmap, size_t offset,
248180982Smarcel    psaddr_t *address)
249133342Sdavidxu{
250133342Sdavidxu	const td_thragent_t *ta = th->th_ta;
251133342Sdavidxu	return (ta->ta_ops->to_thr_tls_get_addr(th, linkmap, offset, address));
252133342Sdavidxu}
253133342Sdavidxu
254132332Smarcel/* FreeBSD specific extensions. */
255132332Smarcel
256132332Smarceltd_err_e
257132332Smarceltd_thr_sstep(const td_thrhandle_t *th, int step)
258132332Smarcel{
259132332Smarcel	const td_thragent_t *ta = th->th_ta;
260132332Smarcel	return (ta->ta_ops->to_thr_sstep(th, step));
261132332Smarcel}
262181065Smarcel
263181065Smarcel/*
264181065Smarcel * Support functions for reading from and writing to the target
265181065Smarcel * address space.
266181065Smarcel */
267181065Smarcel
268181065Smarcelstatic int
269181065Smarcelthr_pread(struct ps_prochandle *ph, psaddr_t addr, uint64_t *val,
270181065Smarcel    u_int size, u_int byteorder)
271181065Smarcel{
272181065Smarcel	uint8_t buf[sizeof(*val)];
273181065Smarcel	ps_err_e err;
274181065Smarcel
275181065Smarcel	if (size > sizeof(buf))
276181065Smarcel		return (EOVERFLOW);
277181065Smarcel
278181065Smarcel	err = ps_pread(ph, addr, buf, size);
279181065Smarcel	if (err != PS_OK)
280181065Smarcel		return (EFAULT);
281181065Smarcel
282181065Smarcel	switch (byteorder) {
283181065Smarcel	case BIG_ENDIAN:
284181065Smarcel		switch (size) {
285181065Smarcel		case 1:
286181065Smarcel			*val = buf[0];
287181065Smarcel			break;
288181065Smarcel		case 2:
289181065Smarcel			*val = be16dec(buf);
290181065Smarcel			break;
291181065Smarcel		case 4:
292181065Smarcel			*val = be32dec(buf);
293181065Smarcel			break;
294181065Smarcel		case 8:
295181065Smarcel			*val = be64dec(buf);
296181065Smarcel			break;
297181065Smarcel		default:
298181065Smarcel			return (EINVAL);
299181065Smarcel		}
300181065Smarcel		break;
301181065Smarcel	case LITTLE_ENDIAN:
302181065Smarcel		switch (size) {
303181065Smarcel		case 1:
304181065Smarcel			*val = buf[0];
305181065Smarcel			break;
306181065Smarcel		case 2:
307181065Smarcel			*val = le16dec(buf);
308181065Smarcel			break;
309181065Smarcel		case 4:
310181065Smarcel			*val = le32dec(buf);
311181065Smarcel			break;
312181065Smarcel		case 8:
313181065Smarcel			*val = le64dec(buf);
314181065Smarcel			break;
315181065Smarcel		default:
316181065Smarcel			return (EINVAL);
317181065Smarcel		}
318181065Smarcel		break;
319181065Smarcel	default:
320181065Smarcel		return (EINVAL);
321181065Smarcel	}
322181065Smarcel
323181065Smarcel	return (0);
324181065Smarcel}
325181065Smarcel
326181065Smarcelint
327181065Smarcelthr_pread_int(struct td_thragent *ta, psaddr_t addr, uint32_t *val)
328181065Smarcel{
329181065Smarcel	uint64_t tmp;
330181065Smarcel	int error;
331181065Smarcel
332181065Smarcel	error = thr_pread(ta->ph, addr, &tmp, sizeof(int), BYTE_ORDER);
333181065Smarcel	if (!error)
334181065Smarcel		*val = tmp;
335181065Smarcel
336181065Smarcel	return (error);
337181065Smarcel}
338181065Smarcel
339181065Smarcelint
340181065Smarcelthr_pread_long(struct td_thragent *ta, psaddr_t addr, uint64_t *val)
341181065Smarcel{
342181065Smarcel
343181065Smarcel	return (thr_pread(ta->ph, addr, val, sizeof(long), BYTE_ORDER));
344181065Smarcel}
345181065Smarcel
346181065Smarcelint
347181065Smarcelthr_pread_ptr(struct td_thragent *ta, psaddr_t addr, uint64_t *val)
348181065Smarcel{
349181065Smarcel
350181065Smarcel	return (thr_pread(ta->ph, addr, val, sizeof(void *), BYTE_ORDER));
351181065Smarcel}
352181065Smarcel
353181065Smarcelstatic int
354181065Smarcelthr_pwrite(struct ps_prochandle *ph, psaddr_t addr, uint64_t val,
355181065Smarcel    u_int size, u_int byteorder)
356181065Smarcel{
357181065Smarcel	uint8_t buf[sizeof(val)];
358181065Smarcel	ps_err_e err;
359181065Smarcel
360181065Smarcel	if (size > sizeof(buf))
361181065Smarcel		return (EOVERFLOW);
362181065Smarcel
363181065Smarcel	switch (byteorder) {
364181065Smarcel	case BIG_ENDIAN:
365181065Smarcel		switch (size) {
366181065Smarcel		case 1:
367181065Smarcel			buf[0] = (uint8_t)val;
368181065Smarcel			break;
369181065Smarcel		case 2:
370181065Smarcel			be16enc(buf, (uint16_t)val);
371181065Smarcel			break;
372181065Smarcel		case 4:
373181065Smarcel			be32enc(buf, (uint32_t)val);
374181065Smarcel			break;
375181065Smarcel		case 8:
376181065Smarcel			be64enc(buf, (uint64_t)val);
377181065Smarcel			break;
378181065Smarcel		default:
379181065Smarcel			return (EINVAL);
380181065Smarcel		}
381181065Smarcel		break;
382181065Smarcel	case LITTLE_ENDIAN:
383181065Smarcel		switch (size) {
384181065Smarcel		case 1:
385181065Smarcel			buf[0] = (uint8_t)val;
386181065Smarcel			break;
387181065Smarcel		case 2:
388181065Smarcel			le16enc(buf, (uint16_t)val);
389181065Smarcel			break;
390181065Smarcel		case 4:
391181065Smarcel			le32enc(buf, (uint32_t)val);
392181065Smarcel			break;
393181065Smarcel		case 8:
394181065Smarcel			le64enc(buf, (uint64_t)val);
395181065Smarcel			break;
396181065Smarcel		default:
397181065Smarcel			return (EINVAL);
398181065Smarcel		}
399181065Smarcel		break;
400181065Smarcel	default:
401181065Smarcel		return (EINVAL);
402181065Smarcel	}
403181065Smarcel
404181065Smarcel	err = ps_pwrite(ph, addr, buf, size);
405181065Smarcel	return ((err != PS_OK) ? EFAULT : 0);
406181065Smarcel}
407181065Smarcel
408181065Smarcelint
409181065Smarcelthr_pwrite_int(struct td_thragent *ta, psaddr_t addr, uint32_t val)
410181065Smarcel{
411181065Smarcel
412181065Smarcel	return (thr_pwrite(ta->ph, addr, val, sizeof(int), BYTE_ORDER));
413181065Smarcel}
414181065Smarcel
415181065Smarcelint
416181065Smarcelthr_pwrite_long(struct td_thragent *ta, psaddr_t addr, uint64_t val)
417181065Smarcel{
418181065Smarcel
419181065Smarcel	return (thr_pwrite(ta->ph, addr, val, sizeof(long), BYTE_ORDER));
420181065Smarcel}
421181065Smarcel
422181065Smarcelint
423181065Smarcelthr_pwrite_ptr(struct td_thragent *ta, psaddr_t addr, uint64_t val)
424181065Smarcel{
425181065Smarcel
426181065Smarcel	return (thr_pwrite(ta->ph, addr, val, sizeof(void *), BYTE_ORDER));
427181065Smarcel}
428181065Smarcel
429