1130803Smarcel/* Thread management interface, for the remote server for GDB.
2130803Smarcel   Copyright 2002
3130803Smarcel   Free Software Foundation, Inc.
4130803Smarcel
5130803Smarcel   Contributed by MontaVista Software.
6130803Smarcel
7130803Smarcel   This file is part of GDB.
8130803Smarcel
9130803Smarcel   This program is free software; you can redistribute it and/or modify
10130803Smarcel   it under the terms of the GNU General Public License as published by
11130803Smarcel   the Free Software Foundation; either version 2 of the License, or
12130803Smarcel   (at your option) any later version.
13130803Smarcel
14130803Smarcel   This program is distributed in the hope that it will be useful,
15130803Smarcel   but WITHOUT ANY WARRANTY; without even the implied warranty of
16130803Smarcel   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
17130803Smarcel   GNU General Public License for more details.
18130803Smarcel
19130803Smarcel   You should have received a copy of the GNU General Public License
20130803Smarcel   along with this program; if not, write to the Free Software
21130803Smarcel   Foundation, Inc., 59 Temple Place - Suite 330,
22130803Smarcel   Boston, MA 02111-1307, USA.  */
23130803Smarcel
24130803Smarcel#include "server.h"
25130803Smarcel
26130803Smarcel#include "linux-low.h"
27130803Smarcel
28130803Smarcelextern int debug_threads;
29130803Smarcel
30130803Smarcel#ifdef HAVE_THREAD_DB_H
31130803Smarcel#include <thread_db.h>
32130803Smarcel#endif
33130803Smarcel
34130803Smarcel/* Correct for all GNU/Linux targets (for quite some time).  */
35130803Smarcel#define GDB_GREGSET_T elf_gregset_t
36130803Smarcel#define GDB_FPREGSET_T elf_fpregset_t
37130803Smarcel
38130803Smarcel#ifndef HAVE_ELF_FPREGSET_T
39130803Smarcel/* Make sure we have said types.  Not all platforms bring in <linux/elf.h>
40130803Smarcel   via <sys/procfs.h>.  */
41130803Smarcel#ifdef HAVE_LINUX_ELF_H
42130803Smarcel#include <linux/elf.h>
43130803Smarcel#endif
44130803Smarcel#endif
45130803Smarcel
46130803Smarcel#include "../gdb_proc_service.h"
47130803Smarcel
48130803Smarcel/* Structure that identifies the child process for the
49130803Smarcel   <proc_service.h> interface.  */
50130803Smarcelstatic struct ps_prochandle proc_handle;
51130803Smarcel
52130803Smarcel/* Connection to the libthread_db library.  */
53130803Smarcelstatic td_thragent_t *thread_agent;
54130803Smarcel
55130803Smarcelstatic int find_new_threads_callback (const td_thrhandle_t *th_p, void *data);
56130803Smarcel
57130803Smarcelstatic char *
58130803Smarcelthread_db_err_str (td_err_e err)
59130803Smarcel{
60130803Smarcel  static char buf[64];
61130803Smarcel
62130803Smarcel  switch (err)
63130803Smarcel    {
64130803Smarcel    case TD_OK:
65130803Smarcel      return "generic 'call succeeded'";
66130803Smarcel    case TD_ERR:
67130803Smarcel      return "generic error";
68130803Smarcel    case TD_NOTHR:
69130803Smarcel      return "no thread to satisfy query";
70130803Smarcel    case TD_NOSV:
71130803Smarcel      return "no sync handle to satisfy query";
72130803Smarcel    case TD_NOLWP:
73130803Smarcel      return "no LWP to satisfy query";
74130803Smarcel    case TD_BADPH:
75130803Smarcel      return "invalid process handle";
76130803Smarcel    case TD_BADTH:
77130803Smarcel      return "invalid thread handle";
78130803Smarcel    case TD_BADSH:
79130803Smarcel      return "invalid synchronization handle";
80130803Smarcel    case TD_BADTA:
81130803Smarcel      return "invalid thread agent";
82130803Smarcel    case TD_BADKEY:
83130803Smarcel      return "invalid key";
84130803Smarcel    case TD_NOMSG:
85130803Smarcel      return "no event message for getmsg";
86130803Smarcel    case TD_NOFPREGS:
87130803Smarcel      return "FPU register set not available";
88130803Smarcel    case TD_NOLIBTHREAD:
89130803Smarcel      return "application not linked with libthread";
90130803Smarcel    case TD_NOEVENT:
91130803Smarcel      return "requested event is not supported";
92130803Smarcel    case TD_NOCAPAB:
93130803Smarcel      return "capability not available";
94130803Smarcel    case TD_DBERR:
95130803Smarcel      return "debugger service failed";
96130803Smarcel    case TD_NOAPLIC:
97130803Smarcel      return "operation not applicable to";
98130803Smarcel    case TD_NOTSD:
99130803Smarcel      return "no thread-specific data for this thread";
100130803Smarcel    case TD_MALLOC:
101130803Smarcel      return "malloc failed";
102130803Smarcel    case TD_PARTIALREG:
103130803Smarcel      return "only part of register set was written/read";
104130803Smarcel    case TD_NOXREGS:
105130803Smarcel      return "X register set not available for this thread";
106130803Smarcel    default:
107130803Smarcel      snprintf (buf, sizeof (buf), "unknown thread_db error '%d'", err);
108130803Smarcel      return buf;
109130803Smarcel    }
110130803Smarcel}
111130803Smarcel
112130803Smarcel#if 0
113130803Smarcelstatic char *
114130803Smarcelthread_db_state_str (td_thr_state_e state)
115130803Smarcel{
116130803Smarcel  static char buf[64];
117130803Smarcel
118130803Smarcel  switch (state)
119130803Smarcel    {
120130803Smarcel    case TD_THR_STOPPED:
121130803Smarcel      return "stopped by debugger";
122130803Smarcel    case TD_THR_RUN:
123130803Smarcel      return "runnable";
124130803Smarcel    case TD_THR_ACTIVE:
125130803Smarcel      return "active";
126130803Smarcel    case TD_THR_ZOMBIE:
127130803Smarcel      return "zombie";
128130803Smarcel    case TD_THR_SLEEP:
129130803Smarcel      return "sleeping";
130130803Smarcel    case TD_THR_STOPPED_ASLEEP:
131130803Smarcel      return "stopped by debugger AND blocked";
132130803Smarcel    default:
133130803Smarcel      snprintf (buf, sizeof (buf), "unknown thread_db state %d", state);
134130803Smarcel      return buf;
135130803Smarcel    }
136130803Smarcel}
137130803Smarcel#endif
138130803Smarcel
139130803Smarcelstatic void
140130803Smarcelthread_db_create_event (CORE_ADDR where)
141130803Smarcel{
142130803Smarcel  td_event_msg_t msg;
143130803Smarcel  td_err_e err;
144130803Smarcel  struct inferior_linux_data *tdata;
145130803Smarcel
146130803Smarcel  if (debug_threads)
147130803Smarcel    fprintf (stderr, "Thread creation event.\n");
148130803Smarcel
149130803Smarcel  tdata = inferior_target_data (current_inferior);
150130803Smarcel
151130803Smarcel  /* FIXME: This assumes we don't get another event.
152130803Smarcel     In the LinuxThreads implementation, this is safe,
153130803Smarcel     because all events come from the manager thread
154130803Smarcel     (except for its own creation, of course).  */
155130803Smarcel  err = td_ta_event_getmsg (thread_agent, &msg);
156130803Smarcel  if (err != TD_OK)
157130803Smarcel    fprintf (stderr, "thread getmsg err: %s\n",
158130803Smarcel	     thread_db_err_str (err));
159130803Smarcel
160130803Smarcel  /* msg.event == TD_EVENT_CREATE */
161130803Smarcel
162130803Smarcel  find_new_threads_callback (msg.th_p, NULL);
163130803Smarcel}
164130803Smarcel
165130803Smarcel#if 0
166130803Smarcelstatic void
167130803Smarcelthread_db_death_event (CORE_ADDR where)
168130803Smarcel{
169130803Smarcel  if (debug_threads)
170130803Smarcel    fprintf (stderr, "Thread death event.\n");
171130803Smarcel}
172130803Smarcel#endif
173130803Smarcel
174130803Smarcelstatic int
175130803Smarcelthread_db_enable_reporting ()
176130803Smarcel{
177130803Smarcel  td_thr_events_t events;
178130803Smarcel  td_notify_t notify;
179130803Smarcel  td_err_e err;
180130803Smarcel
181130803Smarcel  /* Set the process wide mask saying which events we're interested in.  */
182130803Smarcel  td_event_emptyset (&events);
183130803Smarcel  td_event_addset (&events, TD_CREATE);
184130803Smarcel
185130803Smarcel#if 0
186130803Smarcel  /* This is reported to be broken in glibc 2.1.3.  A different approach
187130803Smarcel     will be necessary to support that.  */
188130803Smarcel  td_event_addset (&events, TD_DEATH);
189130803Smarcel#endif
190130803Smarcel
191130803Smarcel  err = td_ta_set_event (thread_agent, &events);
192130803Smarcel  if (err != TD_OK)
193130803Smarcel    {
194130803Smarcel      warning ("Unable to set global thread event mask: %s",
195130803Smarcel               thread_db_err_str (err));
196130803Smarcel      return 0;
197130803Smarcel    }
198130803Smarcel
199130803Smarcel  /* Get address for thread creation breakpoint.  */
200130803Smarcel  err = td_ta_event_addr (thread_agent, TD_CREATE, &notify);
201130803Smarcel  if (err != TD_OK)
202130803Smarcel    {
203130803Smarcel      warning ("Unable to get location for thread creation breakpoint: %s",
204130803Smarcel	       thread_db_err_str (err));
205130803Smarcel      return 0;
206130803Smarcel    }
207130803Smarcel  set_breakpoint_at ((CORE_ADDR) (unsigned long) notify.u.bptaddr,
208130803Smarcel		     thread_db_create_event);
209130803Smarcel
210130803Smarcel#if 0
211130803Smarcel  /* Don't concern ourselves with reported thread deaths, only
212130803Smarcel     with actual thread deaths (via wait).  */
213130803Smarcel
214130803Smarcel  /* Get address for thread death breakpoint.  */
215130803Smarcel  err = td_ta_event_addr (thread_agent, TD_DEATH, &notify);
216130803Smarcel  if (err != TD_OK)
217130803Smarcel    {
218130803Smarcel      warning ("Unable to get location for thread death breakpoint: %s",
219130803Smarcel	       thread_db_err_str (err));
220130803Smarcel      return;
221130803Smarcel    }
222130803Smarcel  set_breakpoint_at ((CORE_ADDR) (unsigned long) notify.u.bptaddr,
223130803Smarcel		     thread_db_death_event);
224130803Smarcel#endif
225130803Smarcel
226130803Smarcel  return 1;
227130803Smarcel}
228130803Smarcel
229130803Smarcelstatic void
230130803Smarcelmaybe_attach_thread (const td_thrhandle_t *th_p, td_thrinfo_t *ti_p)
231130803Smarcel{
232130803Smarcel  td_err_e err;
233130803Smarcel  struct thread_info *inferior;
234130803Smarcel  struct process_info *process;
235130803Smarcel
236130803Smarcel  /* If we are attaching to our first thread, things are a little
237130803Smarcel     different.  */
238130803Smarcel  if (all_threads.head == all_threads.tail)
239130803Smarcel    {
240130803Smarcel      inferior = (struct thread_info *) all_threads.head;
241130803Smarcel      process = get_thread_process (inferior);
242130803Smarcel      if (process->thread_known == 0)
243130803Smarcel	{
244130803Smarcel	  /* Switch to indexing the threads list by TID.  */
245130803Smarcel	  change_inferior_id (&all_threads, ti_p->ti_tid);
246130803Smarcel	  goto found;
247130803Smarcel	}
248130803Smarcel    }
249130803Smarcel
250130803Smarcel  inferior = (struct thread_info *) find_inferior_id (&all_threads,
251130803Smarcel						      ti_p->ti_tid);
252130803Smarcel  if (inferior != NULL)
253130803Smarcel    return;
254130803Smarcel
255130803Smarcel  if (debug_threads)
256130803Smarcel    fprintf (stderr, "Attaching to thread %ld (LWP %d)\n",
257130803Smarcel	     ti_p->ti_tid, ti_p->ti_lid);
258130803Smarcel  linux_attach_lwp (ti_p->ti_lid, ti_p->ti_tid);
259130803Smarcel  inferior = (struct thread_info *) find_inferior_id (&all_threads,
260130803Smarcel						      ti_p->ti_tid);
261130803Smarcel  if (inferior == NULL)
262130803Smarcel    {
263130803Smarcel      warning ("Could not attach to thread %ld (LWP %d)\n",
264130803Smarcel	       ti_p->ti_tid, ti_p->ti_lid);
265130803Smarcel      return;
266130803Smarcel    }
267130803Smarcel
268130803Smarcel  process = inferior_target_data (inferior);
269130803Smarcel
270130803Smarcelfound:
271130803Smarcel  new_thread_notify (ti_p->ti_tid);
272130803Smarcel
273130803Smarcel  process->tid = ti_p->ti_tid;
274130803Smarcel  process->lwpid = ti_p->ti_lid;
275130803Smarcel
276130803Smarcel  process->thread_known = 1;
277130803Smarcel  err = td_thr_event_enable (th_p, 1);
278130803Smarcel  if (err != TD_OK)
279130803Smarcel    error ("Cannot enable thread event reporting for %d: %s",
280130803Smarcel           ti_p->ti_lid, thread_db_err_str (err));
281130803Smarcel}
282130803Smarcel
283130803Smarcelstatic int
284130803Smarcelfind_new_threads_callback (const td_thrhandle_t *th_p, void *data)
285130803Smarcel{
286130803Smarcel  td_thrinfo_t ti;
287130803Smarcel  td_err_e err;
288130803Smarcel
289130803Smarcel  err = td_thr_get_info (th_p, &ti);
290130803Smarcel  if (err != TD_OK)
291130803Smarcel    error ("Cannot get thread info: %s", thread_db_err_str (err));
292130803Smarcel
293130803Smarcel  /* Check for zombies.  */
294130803Smarcel  if (ti.ti_state == TD_THR_UNKNOWN || ti.ti_state == TD_THR_ZOMBIE)
295130803Smarcel    return 0;
296130803Smarcel
297130803Smarcel  maybe_attach_thread (th_p, &ti);
298130803Smarcel
299130803Smarcel  return 0;
300130803Smarcel}
301130803Smarcel
302130803Smarcelstatic void
303130803Smarcelthread_db_find_new_threads (void)
304130803Smarcel{
305130803Smarcel  td_err_e err;
306130803Smarcel
307130803Smarcel  /* Iterate over all user-space threads to discover new threads.  */
308130803Smarcel  err = td_ta_thr_iter (thread_agent, find_new_threads_callback, NULL,
309130803Smarcel			TD_THR_ANY_STATE, TD_THR_LOWEST_PRIORITY,
310130803Smarcel			TD_SIGNO_MASK, TD_THR_ANY_USER_FLAGS);
311130803Smarcel  if (err != TD_OK)
312130803Smarcel    error ("Cannot find new threads: %s", thread_db_err_str (err));
313130803Smarcel}
314130803Smarcel
315130803Smarcelint
316130803Smarcelthread_db_init ()
317130803Smarcel{
318130803Smarcel  int err;
319130803Smarcel
320130803Smarcel  proc_handle.pid = ((struct inferior_list_entry *)current_inferior)->id;
321130803Smarcel
322130803Smarcel  err = td_ta_new (&proc_handle, &thread_agent);
323130803Smarcel  switch (err)
324130803Smarcel    {
325130803Smarcel    case TD_NOLIBTHREAD:
326130803Smarcel      /* No thread library was detected.  */
327130803Smarcel      return 0;
328130803Smarcel
329130803Smarcel    case TD_OK:
330130803Smarcel      /* The thread library was detected.  */
331130803Smarcel
332130803Smarcel      if (thread_db_enable_reporting () == 0)
333130803Smarcel	return 0;
334130803Smarcel      thread_db_find_new_threads ();
335130803Smarcel      return 1;
336130803Smarcel
337130803Smarcel    default:
338130803Smarcel      warning ("error initializing thread_db library.");
339130803Smarcel    }
340130803Smarcel
341130803Smarcel  return 0;
342130803Smarcel}
343