1 /* Thread management interface, for the remote server for GDB.
2 Copyright 2002, 2004, 2005
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";
106 #ifdef HAVE_TD_VERSION
108 return "version mismatch between libthread_db and libpthread";
111 snprintf (buf, sizeof (buf), "unknown thread_db error '%d'", err);
118 thread_db_state_str (td_thr_state_e state)
125 return "stopped by debugger";
134 case TD_THR_STOPPED_ASLEEP:
135 return "stopped by debugger AND blocked";
137 snprintf (buf, sizeof (buf), "unknown thread_db state %d", state);
144 thread_db_create_event (CORE_ADDR where)
148 struct inferior_linux_data *tdata;
151 fprintf (stderr, "Thread creation event.\n");
153 tdata = inferior_target_data (current_inferior);
155 /* FIXME: This assumes we don't get another event.
156 In the LinuxThreads implementation, this is safe,
157 because all events come from the manager thread
158 (except for its own creation, of course). */
159 err = td_ta_event_getmsg (thread_agent, &msg);
161 fprintf (stderr, "thread getmsg err: %s\n",
162 thread_db_err_str (err));
164 /* msg.event == TD_EVENT_CREATE */
166 find_new_threads_callback (msg.th_p, NULL);
171 thread_db_death_event (CORE_ADDR where)
174 fprintf (stderr, "Thread death event.\n");
179 thread_db_enable_reporting ()
181 td_thr_events_t events;
185 /* Set the process wide mask saying which events we're interested in. */
186 td_event_emptyset (&events);
187 td_event_addset (&events, TD_CREATE);
190 /* This is reported to be broken in glibc 2.1.3. A different approach
191 will be necessary to support that. */
192 td_event_addset (&events, TD_DEATH);
195 err = td_ta_set_event (thread_agent, &events);
198 warning ("Unable to set global thread event mask: %s",
199 thread_db_err_str (err));
203 /* Get address for thread creation breakpoint. */
204 err = td_ta_event_addr (thread_agent, TD_CREATE, ¬ify);
207 warning ("Unable to get location for thread creation breakpoint: %s",
208 thread_db_err_str (err));
211 set_breakpoint_at ((CORE_ADDR) (unsigned long) notify.u.bptaddr,
212 thread_db_create_event);
215 /* Don't concern ourselves with reported thread deaths, only
216 with actual thread deaths (via wait). */
218 /* Get address for thread death breakpoint. */
219 err = td_ta_event_addr (thread_agent, TD_DEATH, ¬ify);
222 warning ("Unable to get location for thread death breakpoint: %s",
223 thread_db_err_str (err));
226 set_breakpoint_at ((CORE_ADDR) (unsigned long) notify.u.bptaddr,
227 thread_db_death_event);
234 maybe_attach_thread (const td_thrhandle_t *th_p, td_thrinfo_t *ti_p)
237 struct thread_info *inferior;
238 struct process_info *process;
240 /* If we are attaching to our first thread, things are a little
242 if (all_threads.head == all_threads.tail)
244 inferior = (struct thread_info *) all_threads.head;
245 process = get_thread_process (inferior);
246 if (process->thread_known == 0)
248 /* Switch to indexing the threads list by TID. */
249 change_inferior_id (&all_threads, ti_p->ti_tid);
254 inferior = (struct thread_info *) find_inferior_id (&all_threads,
256 if (inferior != NULL)
260 fprintf (stderr, "Attaching to thread %ld (LWP %d)\n",
261 ti_p->ti_tid, ti_p->ti_lid);
262 linux_attach_lwp (ti_p->ti_lid, ti_p->ti_tid);
263 inferior = (struct thread_info *) find_inferior_id (&all_threads,
265 if (inferior == NULL)
267 warning ("Could not attach to thread %ld (LWP %d)\n",
268 ti_p->ti_tid, ti_p->ti_lid);
272 process = inferior_target_data (inferior);
275 new_thread_notify (ti_p->ti_tid);
277 process->tid = ti_p->ti_tid;
278 process->lwpid = ti_p->ti_lid;
280 process->thread_known = 1;
281 err = td_thr_event_enable (th_p, 1);
283 error ("Cannot enable thread event reporting for %d: %s",
284 ti_p->ti_lid, thread_db_err_str (err));
288 find_new_threads_callback (const td_thrhandle_t *th_p, void *data)
293 err = td_thr_get_info (th_p, &ti);
295 error ("Cannot get thread info: %s", thread_db_err_str (err));
297 /* Check for zombies. */
298 if (ti.ti_state == TD_THR_UNKNOWN || ti.ti_state == TD_THR_ZOMBIE)
301 maybe_attach_thread (th_p, &ti);
307 thread_db_find_new_threads (void)
311 /* Iterate over all user-space threads to discover new threads. */
312 err = td_ta_thr_iter (thread_agent, find_new_threads_callback, NULL,
313 TD_THR_ANY_STATE, TD_THR_LOWEST_PRIORITY,
314 TD_SIGNO_MASK, TD_THR_ANY_USER_FLAGS);
316 error ("Cannot find new threads: %s", thread_db_err_str (err));
319 /* Cache all future symbols that thread_db might request. We can not
320 request symbols at arbitrary states in the remote protocol, only
321 when the client tells us that new symbols are available. So when
322 we load the thread library, make sure to check the entire list. */
325 thread_db_look_up_symbols (void)
327 const char **sym_list = td_symbol_list ();
330 for (sym_list = td_symbol_list (); *sym_list; sym_list++)
331 look_up_one_symbol (*sym_list, &unused);
339 /* FIXME drow/2004-10-16: This is the "overall process ID", which
340 GNU/Linux calls tgid, "thread group ID". When we support
341 attaching to threads, the original thread may not be the correct
342 thread. We would have to get the process ID from /proc for NPTL.
343 For LinuxThreads we could do something similar: follow the chain
344 of parent processes until we find the highest one we're attached
345 to, and use its tgid.
347 This isn't the only place in gdbserver that assumes that the first
348 process in the list is the thread group leader. */
349 proc_handle.pid = ((struct inferior_list_entry *)current_inferior)->id;
351 err = td_ta_new (&proc_handle, &thread_agent);
355 /* No thread library was detected. */
359 /* The thread library was detected. */
361 if (thread_db_enable_reporting () == 0)
363 thread_db_find_new_threads ();
364 thread_db_look_up_symbols ();
368 warning ("error initializing thread_db library: %s",
369 thread_db_err_str (err));