* symtab.c, dbxread.c, stabsread.c: Fix up ANSI-C isms. Fix
[deliverable/binutils-gdb.git] / gdb / sol-thread.c
index 00bdc60074f3a6504d828dac0f4261a4edf0488d..cc61c6a0f4f3fb19d4501f9afcd7ca05057a5137 100644 (file)
@@ -67,11 +67,13 @@ Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.  */
 #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
@@ -110,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)
@@ -306,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 = p_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 = p_td_thr_get_info (&th, &ti);
-
-  if (val != TD_OK)
+  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)
@@ -333,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
 /*
@@ -367,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 = p_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 = p_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
 /*
@@ -456,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. */
 }
 
@@ -473,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);
 }
 
@@ -492,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);
@@ -521,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;
@@ -562,7 +602,13 @@ 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);
 
@@ -632,7 +678,13 @@ 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);
 
@@ -719,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);
 
@@ -751,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
@@ -763,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);
     }
@@ -794,6 +848,10 @@ 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.  */
@@ -816,6 +874,7 @@ sol_thread_new_objfile (objfile)
 static void
 sol_thread_mourn_inferior ()
 {
+  unpush_target (&sol_thread_ops);
   procfs_ops.to_mourn_inferior ();
 }
 
@@ -827,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
@@ -898,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)
     {
@@ -910,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);
 
@@ -1123,23 +1213,99 @@ 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 */
@@ -1224,6 +1390,11 @@ _initialize_sol_thread ()
 
   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:
This page took 0.028976 seconds and 4 git commands to generate.