* symtab.c, dbxread.c, stabsread.c: Fix up ANSI-C isms. Fix
[deliverable/binutils-gdb.git] / gdb / sol-thread.c
index d107e2260cfd21a1d22a19da04ddf3b8d755f69d..cc61c6a0f4f3fb19d4501f9afcd7ca05057a5137 100644 (file)
@@ -66,11 +66,14 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
 #include <fcntl.h>
 #include <unistd.h>
 #include <sys/stat.h>
+#include <dlfcn.h>
+#include "gdbcmd.h"
 
 extern struct target_ops sol_thread_ops; /* Forward declaration */
 
 extern int procfs_suppress_run;
 extern struct target_ops procfs_ops; /* target vector for procfs.c */
+extern char *procfs_pid_to_str PARAMS ((int pid));
 
 /* Note that these prototypes differ slightly from those used in procfs.c
    for of two reasons.  One, we can't use gregset_t, as that's got a whole
@@ -109,10 +112,11 @@ static struct cleanup * save_inferior_pid PARAMS ((void));
 static void restore_inferior_pid PARAMS ((int pid));
 static char *td_err_string PARAMS ((td_err_e errcode));
 static char *td_state_string PARAMS ((td_thr_state_e statecode));
-static int thread_to_lwp PARAMS ((int thread_id, int default_lwp));
+static int  thread_to_lwp PARAMS ((int thread_id, int default_lwp));
 static void sol_thread_resume PARAMS ((int pid, int step,
                                       enum target_signal signo));
 static int lwp_to_thread PARAMS ((int lwp));
+static int sol_thread_alive PARAMS ((int pid));
 
 #define THREAD_FLAG 0x80000000
 #define is_thread(ARG) (((ARG) & THREAD_FLAG) != 0)
@@ -121,6 +125,56 @@ static int lwp_to_thread PARAMS ((int lwp));
 #define GET_THREAD(THREAD_ID) (((THREAD_ID) >> 16) & 0x7fff)
 #define BUILD_LWP(LWP_ID, PID) ((LWP_ID) << 16 | (PID))
 #define BUILD_THREAD(THREAD_ID, PID) (THREAD_FLAG | BUILD_LWP (THREAD_ID, PID))
+
+/* Pointers to routines from lithread_db resolved by dlopen() */
+
+static void
+  (*p_td_log) (const int on_off);
+static td_err_e
+  (*p_td_ta_new) (const struct ps_prochandle *ph_p, td_thragent_t **ta_pp);
+static td_err_e
+  (*p_td_ta_delete) (td_thragent_t *ta_p);
+static td_err_e
+  (*p_td_init) (void);
+static td_err_e
+  (*p_td_ta_get_ph) (const td_thragent_t *ta_p, struct ps_prochandle **ph_pp);
+static td_err_e
+  (*p_td_ta_get_nthreads) (const td_thragent_t *ta_p, int *nthread_p);
+static td_err_e
+  (*p_td_ta_tsd_iter) (const td_thragent_t *ta_p, td_key_iter_f *cb, void *cbdata_p);
+static td_err_e
+  (*p_td_ta_thr_iter) (const td_thragent_t *ta_p, td_thr_iter_f *cb, void *cbdata_p, td_thr_state_e state,
+                      int ti_pri, sigset_t *ti_sigmask_p, unsigned ti_user_flags);
+static td_err_e
+  (*p_td_thr_validate) (const td_thrhandle_t *th_p);
+static td_err_e
+  (*p_td_thr_tsd) (const td_thrhandle_t *th_p, const thread_key_t key, void **data_pp);
+static td_err_e
+  (*p_td_thr_get_info) (const td_thrhandle_t *th_p, td_thrinfo_t *ti_p);
+static td_err_e
+  (*p_td_thr_getfpregs) (const td_thrhandle_t *th_p, prfpregset_t *fpregset);
+static td_err_e
+  (*p_td_thr_getxregsize) (const td_thrhandle_t *th_p, int *xregsize);
+static td_err_e
+  (*p_td_thr_getxregs) (const td_thrhandle_t *th_p, const caddr_t xregset);
+static td_err_e
+  (*p_td_thr_sigsetmask) (const td_thrhandle_t *th_p, const sigset_t ti_sigmask);
+static td_err_e
+  (*p_td_thr_setprio) (const td_thrhandle_t *th_p, const int ti_pri);
+static td_err_e
+  (*p_td_thr_setsigpending) (const td_thrhandle_t *th_p, const uchar_t ti_pending_flag, const sigset_t ti_pending);
+static td_err_e
+  (*p_td_thr_setfpregs) (const td_thrhandle_t *th_p, const prfpregset_t *fpregset);
+static td_err_e
+  (*p_td_thr_setxregs) (const td_thrhandle_t *th_p, const caddr_t xregset);
+static td_err_e
+  (*p_td_ta_map_id2thr) (const td_thragent_t *ta_p, thread_t tid, td_thrhandle_t *th_p);
+static td_err_e
+  (*p_td_ta_map_lwp2thr) (const td_thragent_t *ta_p, lwpid_t lwpid, td_thrhandle_t *th_p);
+static td_err_e
+  (*p_td_thr_getgregs) (const td_thrhandle_t *th_p, prgregset_t regset);
+static td_err_e
+  (*p_td_thr_setgregs) (const td_thrhandle_t *th_p, const prgregset_t regset);
 \f
 /*
 
@@ -255,24 +309,22 @@ thread_to_lwp (thread_id, default_lwp)
   td_thrinfo_t ti;
   td_thrhandle_t th;
   td_err_e val;
-  int pid;
-  int lwp;
 
   if (is_lwp (thread_id))
     return thread_id;                  /* It's already an LWP id */
 
   /* It's a thread.  Convert to lwp */
 
-  pid = PIDGET (thread_id);
-  thread_id = GET_THREAD(thread_id);
-
-  val = td_ta_map_id2thr (main_ta, thread_id, &th);
-  if (val != TD_OK)
+  val = p_td_ta_map_id2thr (main_ta, GET_THREAD (thread_id), &th);
+  if (val == TD_NOTHR)
+    return -1;         /* thread must have terminated */
+  else if (val != TD_OK)
     error ("thread_to_lwp: td_ta_map_id2thr %s", td_err_string (val));
 
-  val = td_thr_get_info (&th, &ti);
-
-  if (val != TD_OK)
+  val = p_td_thr_get_info (&th, &ti);
+  if (val == TD_NOTHR)
+    return -1;         /* thread must have terminated */
+  else if (val != TD_OK)
     error ("thread_to_lwp: td_thr_get_info: %s", td_err_string (val));
 
   if (ti.ti_state != TD_THR_ACTIVE)
@@ -282,10 +334,8 @@ thread_to_lwp (thread_id, default_lwp)
       error ("thread_to_lwp: thread state not active: %s",
             td_state_string (ti.ti_state));
     }
-  
-  lwp = BUILD_LWP (ti.ti_lid, pid);
 
-  return lwp;
+  return BUILD_LWP (ti.ti_lid, PIDGET (thread_id));
 }
 \f
 /*
@@ -316,29 +366,34 @@ lwp_to_thread (lwp)
   td_thrinfo_t ti;
   td_thrhandle_t th;
   td_err_e val;
-  int pid;
-  int thread_id;
 
   if (is_thread (lwp))
     return lwp;                        /* It's already a thread id */
 
   /* It's an lwp.  Convert it to a thread id.  */
 
-  pid = PIDGET (lwp);
-  lwp = GET_LWP (lwp);
+  if (!sol_thread_alive (lwp))
+    return -1;                 /* defunct lwp */
 
-  val = td_ta_map_lwp2thr (main_ta, lwp, &th);
-  if (val != TD_OK)
+  val = p_td_ta_map_lwp2thr (main_ta, GET_LWP (lwp), &th);
+  if (val == TD_NOTHR)
+    return -1;         /* thread must have terminated */
+  else if (val != TD_OK)
     error ("lwp_to_thread: td_thr_get_info: %s.", td_err_string (val));
 
-  val = td_thr_get_info (&th, &ti);
+  val = p_td_thr_validate (&th);
+  if (val == TD_NOTHR)
+    return lwp;                        /* libthread doesn't know about it, just return lwp */
+  else if (val != TD_OK)
+    error ("lwp_to_thread: td_thr_validate: %s.", td_err_string (val));
 
-  if (val != TD_OK)
+  val = p_td_thr_get_info (&th, &ti);
+  if (val == TD_NOTHR)
+    return -1;         /* thread must have terminated */
+  else if (val != TD_OK)
     error ("lwp_to_thread: td_thr_get_info: %s.", td_err_string (val));
 
-  thread_id = BUILD_THREAD (ti.ti_tid, pid);
-
-  return thread_id;
+  return BUILD_THREAD (ti.ti_tid, PIDGET (lwp));
 }
 \f
 /*
@@ -405,7 +460,19 @@ sol_thread_attach (args, from_tty)
      int from_tty;
 {
   procfs_ops.to_attach (args, from_tty);
-
+  /* Must get symbols from solibs before libthread_db can run! */
+  SOLIB_ADD ((char *)0, from_tty, (struct target_ops *)0);
+  if (sol_thread_active)
+    {
+      printf_filtered ("sol-thread active.\n");
+      main_ph.pid = inferior_pid; /* Save for xfer_memory */
+      push_target (&sol_thread_ops);
+      inferior_pid = lwp_to_thread (inferior_pid);
+      if (inferior_pid == -1)
+       inferior_pid = main_ph.pid;
+      else
+       add_thread (inferior_pid);
+    }
   /* XXX - might want to iterate over all the threads and register them. */
 }
 
@@ -422,6 +489,7 @@ sol_thread_detach (args, from_tty)
      char *args;
      int from_tty;
 {
+  unpush_target (&sol_thread_ops);
   procfs_ops.to_detach (args, from_tty);
 }
 
@@ -441,12 +509,19 @@ sol_thread_resume (pid, step, signo)
   old_chain = save_inferior_pid ();
 
   inferior_pid = thread_to_lwp (inferior_pid, main_ph.pid);
+  if (inferior_pid == -1)
+    inferior_pid = procfs_first_available ();
 
   if (pid != -1)
     {
+      int save_pid = pid;
+
       pid = thread_to_lwp (pid, -2);
       if (pid == -2)           /* Inactive thread */
        error ("This version of Solaris can't start inactive threads.");
+      if (info_verbose && pid == -1)
+       warning ("Specified thread %d seems to have terminated", 
+                GET_THREAD (save_pid));
     }
 
   procfs_ops.to_resume (pid, step, signo);
@@ -470,28 +545,44 @@ sol_thread_wait (pid, ourstatus)
   old_chain = save_inferior_pid ();
 
   inferior_pid = thread_to_lwp (inferior_pid, main_ph.pid);
+  if (inferior_pid == -1)
+    inferior_pid = procfs_first_available ();
 
   if (pid != -1)
-    pid = thread_to_lwp (pid, -1);
+    {
+      int save_pid = pid;
+
+      pid = thread_to_lwp (pid, -2);
+      if (pid == -2)           /* Inactive thread */
+       error ("This version of Solaris can't start inactive threads.");
+      if (info_verbose && pid == -1)
+       warning ("Specified thread %d seems to have terminated", 
+                GET_THREAD (save_pid));
+    }
 
   rtnval = procfs_ops.to_wait (pid, ourstatus);
 
-  if (rtnval != save_pid
-      && !in_thread_list (rtnval))
+  if (ourstatus->kind != TARGET_WAITKIND_EXITED)
     {
-      fprintf_unfiltered (gdb_stderr, "[New %s]\n",
-                         target_pid_to_str (rtnval));
-      add_thread (rtnval);
+      /* Map the LWP of interest back to the appropriate thread ID */
+      rtnval = lwp_to_thread (rtnval);
+      if (rtnval == -1)
+       rtnval = save_pid;
+
+      /* See if we have a new thread */
+      if (is_thread (rtnval)
+         && rtnval != save_pid
+         && !in_thread_list (rtnval))
+       {
+         printf_filtered ("[New %s]\n", target_pid_to_str (rtnval));
+         add_thread (rtnval);
+       }
     }
 
   /* During process initialization, we may get here without the thread package
      being initialized, since that can only happen after we've found the shared
      libs.  */
 
-  /* Map the LWP of interest back to the appropriate thread ID */
-
-  rtnval = lwp_to_thread (rtnval);
-
   do_cleanups (old_chain);
 
   return rtnval;
@@ -511,21 +602,27 @@ sol_thread_fetch_registers (regno)
   caddr_t xregset;
 #endif
 
-  /* Convert inferior_pid into a td_thrhandle_t */
+  if (!is_thread (inferior_pid))
+    { /* LWP: pass the request on to procfs.c */
+      procfs_ops.to_fetch_registers (regno);
+      return;
+    }
+
+  /* Solaris thread: convert inferior_pid into a td_thrhandle_t */
 
   thread = GET_THREAD (inferior_pid);
 
   if (thread == 0)
     error ("sol_thread_fetch_registers:  thread == 0");
 
-  val = td_ta_map_id2thr (main_ta, thread, &thandle);
+  val = p_td_ta_map_id2thr (main_ta, thread, &thandle);
   if (val != TD_OK)
     error ("sol_thread_fetch_registers: td_ta_map_id2thr: %s",
           td_err_string (val));
 
   /* Get the integer regs */
 
-  val = td_thr_getgregs (&thandle, gregset);
+  val = p_td_thr_getgregs (&thandle, gregset);
   if (val != TD_OK
       && val != TD_PARTIALREG)
     error ("sol_thread_fetch_registers: td_thr_getgregs %s",
@@ -536,7 +633,7 @@ sol_thread_fetch_registers (regno)
 
   /* And, now the fp regs */
 
-  val = td_thr_getfpregs (&thandle, &fpregset);
+  val = p_td_thr_getfpregs (&thandle, &fpregset);
   if (val != TD_OK
       && val != TD_NOFPREGS)
     error ("sol_thread_fetch_registers: td_thr_getfpregs %s",
@@ -581,22 +678,28 @@ sol_thread_store_registers (regno)
   caddr_t xregset;
 #endif
 
-  /* Convert inferior_pid into a td_thrhandle_t */
+  if (!is_thread (inferior_pid))
+    { /* LWP: pass the request on to procfs.c */
+      procfs_ops.to_store_registers (regno);
+      return;
+    }
+
+  /* Solaris thread: convert inferior_pid into a td_thrhandle_t */
 
   thread = GET_THREAD (inferior_pid);
 
-  val = td_ta_map_id2thr (main_ta, thread, &thandle);
+  val = p_td_ta_map_id2thr (main_ta, thread, &thandle);
   if (val != TD_OK)
     error ("sol_thread_store_registers: td_ta_map_id2thr %s",
           td_err_string (val));
 
   if (regno != -1)
     {                          /* Not writing all the regs */
-      val = td_thr_getgregs (&thandle, regset);
+      val = p_td_thr_getgregs (&thandle, regset);
       if (val != TD_OK)
        error ("sol_thread_store_registers: td_thr_getgregs %s",
               td_err_string (val));
-      val = td_thr_getfpregs (&thandle, &fpregset);
+      val = p_td_thr_getfpregs (&thandle, &fpregset);
       if (val != TD_OK)
        error ("sol_thread_store_registers: td_thr_getfpregs %s",
               td_err_string (val));
@@ -622,11 +725,11 @@ sol_thread_store_registers (regno)
   fill_gregset (regset, regno);
   fill_fpregset (fpregset, regno);
 
-  val = td_thr_setgregs (&thandle, regset);
+  val = p_td_thr_setgregs (&thandle, regset);
   if (val != TD_OK)
     error ("sol_thread_store_registers: td_thr_setgregs %s",
           td_err_string (val));
-  val = td_thr_setfpregs (&thandle, &fpregset);
+  val = p_td_thr_setfpregs (&thandle, &fpregset);
   if (val != TD_OK)
     error ("sol_thread_store_registers: td_thr_setfpregs %s",
           td_err_string (val));
@@ -668,8 +771,10 @@ sol_thread_xfer_memory (memaddr, myaddr, len, dowrite, target)
 
   old_chain = save_inferior_pid ();
 
-  if (is_thread (inferior_pid))
-    inferior_pid = main_ph.pid;        /* It's a thread.  Convert to lwp */
+  if (is_thread (inferior_pid) ||              /* A thread */
+      !target_thread_alive (inferior_pid))     /* An lwp, but not alive */
+    inferior_pid = procfs_first_available ();  /* Find any live lwp.  */
+  /* Note: don't need to call switch_to_thread; we're just reading memory.  */
 
   retval = procfs_ops.to_xfer_memory (memaddr, myaddr, len, dowrite, target);
 
@@ -700,8 +805,6 @@ sol_thread_notice_signals (pid)
   procfs_ops.to_notice_signals (pid);
 }
 
-void target_new_objfile PARAMS ((struct objfile *objfile));
-
 /* Fork an inferior process, and start debugging it with /proc.  */
 
 static void
@@ -712,13 +815,15 @@ sol_thread_create_inferior (exec_file, allargs, env)
 {
   procfs_ops.to_create_inferior (exec_file, allargs, env);
 
-  if (sol_thread_active)
+  if (sol_thread_active && inferior_pid != 0)
     {
       main_ph.pid = inferior_pid; /* Save for xfer_memory */
 
       push_target (&sol_thread_ops);
 
       inferior_pid = lwp_to_thread (inferior_pid);
+      if (inferior_pid == -1)
+       inferior_pid = main_ph.pid;
 
       add_thread (inferior_pid);
     }
@@ -743,15 +848,19 @@ sol_thread_new_objfile (objfile)
       return;
     }
 
+  /* don't do anything if init failed to resolve the libthread_db library */
+  if (!procfs_suppress_run)
+    return;
+
   /* Now, initialize the thread debugging library.  This needs to be done after
      the shared libraries are located because it needs information from the
      user's thread library.  */
 
-  val = td_init ();
+  val = p_td_init ();
   if (val != TD_OK)
     error ("target_new_objfile: td_init: %s", td_err_string (val));
 
-  val = td_ta_new (&main_ph, &main_ta);
+  val = p_td_ta_new (&main_ph, &main_ta);
   if (val == TD_NOLIBTHREAD)
     return;
   else if (val != TD_OK)
@@ -765,6 +874,7 @@ sol_thread_new_objfile (objfile)
 static void
 sol_thread_mourn_inferior ()
 {
+  unpush_target (&sol_thread_ops);
   procfs_ops.to_mourn_inferior ();
 }
 
@@ -776,11 +886,40 @@ sol_thread_can_run ()
   return procfs_suppress_run;
 }
 
+/* 
+
+LOCAL FUNCTION
+
+       sol_thread_alive     - test thread for "aliveness"
+
+SYNOPSIS
+
+       static bool sol_thread_alive (int pid);
+
+DESCRIPTION
+
+       returns true if thread still active in inferior.
+
+ */
+
 static int
 sol_thread_alive (pid)
      int pid;
 {
-  return 1;
+  if (is_thread (pid))         /* non-kernel thread */
+    {
+      td_err_e val;
+      td_thrhandle_t th;
+
+      pid = GET_THREAD (pid);
+      if ((val = p_td_ta_map_id2thr (main_ta, pid, &th)) != TD_OK)
+       return 0;       /* thread not found */
+      if ((val = p_td_thr_validate (&th)) != TD_OK)
+       return 0;       /* thread not valid */
+      return 1;                /* known thread: return true */
+    }
+  else                 /* kernel thread (LWP): let procfs test it */
+    return procfs_ops.to_thread_alive (pid);
 }
 
 static void
@@ -847,8 +986,10 @@ rw_common (int dowrite, const struct ps_prochandle *ph, paddr_t addr,
 
   old_chain = save_inferior_pid ();
 
-  if (is_thread (inferior_pid))
-    inferior_pid = main_ph.pid;        /* It's a thread.  Convert to lwp */
+  if (is_thread (inferior_pid) ||              /* A thread */
+      !target_thread_alive (inferior_pid))     /* An lwp, but not alive */
+    inferior_pid = procfs_first_available ();  /* Find any live lwp.  */
+  /* Note: don't need to call switch_to_thread; we're just reading memory.  */
 
   while (size > 0)
     {
@@ -859,9 +1000,9 @@ rw_common (int dowrite, const struct ps_prochandle *ph, paddr_t addr,
       if (cc < 0)
        {
          if (dowrite == 0)
-           print_sys_errmsg ("ps_pdread (): read", errno);
+           print_sys_errmsg ("rw_common (): read", errno);
          else
-           print_sys_errmsg ("ps_pdread (): write", errno);
+           print_sys_errmsg ("rw_common (): write", errno);
 
          do_cleanups (old_chain);
 
@@ -1072,38 +1213,114 @@ solaris_pid_to_str (pid)
 {
   static char buf[100];
 
+  /* in case init failed to resolve the libthread_db library */
+  if (!procfs_suppress_run)
+    return procfs_pid_to_str (pid);
+
   if (is_thread (pid))
     {
       int lwp;
 
       lwp = thread_to_lwp (pid, -2);
 
-      if (lwp != -2)
+      if (lwp == -1)
+       sprintf (buf, "Thread %d (defunct)", GET_THREAD (pid));
+      else if (lwp != -2)
        sprintf (buf, "Thread %d (LWP %d)", GET_THREAD (pid), GET_LWP (lwp));
       else
        sprintf (buf, "Thread %d        ", GET_THREAD (pid));
     }
-  else
+  else if (GET_LWP (pid) != 0)
     sprintf (buf, "LWP    %d        ", GET_LWP (pid));
+  else
+    sprintf (buf, "process %d    ", PIDGET (pid));
 
   return buf;
 }
 \f
+
+#ifdef MAINTENANCE_CMDS
+/* Worker bee for info sol-thread command.  This is a callback function that
+   gets called once for each Solaris thread (ie. not kernel thread) in the 
+   inferior.  Print anything interesting that we can think of.  */
+
+static int 
+info_cb (th, s)
+     const td_thrhandle_t *th;
+     void *s;
+{
+  td_err_e ret;
+  td_thrinfo_t ti;
+  struct minimal_symbol *msym;
+
+  if ((ret = p_td_thr_get_info (th, &ti)) == TD_OK)
+    {
+      printf_filtered ("%s thread #%d, lwp %d, ", 
+                      ti.ti_type == TD_THR_SYSTEM ? "system" : "user  ", 
+                      ti.ti_tid, ti.ti_lid);
+      switch (ti.ti_state) {
+       default:
+       case TD_THR_UNKNOWN: printf_filtered ("<unknown state>");       break;
+       case TD_THR_STOPPED: printf_filtered ("(stopped)");     break;
+       case TD_THR_RUN:     printf_filtered ("(run)    ");     break;
+       case TD_THR_ACTIVE:  printf_filtered ("(active) ");     break;
+       case TD_THR_ZOMBIE:  printf_filtered ("(zombie) ");     break;
+       case TD_THR_SLEEP:   printf_filtered ("(asleep) ");     break;
+       case TD_THR_STOPPED_ASLEEP: 
+         printf_filtered ("(stopped asleep)");                 break;
+      }
+      /* Print thr_create start function: */
+      if (ti.ti_startfunc != 0)
+       if (msym = lookup_minimal_symbol_by_pc (ti.ti_startfunc))
+         printf_filtered ("   startfunc: %s\n", SYMBOL_NAME (msym));
+       else
+         printf_filtered ("   startfunc: 0x%08x\n", ti.ti_startfunc);
+
+      /* If thread is asleep, print function that went to sleep: */
+      if (ti.ti_state == TD_THR_SLEEP)
+       if (msym = lookup_minimal_symbol_by_pc (ti.ti_pc))
+         printf_filtered (" - Sleep func: %s\n", SYMBOL_NAME (msym));
+       else
+         printf_filtered (" - Sleep func: 0x%08x\n", ti.ti_startfunc);
+
+      /* Wrap up line, if necessary */
+      if (ti.ti_state != TD_THR_SLEEP && ti.ti_startfunc == 0)
+       printf_filtered ("\n"); /* don't you hate counting newlines? */
+    }
+  else
+    warning ("info sol-thread: failed to get info for thread.");
+
+  return 0;    
+}
+
+/* List some state about each Solaris user thread in the inferior.  */
+
+static void
+info_solthreads (args, from_tty)
+     char *args;
+     int from_tty;
+{
+  p_td_ta_thr_iter (main_ta, info_cb, args, 
+                   TD_THR_ANY_STATE, TD_THR_LOWEST_PRIORITY,
+                   TD_SIGNO_MASK, TD_THR_ANY_USER_FLAGS);
+}
+#endif /* MAINTENANCE_CMDS */
+
 struct target_ops sol_thread_ops = {
   "solaris-threads",           /* to_shortname */
   "Solaris threads and pthread.", /* to_longname */
   "Solaris threads and pthread support.", /* to_doc */
   sol_thread_open,             /* to_open */
   0,                           /* to_close */
-  sol_thread_attach,                   /* to_attach */
+  sol_thread_attach,           /* to_attach */
   sol_thread_detach,           /* to_detach */
-  sol_thread_resume,                   /* to_resume */
-  sol_thread_wait,                     /* to_wait */
+  sol_thread_resume,           /* to_resume */
+  sol_thread_wait,             /* to_wait */
   sol_thread_fetch_registers,  /* to_fetch_registers */
   sol_thread_store_registers,  /* to_store_registers */
   sol_thread_prepare_to_store, /* to_prepare_to_store */
-  sol_thread_xfer_memory,              /* to_xfer_memory */
-  sol_thread_files_info,               /* to_files_info */
+  sol_thread_xfer_memory,      /* to_xfer_memory */
+  sol_thread_files_info,       /* to_files_info */
   memory_insert_breakpoint,    /* to_insert_breakpoint */
   memory_remove_breakpoint,    /* to_remove_breakpoint */
   terminal_init_inferior,      /* to_terminal_init */
@@ -1135,7 +1352,57 @@ struct target_ops sol_thread_ops = {
 void
 _initialize_sol_thread ()
 {
+  void *dlhandle;
+
+  dlhandle = dlopen ("libthread_db.so.1", RTLD_NOW);
+  if (!dlhandle)
+    goto die;
+
+#define resolve(X) \
+  if (!(p_##X = dlsym (dlhandle, #X))) \
+    goto die;
+
+  resolve (td_log);
+  resolve (td_ta_new);
+  resolve (td_ta_delete);
+  resolve (td_init);
+  resolve (td_ta_get_ph);
+  resolve (td_ta_get_nthreads);
+  resolve (td_ta_tsd_iter);
+  resolve (td_ta_thr_iter);
+  resolve (td_thr_validate);
+  resolve (td_thr_tsd);
+  resolve (td_thr_get_info);
+  resolve (td_thr_getfpregs);
+  resolve (td_thr_getxregsize);
+  resolve (td_thr_getxregs);
+  resolve (td_thr_sigsetmask);
+  resolve (td_thr_setprio);
+  resolve (td_thr_setsigpending);
+  resolve (td_thr_setfpregs);
+  resolve (td_thr_setxregs);
+  resolve (td_ta_map_id2thr);
+  resolve (td_ta_map_lwp2thr);
+  resolve (td_thr_getgregs);
+  resolve (td_thr_setgregs);
+
   add_target (&sol_thread_ops);
 
   procfs_suppress_run = 1;
+
+#ifdef MAINTENANCE_CMDS
+  add_cmd ("sol-threads", class_maintenance, info_solthreads, 
+           "Show info on Solaris user threads.\n", &maintenanceinfolist);
+#endif /* MAINTENANCE_CMDS */
+
+  return;
+
+ die:
+
+  fprintf_unfiltered (gdb_stderr, "[GDB will not be able to debug user-mode threads: %s]\n", dlerror ());
+
+  if (dlhandle)
+    dlclose (dlhandle);
+
+  return;
 }
This page took 0.031701 seconds and 4 git commands to generate.