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}
343