1 /* Thread management interface, for the remote server for GDB.
3 Free Software Foundation, Inc.
5 Contributed by MontaVista Software.
7 This file is part of GDB.
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.
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.
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. */
26 #include "linux-low.h"
28 extern int debug_threads
;
30 #ifdef HAVE_THREAD_DB_H
31 #include <thread_db.h>
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
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>
46 #include "../gdb_proc_service.h"
48 /* Structure that identifies the child process for the
49 <proc_service.h> interface. */
50 static struct ps_prochandle proc_handle
;
52 /* Connection to the libthread_db library. */
53 static td_thragent_t
*thread_agent
;
55 static int find_new_threads_callback (const td_thrhandle_t
*th_p
, void *data
);
58 thread_db_err_str (td_err_e err
)
65 return "generic 'call succeeded'";
67 return "generic error";
69 return "no thread to satisfy query";
71 return "no sync handle to satisfy query";
73 return "no LWP to satisfy query";
75 return "invalid process handle";
77 return "invalid thread handle";
79 return "invalid synchronization handle";
81 return "invalid thread agent";
85 return "no event message for getmsg";
87 return "FPU register set not available";
89 return "application not linked with libthread";
91 return "requested event is not supported";
93 return "capability not available";
95 return "debugger service failed";
97 return "operation not applicable to";
99 return "no thread-specific data for this thread";
101 return "malloc failed";
103 return "only part of register set was written/read";
105 return "X register set not available for this thread";
107 snprintf (buf
, sizeof (buf
), "unknown thread_db error '%d'", err
);
114 thread_db_state_str (td_thr_state_e state
)
121 return "stopped by debugger";
130 case TD_THR_STOPPED_ASLEEP
:
131 return "stopped by debugger AND blocked";
133 snprintf (buf
, sizeof (buf
), "unknown thread_db state %d", state
);
140 thread_db_create_event (CORE_ADDR where
)
144 struct inferior_linux_data
*tdata
;
147 fprintf (stderr
, "Thread creation event.\n");
149 tdata
= inferior_target_data (current_inferior
);
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
);
157 fprintf (stderr
, "thread getmsg err: %s\n",
158 thread_db_err_str (err
));
160 /* msg.event == TD_EVENT_CREATE */
162 find_new_threads_callback (msg
.th_p
, NULL
);
167 thread_db_death_event (CORE_ADDR where
)
170 fprintf (stderr
, "Thread death event.\n");
175 thread_db_enable_reporting ()
177 td_thr_events_t events
;
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
);
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
);
191 err
= td_ta_set_event (thread_agent
, &events
);
194 warning ("Unable to set global thread event mask: %s",
195 thread_db_err_str (err
));
199 /* Get address for thread creation breakpoint. */
200 err
= td_ta_event_addr (thread_agent
, TD_CREATE
, ¬ify
);
203 warning ("Unable to get location for thread creation breakpoint: %s",
204 thread_db_err_str (err
));
207 set_breakpoint_at ((CORE_ADDR
) (unsigned long) notify
.u
.bptaddr
,
208 thread_db_create_event
);
211 /* Don't concern ourselves with reported thread deaths, only
212 with actual thread deaths (via wait). */
214 /* Get address for thread death breakpoint. */
215 err
= td_ta_event_addr (thread_agent
, TD_DEATH
, ¬ify
);
218 warning ("Unable to get location for thread death breakpoint: %s",
219 thread_db_err_str (err
));
222 set_breakpoint_at ((CORE_ADDR
) (unsigned long) notify
.u
.bptaddr
,
223 thread_db_death_event
);
230 maybe_attach_thread (const td_thrhandle_t
*th_p
, td_thrinfo_t
*ti_p
)
233 struct thread_info
*inferior
;
234 struct process_info
*process
;
236 /* If we are attaching to our first thread, things are a little
238 if (all_threads
.head
== all_threads
.tail
)
240 inferior
= (struct thread_info
*) all_threads
.head
;
241 process
= get_thread_process (inferior
);
242 if (process
->thread_known
== 0)
244 /* Switch to indexing the threads list by TID. */
245 change_inferior_id (&all_threads
, ti_p
->ti_tid
);
250 inferior
= (struct thread_info
*) find_inferior_id (&all_threads
,
252 if (inferior
!= NULL
)
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
,
261 if (inferior
== NULL
)
263 warning ("Could not attach to thread %ld (LWP %d)\n",
264 ti_p
->ti_tid
, ti_p
->ti_lid
);
268 process
= inferior_target_data (inferior
);
271 new_thread_notify (ti_p
->ti_tid
);
273 process
->tid
= ti_p
->ti_tid
;
274 process
->lwpid
= ti_p
->ti_lid
;
276 process
->thread_known
= 1;
277 err
= td_thr_event_enable (th_p
, 1);
279 error ("Cannot enable thread event reporting for %d: %s",
280 ti_p
->ti_lid
, thread_db_err_str (err
));
284 find_new_threads_callback (const td_thrhandle_t
*th_p
, void *data
)
289 err
= td_thr_get_info (th_p
, &ti
);
291 error ("Cannot get thread info: %s", thread_db_err_str (err
));
293 /* Check for zombies. */
294 if (ti
.ti_state
== TD_THR_UNKNOWN
|| ti
.ti_state
== TD_THR_ZOMBIE
)
297 maybe_attach_thread (th_p
, &ti
);
303 thread_db_find_new_threads (void)
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
);
312 error ("Cannot find new threads: %s", thread_db_err_str (err
));
315 /* Cache all future symbols that thread_db might request. We can not
316 request symbols at arbitrary states in the remote protocol, only
317 when the client tells us that new symbols are available. So when
318 we load the thread library, make sure to check the entire list. */
321 thread_db_look_up_symbols (void)
323 const char **sym_list
= td_symbol_list ();
326 for (sym_list
= td_symbol_list (); *sym_list
; sym_list
++)
327 look_up_one_symbol (*sym_list
, &unused
);
335 /* FIXME drow/2004-10-16: This is the "overall process ID", which
336 GNU/Linux calls tgid, "thread group ID". When we support
337 attaching to threads, the original thread may not be the correct
338 thread. We would have to get the process ID from /proc for NPTL.
339 For LinuxThreads we could do something similar: follow the chain
340 of parent processes until we find the highest one we're attached
341 to, and use its tgid.
343 This isn't the only place in gdbserver that assumes that the first
344 process in the list is the thread group leader. */
345 proc_handle
.pid
= ((struct inferior_list_entry
*)current_inferior
)->id
;
347 err
= td_ta_new (&proc_handle
, &thread_agent
);
351 /* No thread library was detected. */
355 /* The thread library was detected. */
357 if (thread_db_enable_reporting () == 0)
359 thread_db_find_new_threads ();
360 thread_db_look_up_symbols ();
364 warning ("error initializing thread_db library.");