xref: /freebsd/lib/libthread_db/libthr_db.c (revision 6b3455a7665208c366849f0b2b3bc916fb97516e)
1 /*
2  * Copyright (c) 2004 Marcel Moolenaar
3  * All rights reserved.
4  *
5  * Redistribution and use in source and binary forms, with or without
6  * modification, are permitted provided that the following conditions
7  * are met:
8  *
9  * 1. Redistributions of source code must retain the above copyright
10  *    notice, this list of conditions and the following disclaimer.
11  * 2. Redistributions in binary form must reproduce the above copyright
12  *    notice, this list of conditions and the following disclaimer in the
13  *    documentation and/or other materials provided with the distribution.
14  *
15  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
16  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
17  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
18  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
19  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
20  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
21  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
22  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
23  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
24  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
25  */
26 
27 #include <sys/cdefs.h>
28 __FBSDID("$FreeBSD$");
29 
30 #include <proc_service.h>
31 #include <stdlib.h>
32 #include <thread_db.h>
33 
34 #include "thread_db_int.h"
35 
36 struct td_thragent {
37 	TD_THRAGENT_FIELDS;
38 	struct ps_prochandle	*ta_ph;
39 	psaddr_t ta_thread_list;
40 	int	ta_ofs_ctx;
41 	int	ta_ofs_next;
42 	int	ta_ofs_thr_id;
43 };
44 
45 static td_err_e
46 libthr_db_init()
47 {
48 	return (TD_OK);
49 }
50 
51 static td_err_e
52 libthr_db_ta_clear_event(const td_thragent_t *ta, td_thr_events_t *ev)
53 {
54 	return (TD_ERR);
55 }
56 
57 static td_err_e
58 libthr_db_ta_delete(td_thragent_t *ta)
59 {
60 	free(ta);
61 	return (TD_OK);
62 }
63 
64 static td_err_e
65 libthr_db_ta_event_addr(const td_thragent_t *ta, td_thr_events_e event,
66     td_notify_t *n)
67 {
68 	return (TD_ERR);
69 }
70 
71 static td_err_e
72 libthr_db_ta_event_getmsg(const td_thragent_t *ta, td_event_msg_t *msg)
73 {
74 	return (TD_ERR);
75 }
76 
77 static td_err_e
78 libthr_db_ta_map_id2thr(const td_thragent_t *ta, thread_t tid,
79     td_thrhandle_t *th)
80 {
81 	return (TD_ERR);
82 }
83 
84 static td_err_e
85 libthr_db_ta_map_lwp2thr(const td_thragent_t *ta, lwpid_t lwpid,
86     td_thrhandle_t *th)
87 {
88 	psaddr_t addr;
89 	thread_t tid;
90 	ps_err_e err;
91 
92 	th->th_ta = ta;
93 
94 	err = ps_pread(ta->ta_ph, ta->ta_thread_list, &th->th_thread,
95 	    sizeof(th->th_thread));
96 	if (err != PS_OK)
97 		return (TD_ERR);
98 	while (th->th_thread != NULL) {
99 		addr = (psaddr_t)((uintptr_t)th->th_thread +
100 		    ta->ta_ofs_thr_id);
101 		err = ps_pread(ta->ta_ph, addr, &tid, sizeof(thread_t));
102 		if (err != PS_OK)
103 			return (TD_ERR);
104 		if (tid == lwpid)
105 			return (TD_OK);
106 		addr = (psaddr_t)((uintptr_t)th->th_thread + ta->ta_ofs_next);
107 		err = ps_pread(ta->ta_ph, addr, &th->th_thread,
108 		    sizeof(th->th_thread));
109 		if (err != PS_OK)
110 			return (TD_ERR);
111 	}
112 	return (TD_NOLWP);
113 }
114 
115 static td_err_e
116 libthr_db_ta_new(struct ps_prochandle *ph, td_thragent_t **ta_p)
117 {
118 	td_thragent_t *ta;
119 	psaddr_t addr;
120 	ps_err_e err;
121 
122 	err = ps_pglobal_lookup(ph, NULL, "_libthr_debug", &addr);
123 	if (err != PS_OK)
124 		return (TD_NOLIBTHREAD);
125 
126 	ta = malloc(sizeof(td_thragent_t));
127 	if (ta == NULL)
128 		return (TD_MALLOC);
129 
130 	ta->ta_ph = ph;
131 
132 	err = ps_pglobal_lookup(ph, NULL, "_thread_list", &ta->ta_thread_list);
133 	if (err != PS_OK)
134 		goto fail;
135 	err = ps_pglobal_lookup(ph, NULL, "_thread_ctx_offset", &addr);
136 	if (err != PS_OK)
137 		goto fail;
138 	err = ps_pread(ph, addr, &ta->ta_ofs_ctx, sizeof(int));
139 	if (err != PS_OK)
140 		goto fail;
141 	err = ps_pglobal_lookup(ph, NULL, "_thread_next_offset", &addr);
142 	if (err != PS_OK)
143 		goto fail;
144 	err = ps_pread(ph, addr, &ta->ta_ofs_next, sizeof(int));
145 	if (err != PS_OK)
146 		goto fail;
147 	err = ps_pglobal_lookup(ph, NULL, "_thread_thr_id_offset", &addr);
148 	if (err != PS_OK)
149 		goto fail;
150 	err = ps_pread(ph, addr, &ta->ta_ofs_thr_id, sizeof(int));
151 	if (err != PS_OK)
152 		goto fail;
153 
154 	*ta_p = ta;
155 	return (TD_OK);
156 
157  fail:
158 	free(ta);
159 	*ta_p = NULL;
160 	return (TD_ERR);
161 }
162 
163 static td_err_e
164 libthr_db_ta_set_event(const td_thragent_t *ta, td_thr_events_t *ev)
165 {
166 	return (TD_ERR);
167 }
168 
169 static td_err_e
170 libthr_db_ta_thr_iter(const td_thragent_t *ta, td_thr_iter_f *cb, void *data,
171     td_thr_state_e state, int pri, sigset_t *mask, unsigned int flags)
172 {
173 	td_thrhandle_t th;
174 	psaddr_t addr;
175 	ps_err_e err;
176 
177 	th.th_ta = ta;
178 
179 	err = ps_pread(ta->ta_ph, ta->ta_thread_list, &th.th_thread,
180 	    sizeof(th.th_thread));
181 	if (err != PS_OK)
182 		return (TD_ERR);
183 	while (th.th_thread != NULL) {
184 		if (cb(&th, data) != 0)
185 			return (TD_OK);
186 		addr = (psaddr_t)((uintptr_t)th.th_thread + ta->ta_ofs_next);
187 		err = ps_pread(ta->ta_ph, addr, &th.th_thread,
188 		    sizeof(th.th_thread));
189 		if (err != PS_OK)
190 			return (TD_ERR);
191 	}
192 	return (TD_OK);
193 }
194 
195 static td_err_e
196 libthr_db_thr_clear_event(const td_thrhandle_t *th, td_thr_events_t *ev)
197 {
198 	return (TD_ERR);
199 }
200 
201 static td_err_e
202 libthr_db_thr_event_enable(const td_thrhandle_t *th, int oo)
203 {
204 	return (TD_ERR);
205 }
206 
207 static td_err_e
208 libthr_db_thr_event_getmsg(const td_thrhandle_t *th, td_event_msg_t *msg)
209 {
210 	return (TD_ERR);
211 }
212 
213 static td_err_e
214 libthr_db_thr_get_info(const td_thrhandle_t *th, td_thrinfo_t *ti)
215 {
216 	const td_thragent_t *ta;
217 	psaddr_t addr;
218 	thread_t tid;
219 	ps_err_e err;
220 
221 	ta = th->th_ta;
222 	ti->ti_ta_p = ta;
223 	addr = (psaddr_t)((uintptr_t)th->th_thread + ta->ta_ofs_thr_id);
224 	err = ps_pread(ta->ta_ph, addr, &tid, sizeof(thread_t));
225 	ti->ti_lid = tid;
226 	ti->ti_tid = tid;
227 	return ((err == PS_OK) ? TD_OK : TD_ERR);
228 }
229 
230 static td_err_e
231 libthr_db_thr_getfpregs(const td_thrhandle_t *th, prfpregset_t *r)
232 {
233 	const td_thragent_t *ta;
234 	psaddr_t addr;
235 	thread_t tid;
236 	ps_err_e err;
237 
238 	ta = th->th_ta;
239 	addr = (psaddr_t)((uintptr_t)th->th_thread + ta->ta_ofs_thr_id);
240 	err = ps_pread(ta->ta_ph, addr, &tid, sizeof(thread_t));
241 	if (err != PS_OK)
242 		return (TD_ERR);
243 	err = ps_lgetfpregs(ta->ta_ph, tid, r);
244 	return ((err == PS_OK) ? TD_OK : TD_ERR);
245 }
246 
247 static td_err_e
248 libthr_db_thr_getgregs(const td_thrhandle_t *th, prgregset_t r)
249 {
250 	const td_thragent_t *ta;
251 	psaddr_t addr;
252 	thread_t tid;
253 	ps_err_e err;
254 
255 	ta = th->th_ta;
256 	addr = (psaddr_t)((uintptr_t)th->th_thread + ta->ta_ofs_thr_id);
257 	err = ps_pread(ta->ta_ph, addr, &tid, sizeof(thread_t));
258 	if (err != PS_OK)
259 		return (TD_ERR);
260 	err = ps_lgetregs(ta->ta_ph, tid, r);
261 	return ((err == PS_OK) ? TD_OK : TD_ERR);
262 }
263 
264 static td_err_e
265 libthr_db_thr_set_event(const td_thrhandle_t *th, td_thr_events_t *ev)
266 {
267 	return (TD_ERR);
268 }
269 
270 static td_err_e
271 libthr_db_thr_setfpregs(const td_thrhandle_t *th, const prfpregset_t *r)
272 {
273 	return (TD_ERR);
274 }
275 
276 static td_err_e
277 libthr_db_thr_setgregs(const td_thrhandle_t *th, const prgregset_t r)
278 {
279 	return (TD_ERR);
280 }
281 
282 static td_err_e
283 libthr_db_thr_validate(const td_thrhandle_t *th)
284 {
285 	return (TD_ERR);
286 }
287 
288 struct ta_ops libthr_db_ops = {
289 	.to_init		= libthr_db_init,
290 
291 	.to_ta_clear_event	= libthr_db_ta_clear_event,
292 	.to_ta_delete		= libthr_db_ta_delete,
293 	.to_ta_event_addr	= libthr_db_ta_event_addr,
294 	.to_ta_event_getmsg	= libthr_db_ta_event_getmsg,
295 	.to_ta_map_id2thr	= libthr_db_ta_map_id2thr,
296 	.to_ta_map_lwp2thr	= libthr_db_ta_map_lwp2thr,
297 	.to_ta_new		= libthr_db_ta_new,
298 	.to_ta_set_event	= libthr_db_ta_set_event,
299 	.to_ta_thr_iter		= libthr_db_ta_thr_iter,
300 
301 	.to_thr_clear_event     = libthr_db_thr_clear_event,
302 	.to_thr_event_enable    = libthr_db_thr_event_enable,
303 	.to_thr_event_getmsg	= libthr_db_thr_event_getmsg,
304 	.to_thr_get_info        = libthr_db_thr_get_info,
305 	.to_thr_getfpregs       = libthr_db_thr_getfpregs,
306 	.to_thr_getgregs        = libthr_db_thr_getgregs,
307 	.to_thr_set_event       = libthr_db_thr_set_event,
308 	.to_thr_setfpregs       = libthr_db_thr_setfpregs,
309 	.to_thr_setgregs        = libthr_db_thr_setgregs,
310 	.to_thr_validate        = libthr_db_thr_validate
311 };
312