OpenCores
URL https://opencores.org/ocsvn/or1k/or1k/trunk

Subversion Repositories or1k

[/] [or1k/] [trunk/] [gdb-5.3/] [gdb/] [gdbserver/] [thread-db.c] - Blame information for rev 1774

Go to most recent revision | Details | Compare with Previous | View Log

Line No. Rev Author Line
1 1181 sfurman
/* 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
 
28
extern 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.  */
50
static struct ps_prochandle proc_handle;
51
 
52
/* Connection to the libthread_db library.  */
53
static td_thragent_t *thread_agent;
54
 
55
static int find_new_threads_callback (const td_thrhandle_t *th_p, void *data);
56
 
57
static char *
58
thread_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
113
static char *
114
thread_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
 
139
static void
140
thread_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
166
static void
167
thread_db_death_event (CORE_ADDR where)
168
{
169
  if (debug_threads)
170
    fprintf (stderr, "Thread death event.\n");
171
}
172
#endif
173
 
174
static int
175
thread_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
 
229
static void
230
maybe_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
 
270
found:
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
 
283
static int
284
find_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
 
302
static void
303
thread_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
 
315
int
316
thread_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
}

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.