OpenCores
URL https://opencores.org/ocsvn/openrisc_2011-10-31/openrisc_2011-10-31/trunk

Subversion Repositories openrisc_2011-10-31

[/] [openrisc/] [tags/] [gnu-src/] [gdb-6.8/] [pre-binutils-2.20.1-sync/] [gdb/] [gdbserver/] [thread-db.c] - Diff between revs 157 and 223

Only display areas with differences | Details | Blame | View Log

Rev 157 Rev 223
/* Thread management interface, for the remote server for GDB.
/* Thread management interface, for the remote server for GDB.
   Copyright (C) 2002, 2004, 2005, 2006, 2007, 2008
   Copyright (C) 2002, 2004, 2005, 2006, 2007, 2008
   Free Software Foundation, Inc.
   Free Software Foundation, Inc.
 
 
   Contributed by MontaVista Software.
   Contributed by MontaVista Software.
 
 
   This file is part of GDB.
   This file is part of GDB.
 
 
   This program is free software; you can redistribute it and/or modify
   This program is free software; you can redistribute it and/or modify
   it under the terms of the GNU General Public License as published by
   it under the terms of the GNU General Public License as published by
   the Free Software Foundation; either version 3 of the License, or
   the Free Software Foundation; either version 3 of the License, or
   (at your option) any later version.
   (at your option) any later version.
 
 
   This program is distributed in the hope that it will be useful,
   This program is distributed in the hope that it will be useful,
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   but WITHOUT ANY WARRANTY; without even the implied warranty of
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
   GNU General Public License for more details.
   GNU General Public License for more details.
 
 
   You should have received a copy of the GNU General Public License
   You should have received a copy of the GNU General Public License
   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
 
 
#include "server.h"
#include "server.h"
 
 
#include "linux-low.h"
#include "linux-low.h"
 
 
extern int debug_threads;
extern int debug_threads;
 
 
static int thread_db_use_events;
static int thread_db_use_events;
 
 
#ifdef HAVE_THREAD_DB_H
#ifdef HAVE_THREAD_DB_H
#include <thread_db.h>
#include <thread_db.h>
#endif
#endif
 
 
#include "gdb_proc_service.h"
#include "gdb_proc_service.h"
 
 
#include <stdint.h>
#include <stdint.h>
 
 
/* Structure that identifies the child process for the
/* Structure that identifies the child process for the
   <proc_service.h> interface.  */
   <proc_service.h> interface.  */
static struct ps_prochandle proc_handle;
static struct ps_prochandle proc_handle;
 
 
/* Connection to the libthread_db library.  */
/* Connection to the libthread_db library.  */
static td_thragent_t *thread_agent;
static td_thragent_t *thread_agent;
 
 
static int find_one_thread (int);
static int find_one_thread (int);
static int find_new_threads_callback (const td_thrhandle_t *th_p, void *data);
static int find_new_threads_callback (const td_thrhandle_t *th_p, void *data);
 
 
static char *
static char *
thread_db_err_str (td_err_e err)
thread_db_err_str (td_err_e err)
{
{
  static char buf[64];
  static char buf[64];
 
 
  switch (err)
  switch (err)
    {
    {
    case TD_OK:
    case TD_OK:
      return "generic 'call succeeded'";
      return "generic 'call succeeded'";
    case TD_ERR:
    case TD_ERR:
      return "generic error";
      return "generic error";
    case TD_NOTHR:
    case TD_NOTHR:
      return "no thread to satisfy query";
      return "no thread to satisfy query";
    case TD_NOSV:
    case TD_NOSV:
      return "no sync handle to satisfy query";
      return "no sync handle to satisfy query";
    case TD_NOLWP:
    case TD_NOLWP:
      return "no LWP to satisfy query";
      return "no LWP to satisfy query";
    case TD_BADPH:
    case TD_BADPH:
      return "invalid process handle";
      return "invalid process handle";
    case TD_BADTH:
    case TD_BADTH:
      return "invalid thread handle";
      return "invalid thread handle";
    case TD_BADSH:
    case TD_BADSH:
      return "invalid synchronization handle";
      return "invalid synchronization handle";
    case TD_BADTA:
    case TD_BADTA:
      return "invalid thread agent";
      return "invalid thread agent";
    case TD_BADKEY:
    case TD_BADKEY:
      return "invalid key";
      return "invalid key";
    case TD_NOMSG:
    case TD_NOMSG:
      return "no event message for getmsg";
      return "no event message for getmsg";
    case TD_NOFPREGS:
    case TD_NOFPREGS:
      return "FPU register set not available";
      return "FPU register set not available";
    case TD_NOLIBTHREAD:
    case TD_NOLIBTHREAD:
      return "application not linked with libthread";
      return "application not linked with libthread";
    case TD_NOEVENT:
    case TD_NOEVENT:
      return "requested event is not supported";
      return "requested event is not supported";
    case TD_NOCAPAB:
    case TD_NOCAPAB:
      return "capability not available";
      return "capability not available";
    case TD_DBERR:
    case TD_DBERR:
      return "debugger service failed";
      return "debugger service failed";
    case TD_NOAPLIC:
    case TD_NOAPLIC:
      return "operation not applicable to";
      return "operation not applicable to";
    case TD_NOTSD:
    case TD_NOTSD:
      return "no thread-specific data for this thread";
      return "no thread-specific data for this thread";
    case TD_MALLOC:
    case TD_MALLOC:
      return "malloc failed";
      return "malloc failed";
    case TD_PARTIALREG:
    case TD_PARTIALREG:
      return "only part of register set was written/read";
      return "only part of register set was written/read";
    case TD_NOXREGS:
    case TD_NOXREGS:
      return "X register set not available for this thread";
      return "X register set not available for this thread";
#ifdef HAVE_TD_VERSION
#ifdef HAVE_TD_VERSION
    case TD_VERSION:
    case TD_VERSION:
      return "version mismatch between libthread_db and libpthread";
      return "version mismatch between libthread_db and libpthread";
#endif
#endif
    default:
    default:
      snprintf (buf, sizeof (buf), "unknown thread_db error '%d'", err);
      snprintf (buf, sizeof (buf), "unknown thread_db error '%d'", err);
      return buf;
      return buf;
    }
    }
}
}
 
 
#if 0
#if 0
static char *
static char *
thread_db_state_str (td_thr_state_e state)
thread_db_state_str (td_thr_state_e state)
{
{
  static char buf[64];
  static char buf[64];
 
 
  switch (state)
  switch (state)
    {
    {
    case TD_THR_STOPPED:
    case TD_THR_STOPPED:
      return "stopped by debugger";
      return "stopped by debugger";
    case TD_THR_RUN:
    case TD_THR_RUN:
      return "runnable";
      return "runnable";
    case TD_THR_ACTIVE:
    case TD_THR_ACTIVE:
      return "active";
      return "active";
    case TD_THR_ZOMBIE:
    case TD_THR_ZOMBIE:
      return "zombie";
      return "zombie";
    case TD_THR_SLEEP:
    case TD_THR_SLEEP:
      return "sleeping";
      return "sleeping";
    case TD_THR_STOPPED_ASLEEP:
    case TD_THR_STOPPED_ASLEEP:
      return "stopped by debugger AND blocked";
      return "stopped by debugger AND blocked";
    default:
    default:
      snprintf (buf, sizeof (buf), "unknown thread_db state %d", state);
      snprintf (buf, sizeof (buf), "unknown thread_db state %d", state);
      return buf;
      return buf;
    }
    }
}
}
#endif
#endif
 
 
static int
static int
thread_db_create_event (CORE_ADDR where)
thread_db_create_event (CORE_ADDR where)
{
{
  td_event_msg_t msg;
  td_event_msg_t msg;
  td_err_e err;
  td_err_e err;
  struct process_info *process;
  struct process_info *process;
 
 
  if (debug_threads)
  if (debug_threads)
    fprintf (stderr, "Thread creation event.\n");
    fprintf (stderr, "Thread creation event.\n");
 
 
  /* FIXME: This assumes we don't get another event.
  /* FIXME: This assumes we don't get another event.
     In the LinuxThreads implementation, this is safe,
     In the LinuxThreads implementation, this is safe,
     because all events come from the manager thread
     because all events come from the manager thread
     (except for its own creation, of course).  */
     (except for its own creation, of course).  */
  err = td_ta_event_getmsg (thread_agent, &msg);
  err = td_ta_event_getmsg (thread_agent, &msg);
  if (err != TD_OK)
  if (err != TD_OK)
    fprintf (stderr, "thread getmsg err: %s\n",
    fprintf (stderr, "thread getmsg err: %s\n",
             thread_db_err_str (err));
             thread_db_err_str (err));
 
 
  /* If we do not know about the main thread yet, this would be a good time to
  /* If we do not know about the main thread yet, this would be a good time to
     find it.  We need to do this to pick up the main thread before any newly
     find it.  We need to do this to pick up the main thread before any newly
     created threads.  */
     created threads.  */
  process = get_thread_process (current_inferior);
  process = get_thread_process (current_inferior);
  if (process->thread_known == 0)
  if (process->thread_known == 0)
    find_one_thread (process->lwpid);
    find_one_thread (process->lwpid);
 
 
  /* msg.event == TD_EVENT_CREATE */
  /* msg.event == TD_EVENT_CREATE */
 
 
  find_new_threads_callback (msg.th_p, NULL);
  find_new_threads_callback (msg.th_p, NULL);
 
 
  return 0;
  return 0;
}
}
 
 
#if 0
#if 0
static int
static int
thread_db_death_event (CORE_ADDR where)
thread_db_death_event (CORE_ADDR where)
{
{
  if (debug_threads)
  if (debug_threads)
    fprintf (stderr, "Thread death event.\n");
    fprintf (stderr, "Thread death event.\n");
 
 
  return 0;
  return 0;
}
}
#endif
#endif
 
 
static int
static int
thread_db_enable_reporting ()
thread_db_enable_reporting ()
{
{
  td_thr_events_t events;
  td_thr_events_t events;
  td_notify_t notify;
  td_notify_t notify;
  td_err_e err;
  td_err_e err;
 
 
  /* Set the process wide mask saying which events we're interested in.  */
  /* Set the process wide mask saying which events we're interested in.  */
  td_event_emptyset (&events);
  td_event_emptyset (&events);
  td_event_addset (&events, TD_CREATE);
  td_event_addset (&events, TD_CREATE);
 
 
#if 0
#if 0
  /* This is reported to be broken in glibc 2.1.3.  A different approach
  /* This is reported to be broken in glibc 2.1.3.  A different approach
     will be necessary to support that.  */
     will be necessary to support that.  */
  td_event_addset (&events, TD_DEATH);
  td_event_addset (&events, TD_DEATH);
#endif
#endif
 
 
  err = td_ta_set_event (thread_agent, &events);
  err = td_ta_set_event (thread_agent, &events);
  if (err != TD_OK)
  if (err != TD_OK)
    {
    {
      warning ("Unable to set global thread event mask: %s",
      warning ("Unable to set global thread event mask: %s",
               thread_db_err_str (err));
               thread_db_err_str (err));
      return 0;
      return 0;
    }
    }
 
 
  /* Get address for thread creation breakpoint.  */
  /* Get address for thread creation breakpoint.  */
  err = td_ta_event_addr (thread_agent, TD_CREATE, &notify);
  err = td_ta_event_addr (thread_agent, TD_CREATE, &notify);
  if (err != TD_OK)
  if (err != TD_OK)
    {
    {
      warning ("Unable to get location for thread creation breakpoint: %s",
      warning ("Unable to get location for thread creation breakpoint: %s",
               thread_db_err_str (err));
               thread_db_err_str (err));
      return 0;
      return 0;
    }
    }
  set_breakpoint_at ((CORE_ADDR) (unsigned long) notify.u.bptaddr,
  set_breakpoint_at ((CORE_ADDR) (unsigned long) notify.u.bptaddr,
                     thread_db_create_event);
                     thread_db_create_event);
 
 
#if 0
#if 0
  /* Don't concern ourselves with reported thread deaths, only
  /* Don't concern ourselves with reported thread deaths, only
     with actual thread deaths (via wait).  */
     with actual thread deaths (via wait).  */
 
 
  /* Get address for thread death breakpoint.  */
  /* Get address for thread death breakpoint.  */
  err = td_ta_event_addr (thread_agent, TD_DEATH, &notify);
  err = td_ta_event_addr (thread_agent, TD_DEATH, &notify);
  if (err != TD_OK)
  if (err != TD_OK)
    {
    {
      warning ("Unable to get location for thread death breakpoint: %s",
      warning ("Unable to get location for thread death breakpoint: %s",
               thread_db_err_str (err));
               thread_db_err_str (err));
      return;
      return;
    }
    }
  set_breakpoint_at ((CORE_ADDR) (unsigned long) notify.u.bptaddr,
  set_breakpoint_at ((CORE_ADDR) (unsigned long) notify.u.bptaddr,
                     thread_db_death_event);
                     thread_db_death_event);
#endif
#endif
 
 
  return 1;
  return 1;
}
}
 
 
static int
static int
find_one_thread (int lwpid)
find_one_thread (int lwpid)
{
{
  td_thrhandle_t th;
  td_thrhandle_t th;
  td_thrinfo_t ti;
  td_thrinfo_t ti;
  td_err_e err;
  td_err_e err;
  struct thread_info *inferior;
  struct thread_info *inferior;
  struct process_info *process;
  struct process_info *process;
 
 
  inferior = (struct thread_info *) find_inferior_id (&all_threads, lwpid);
  inferior = (struct thread_info *) find_inferior_id (&all_threads, lwpid);
  process = get_thread_process (inferior);
  process = get_thread_process (inferior);
  if (process->thread_known)
  if (process->thread_known)
    return 1;
    return 1;
 
 
  /* Get information about this thread.  */
  /* Get information about this thread.  */
  err = td_ta_map_lwp2thr (thread_agent, process->lwpid, &th);
  err = td_ta_map_lwp2thr (thread_agent, process->lwpid, &th);
  if (err != TD_OK)
  if (err != TD_OK)
    error ("Cannot get thread handle for LWP %d: %s",
    error ("Cannot get thread handle for LWP %d: %s",
           lwpid, thread_db_err_str (err));
           lwpid, thread_db_err_str (err));
 
 
  err = td_thr_get_info (&th, &ti);
  err = td_thr_get_info (&th, &ti);
  if (err != TD_OK)
  if (err != TD_OK)
    error ("Cannot get thread info for LWP %d: %s",
    error ("Cannot get thread info for LWP %d: %s",
           lwpid, thread_db_err_str (err));
           lwpid, thread_db_err_str (err));
 
 
  if (debug_threads)
  if (debug_threads)
    fprintf (stderr, "Found thread %ld (LWP %d)\n",
    fprintf (stderr, "Found thread %ld (LWP %d)\n",
             ti.ti_tid, ti.ti_lid);
             ti.ti_tid, ti.ti_lid);
 
 
  if (process->lwpid != ti.ti_lid)
  if (process->lwpid != ti.ti_lid)
    {
    {
      warning ("PID mismatch!  Expected %ld, got %ld",
      warning ("PID mismatch!  Expected %ld, got %ld",
               (long) process->lwpid, (long) ti.ti_lid);
               (long) process->lwpid, (long) ti.ti_lid);
      return 0;
      return 0;
    }
    }
 
 
  if (thread_db_use_events)
  if (thread_db_use_events)
    {
    {
      err = td_thr_event_enable (&th, 1);
      err = td_thr_event_enable (&th, 1);
      if (err != TD_OK)
      if (err != TD_OK)
        error ("Cannot enable thread event reporting for %d: %s",
        error ("Cannot enable thread event reporting for %d: %s",
               ti.ti_lid, thread_db_err_str (err));
               ti.ti_lid, thread_db_err_str (err));
    }
    }
 
 
  /* If the new thread ID is zero, a final thread ID will be available
  /* If the new thread ID is zero, a final thread ID will be available
     later.  Do not enable thread debugging yet.  */
     later.  Do not enable thread debugging yet.  */
  if (ti.ti_tid == 0)
  if (ti.ti_tid == 0)
    return 0;
    return 0;
 
 
  process->thread_known = 1;
  process->thread_known = 1;
  process->tid = ti.ti_tid;
  process->tid = ti.ti_tid;
  process->th = th;
  process->th = th;
 
 
  return 1;
  return 1;
}
}
 
 
static void
static void
maybe_attach_thread (const td_thrhandle_t *th_p, td_thrinfo_t *ti_p)
maybe_attach_thread (const td_thrhandle_t *th_p, td_thrinfo_t *ti_p)
{
{
  td_err_e err;
  td_err_e err;
  struct thread_info *inferior;
  struct thread_info *inferior;
  struct process_info *process;
  struct process_info *process;
 
 
  inferior = (struct thread_info *) find_inferior_id (&all_threads,
  inferior = (struct thread_info *) find_inferior_id (&all_threads,
                                                      ti_p->ti_lid);
                                                      ti_p->ti_lid);
  if (inferior != NULL)
  if (inferior != NULL)
    return;
    return;
 
 
  if (debug_threads)
  if (debug_threads)
    fprintf (stderr, "Attaching to thread %ld (LWP %d)\n",
    fprintf (stderr, "Attaching to thread %ld (LWP %d)\n",
             ti_p->ti_tid, ti_p->ti_lid);
             ti_p->ti_tid, ti_p->ti_lid);
  linux_attach_lwp (ti_p->ti_lid);
  linux_attach_lwp (ti_p->ti_lid);
  inferior = (struct thread_info *) find_inferior_id (&all_threads,
  inferior = (struct thread_info *) find_inferior_id (&all_threads,
                                                      ti_p->ti_lid);
                                                      ti_p->ti_lid);
  if (inferior == NULL)
  if (inferior == NULL)
    {
    {
      warning ("Could not attach to thread %ld (LWP %d)\n",
      warning ("Could not attach to thread %ld (LWP %d)\n",
               ti_p->ti_tid, ti_p->ti_lid);
               ti_p->ti_tid, ti_p->ti_lid);
      return;
      return;
    }
    }
 
 
  process = inferior_target_data (inferior);
  process = inferior_target_data (inferior);
 
 
  process->tid = ti_p->ti_tid;
  process->tid = ti_p->ti_tid;
  process->thread_known = 1;
  process->thread_known = 1;
  process->th = *th_p;
  process->th = *th_p;
 
 
  if (thread_db_use_events)
  if (thread_db_use_events)
    {
    {
      err = td_thr_event_enable (th_p, 1);
      err = td_thr_event_enable (th_p, 1);
      if (err != TD_OK)
      if (err != TD_OK)
        error ("Cannot enable thread event reporting for %d: %s",
        error ("Cannot enable thread event reporting for %d: %s",
               ti_p->ti_lid, thread_db_err_str (err));
               ti_p->ti_lid, thread_db_err_str (err));
    }
    }
}
}
 
 
static int
static int
find_new_threads_callback (const td_thrhandle_t *th_p, void *data)
find_new_threads_callback (const td_thrhandle_t *th_p, void *data)
{
{
  td_thrinfo_t ti;
  td_thrinfo_t ti;
  td_err_e err;
  td_err_e err;
 
 
  err = td_thr_get_info (th_p, &ti);
  err = td_thr_get_info (th_p, &ti);
  if (err != TD_OK)
  if (err != TD_OK)
    error ("Cannot get thread info: %s", thread_db_err_str (err));
    error ("Cannot get thread info: %s", thread_db_err_str (err));
 
 
  /* Check for zombies.  */
  /* Check for zombies.  */
  if (ti.ti_state == TD_THR_UNKNOWN || ti.ti_state == TD_THR_ZOMBIE)
  if (ti.ti_state == TD_THR_UNKNOWN || ti.ti_state == TD_THR_ZOMBIE)
    return 0;
    return 0;
 
 
  maybe_attach_thread (th_p, &ti);
  maybe_attach_thread (th_p, &ti);
 
 
  return 0;
  return 0;
}
}
 
 
static void
static void
thread_db_find_new_threads (void)
thread_db_find_new_threads (void)
{
{
  td_err_e err;
  td_err_e err;
 
 
  /* This function is only called when we first initialize thread_db.
  /* This function is only called when we first initialize thread_db.
     First locate the initial thread.  If it is not ready for
     First locate the initial thread.  If it is not ready for
     debugging yet, then stop.  */
     debugging yet, then stop.  */
  if (find_one_thread (all_threads.head->id) == 0)
  if (find_one_thread (all_threads.head->id) == 0)
    return;
    return;
 
 
  /* Iterate over all user-space threads to discover new threads.  */
  /* Iterate over all user-space threads to discover new threads.  */
  err = td_ta_thr_iter (thread_agent, find_new_threads_callback, NULL,
  err = td_ta_thr_iter (thread_agent, find_new_threads_callback, NULL,
                        TD_THR_ANY_STATE, TD_THR_LOWEST_PRIORITY,
                        TD_THR_ANY_STATE, TD_THR_LOWEST_PRIORITY,
                        TD_SIGNO_MASK, TD_THR_ANY_USER_FLAGS);
                        TD_SIGNO_MASK, TD_THR_ANY_USER_FLAGS);
  if (err != TD_OK)
  if (err != TD_OK)
    error ("Cannot find new threads: %s", thread_db_err_str (err));
    error ("Cannot find new threads: %s", thread_db_err_str (err));
}
}
 
 
/* Cache all future symbols that thread_db might request.  We can not
/* Cache all future symbols that thread_db might request.  We can not
   request symbols at arbitrary states in the remote protocol, only
   request symbols at arbitrary states in the remote protocol, only
   when the client tells us that new symbols are available.  So when
   when the client tells us that new symbols are available.  So when
   we load the thread library, make sure to check the entire list.  */
   we load the thread library, make sure to check the entire list.  */
 
 
static void
static void
thread_db_look_up_symbols (void)
thread_db_look_up_symbols (void)
{
{
  const char **sym_list = td_symbol_list ();
  const char **sym_list = td_symbol_list ();
  CORE_ADDR unused;
  CORE_ADDR unused;
 
 
  for (sym_list = td_symbol_list (); *sym_list; sym_list++)
  for (sym_list = td_symbol_list (); *sym_list; sym_list++)
    look_up_one_symbol (*sym_list, &unused);
    look_up_one_symbol (*sym_list, &unused);
}
}
 
 
int
int
thread_db_get_tls_address (struct thread_info *thread, CORE_ADDR offset,
thread_db_get_tls_address (struct thread_info *thread, CORE_ADDR offset,
                           CORE_ADDR load_module, CORE_ADDR *address)
                           CORE_ADDR load_module, CORE_ADDR *address)
{
{
#if HAVE_TD_THR_TLS_GET_ADDR
#if HAVE_TD_THR_TLS_GET_ADDR
  psaddr_t addr;
  psaddr_t addr;
  td_err_e err;
  td_err_e err;
  struct process_info *process;
  struct process_info *process;
 
 
  process = get_thread_process (thread);
  process = get_thread_process (thread);
  if (!process->thread_known)
  if (!process->thread_known)
    find_one_thread (process->lwpid);
    find_one_thread (process->lwpid);
  if (!process->thread_known)
  if (!process->thread_known)
    return TD_NOTHR;
    return TD_NOTHR;
 
 
  /* Note the cast through uintptr_t: this interface only works if
  /* Note the cast through uintptr_t: this interface only works if
     a target address fits in a psaddr_t, which is a host pointer.
     a target address fits in a psaddr_t, which is a host pointer.
     So a 32-bit debugger can not access 64-bit TLS through this.  */
     So a 32-bit debugger can not access 64-bit TLS through this.  */
  err = td_thr_tls_get_addr (&process->th, (psaddr_t) (uintptr_t) load_module,
  err = td_thr_tls_get_addr (&process->th, (psaddr_t) (uintptr_t) load_module,
                             offset, &addr);
                             offset, &addr);
  if (err == TD_OK)
  if (err == TD_OK)
    {
    {
      *address = (CORE_ADDR) (uintptr_t) addr;
      *address = (CORE_ADDR) (uintptr_t) addr;
      return 0;
      return 0;
    }
    }
  else
  else
    return err;
    return err;
#else
#else
  return -1;
  return -1;
#endif
#endif
}
}
 
 
int
int
thread_db_init (int use_events)
thread_db_init (int use_events)
{
{
  int err;
  int err;
 
 
  /* FIXME drow/2004-10-16: This is the "overall process ID", which
  /* FIXME drow/2004-10-16: This is the "overall process ID", which
     GNU/Linux calls tgid, "thread group ID".  When we support
     GNU/Linux calls tgid, "thread group ID".  When we support
     attaching to threads, the original thread may not be the correct
     attaching to threads, the original thread may not be the correct
     thread.  We would have to get the process ID from /proc for NPTL.
     thread.  We would have to get the process ID from /proc for NPTL.
     For LinuxThreads we could do something similar: follow the chain
     For LinuxThreads we could do something similar: follow the chain
     of parent processes until we find the highest one we're attached
     of parent processes until we find the highest one we're attached
     to, and use its tgid.
     to, and use its tgid.
 
 
     This isn't the only place in gdbserver that assumes that the first
     This isn't the only place in gdbserver that assumes that the first
     process in the list is the thread group leader.  */
     process in the list is the thread group leader.  */
  proc_handle.pid = ((struct inferior_list_entry *)current_inferior)->id;
  proc_handle.pid = ((struct inferior_list_entry *)current_inferior)->id;
 
 
  /* Allow new symbol lookups.  */
  /* Allow new symbol lookups.  */
  all_symbols_looked_up = 0;
  all_symbols_looked_up = 0;
 
 
  thread_db_use_events = use_events;
  thread_db_use_events = use_events;
 
 
  err = td_ta_new (&proc_handle, &thread_agent);
  err = td_ta_new (&proc_handle, &thread_agent);
  switch (err)
  switch (err)
    {
    {
    case TD_NOLIBTHREAD:
    case TD_NOLIBTHREAD:
      /* No thread library was detected.  */
      /* No thread library was detected.  */
      return 0;
      return 0;
 
 
    case TD_OK:
    case TD_OK:
      /* The thread library was detected.  */
      /* The thread library was detected.  */
 
 
      if (use_events && thread_db_enable_reporting () == 0)
      if (use_events && thread_db_enable_reporting () == 0)
        return 0;
        return 0;
      thread_db_find_new_threads ();
      thread_db_find_new_threads ();
      thread_db_look_up_symbols ();
      thread_db_look_up_symbols ();
      all_symbols_looked_up = 1;
      all_symbols_looked_up = 1;
      return 1;
      return 1;
 
 
    default:
    default:
      warning ("error initializing thread_db library: %s",
      warning ("error initializing thread_db library: %s",
               thread_db_err_str (err));
               thread_db_err_str (err));
    }
    }
 
 
  return 0;
  return 0;
}
}
 
 

powered by: WebSVN 2.1.0

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