2002-08-01 Andrew Cagney <cagney@redhat.com>
[deliverable/binutils-gdb.git] / gdb / gdbserver / thread-db.c
CommitLineData
0d62e5e8
DJ
1/* Thread management interface, for the remote server for GDB.
2 Copyright 2002
3 Free Software Foundation, Inc.
4
5 Contributed by MontaVista Software.
6
7 This file is part of GDB.
8
9 This program is free software; you can redistribute it and/or modify
10 it under the terms of the GNU General Public License as published by
11 the Free Software Foundation; either version 2 of the License, or
12 (at your option) any later version.
13
14 This program is distributed in the hope that it will be useful,
15 but WITHOUT ANY WARRANTY; without even the implied warranty of
16 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 GNU General Public License for more details.
18
19 You should have received a copy of the GNU General Public License
20 along with this program; if not, write to the Free Software
21 Foundation, Inc., 59 Temple Place - Suite 330,
22 Boston, MA 02111-1307, USA. */
23
24#include "server.h"
25
26#include "linux-low.h"
27
28extern int debug_threads;
29
30#ifdef HAVE_THREAD_DB_H
31#include <thread_db.h>
32#endif
33
34/* Correct for all GNU/Linux targets (for quite some time). */
35#define GDB_GREGSET_T elf_gregset_t
36#define GDB_FPREGSET_T elf_fpregset_t
37
38#ifndef HAVE_ELF_FPREGSET_T
39/* Make sure we have said types. Not all platforms bring in <linux/elf.h>
40 via <sys/procfs.h>. */
41#ifdef HAVE_LINUX_ELF_H
42#include <linux/elf.h>
43#endif
44#endif
45
46#include "../gdb_proc_service.h"
47
48/* Structure that identifies the child process for the
49 <proc_service.h> interface. */
50static struct ps_prochandle proc_handle;
51
52/* Connection to the libthread_db library. */
53static td_thragent_t *thread_agent;
54
55static int find_new_threads_callback (const td_thrhandle_t *th_p, void *data);
56
57static char *
58thread_db_err_str (td_err_e err)
59{
60 static char buf[64];
61
62 switch (err)
63 {
64 case TD_OK:
65 return "generic 'call succeeded'";
66 case TD_ERR:
67 return "generic error";
68 case TD_NOTHR:
69 return "no thread to satisfy query";
70 case TD_NOSV:
71 return "no sync handle to satisfy query";
72 case TD_NOLWP:
73 return "no LWP to satisfy query";
74 case TD_BADPH:
75 return "invalid process handle";
76 case TD_BADTH:
77 return "invalid thread handle";
78 case TD_BADSH:
79 return "invalid synchronization handle";
80 case TD_BADTA:
81 return "invalid thread agent";
82 case TD_BADKEY:
83 return "invalid key";
84 case TD_NOMSG:
85 return "no event message for getmsg";
86 case TD_NOFPREGS:
87 return "FPU register set not available";
88 case TD_NOLIBTHREAD:
89 return "application not linked with libthread";
90 case TD_NOEVENT:
91 return "requested event is not supported";
92 case TD_NOCAPAB:
93 return "capability not available";
94 case TD_DBERR:
95 return "debugger service failed";
96 case TD_NOAPLIC:
97 return "operation not applicable to";
98 case TD_NOTSD:
99 return "no thread-specific data for this thread";
100 case TD_MALLOC:
101 return "malloc failed";
102 case TD_PARTIALREG:
103 return "only part of register set was written/read";
104 case TD_NOXREGS:
105 return "X register set not available for this thread";
106 default:
107 snprintf (buf, sizeof (buf), "unknown thread_db error '%d'", err);
108 return buf;
109 }
110}
111
112#if 0
113static char *
114thread_db_state_str (td_thr_state_e state)
115{
116 static char buf[64];
117
118 switch (state)
119 {
120 case TD_THR_STOPPED:
121 return "stopped by debugger";
122 case TD_THR_RUN:
123 return "runnable";
124 case TD_THR_ACTIVE:
125 return "active";
126 case TD_THR_ZOMBIE:
127 return "zombie";
128 case TD_THR_SLEEP:
129 return "sleeping";
130 case TD_THR_STOPPED_ASLEEP:
131 return "stopped by debugger AND blocked";
132 default:
133 snprintf (buf, sizeof (buf), "unknown thread_db state %d", state);
134 return buf;
135 }
136}
137#endif
138
139static void
140thread_db_create_event (CORE_ADDR where)
141{
142 td_event_msg_t msg;
143 td_err_e err;
144 struct inferior_linux_data *tdata;
145
146 if (debug_threads)
147 fprintf (stderr, "Thread creation event.\n");
148
149 tdata = inferior_target_data (current_inferior);
150
151 /* FIXME: This assumes we don't get another event.
152 In the LinuxThreads implementation, this is safe,
153 because all events come from the manager thread
154 (except for its own creation, of course). */
155 err = td_ta_event_getmsg (thread_agent, &msg);
156 if (err != TD_OK)
157 fprintf (stderr, "thread getmsg err: %s\n",
158 thread_db_err_str (err));
159
160 /* msg.event == TD_EVENT_CREATE */
161
162 find_new_threads_callback (msg.th_p, NULL);
163}
164
165#if 0
166static void
167thread_db_death_event (CORE_ADDR where)
168{
169 if (debug_threads)
170 fprintf (stderr, "Thread death event.\n");
171}
172#endif
173
174static int
175thread_db_enable_reporting ()
176{
177 td_thr_events_t events;
178 td_notify_t notify;
179 td_err_e err;
180
181 /* Set the process wide mask saying which events we're interested in. */
182 td_event_emptyset (&events);
183 td_event_addset (&events, TD_CREATE);
184
185#if 0
186 /* This is reported to be broken in glibc 2.1.3. A different approach
187 will be necessary to support that. */
188 td_event_addset (&events, TD_DEATH);
189#endif
190
191 err = td_ta_set_event (thread_agent, &events);
192 if (err != TD_OK)
193 {
194 warning ("Unable to set global thread event mask: %s",
195 thread_db_err_str (err));
196 return 0;
197 }
198
199 /* Get address for thread creation breakpoint. */
200 err = td_ta_event_addr (thread_agent, TD_CREATE, &notify);
201 if (err != TD_OK)
202 {
203 warning ("Unable to get location for thread creation breakpoint: %s",
204 thread_db_err_str (err));
205 return 0;
206 }
207 set_breakpoint_at ((CORE_ADDR) (unsigned long) notify.u.bptaddr,
208 thread_db_create_event);
209
210#if 0
211 /* Don't concern ourselves with reported thread deaths, only
212 with actual thread deaths (via wait). */
213
214 /* Get address for thread death breakpoint. */
215 err = td_ta_event_addr (thread_agent, TD_DEATH, &notify);
216 if (err != TD_OK)
217 {
218 warning ("Unable to get location for thread death breakpoint: %s",
219 thread_db_err_str (err));
220 return;
221 }
222 set_breakpoint_at ((CORE_ADDR) (unsigned long) notify.u.bptaddr,
223 thread_db_death_event);
224#endif
225
226 return 1;
227}
228
229static void
230maybe_attach_thread (const td_thrhandle_t *th_p, td_thrinfo_t *ti_p)
231{
232 td_err_e err;
233 struct thread_info *inferior;
234 struct process_info *process;
235
236 /* If we are attaching to our first thread, things are a little
237 different. */
238 if (all_threads.head == all_threads.tail)
239 {
240 inferior = (struct thread_info *) all_threads.head;
241 process = get_thread_process (inferior);
242 if (process->thread_known == 0)
243 {
244 /* Switch to indexing the threads list by TID. */
245 change_inferior_id (&all_threads, ti_p->ti_tid);
246 goto found;
247 }
248 }
249
250 inferior = (struct thread_info *) find_inferior_id (&all_threads,
251 ti_p->ti_tid);
252 if (inferior != NULL)
253 return;
254
255 if (debug_threads)
256 fprintf (stderr, "Attaching to thread %ld (LWP %d)\n",
257 ti_p->ti_tid, ti_p->ti_lid);
258 linux_attach_lwp (ti_p->ti_lid, ti_p->ti_tid);
259 inferior = (struct thread_info *) find_inferior_id (&all_threads,
260 ti_p->ti_tid);
261 if (inferior == NULL)
262 {
263 warning ("Could not attach to thread %ld (LWP %d)\n",
264 ti_p->ti_tid, ti_p->ti_lid);
265 return;
266 }
267
268 process = inferior_target_data (inferior);
269
270found:
271 new_thread_notify (ti_p->ti_tid);
272
273 process->tid = ti_p->ti_tid;
274 process->lwpid = ti_p->ti_lid;
275
276 process->thread_known = 1;
277 err = td_thr_event_enable (th_p, 1);
278 if (err != TD_OK)
279 error ("Cannot enable thread event reporting for %d: %s",
280 ti_p->ti_lid, thread_db_err_str (err));
281}
282
283static int
284find_new_threads_callback (const td_thrhandle_t *th_p, void *data)
285{
286 td_thrinfo_t ti;
287 td_err_e err;
288
289 err = td_thr_get_info (th_p, &ti);
290 if (err != TD_OK)
291 error ("Cannot get thread info: %s", thread_db_err_str (err));
292
293 /* Check for zombies. */
294 if (ti.ti_state == TD_THR_UNKNOWN || ti.ti_state == TD_THR_ZOMBIE)
295 return 0;
296
297 maybe_attach_thread (th_p, &ti);
298
299 return 0;
300}
301
302static void
303thread_db_find_new_threads (void)
304{
305 td_err_e err;
306
307 /* Iterate over all user-space threads to discover new threads. */
308 err = td_ta_thr_iter (thread_agent, find_new_threads_callback, NULL,
309 TD_THR_ANY_STATE, TD_THR_LOWEST_PRIORITY,
310 TD_SIGNO_MASK, TD_THR_ANY_USER_FLAGS);
311 if (err != TD_OK)
312 error ("Cannot find new threads: %s", thread_db_err_str (err));
313}
314
315int
316thread_db_init ()
317{
318 int err;
319
320 proc_handle.pid = ((struct inferior_list_entry *)current_inferior)->id;
321
322 err = td_ta_new (&proc_handle, &thread_agent);
323 switch (err)
324 {
325 case TD_NOLIBTHREAD:
326 /* No thread library was detected. */
327 return 0;
328
329 case TD_OK:
330 /* The thread library was detected. */
331
332 if (thread_db_enable_reporting () == 0)
333 return 0;
334 thread_db_find_new_threads ();
335 return 1;
336
337 default:
338 warning ("error initializing thread_db library.");
339 }
340
341 return 0;
342}
This page took 0.046879 seconds and 4 git commands to generate.