2005-05-01 Andrew Cagney <cagney@gnu.org>
[deliverable/binutils-gdb.git] / gdb / inf-ttrace.c
index 2d2074d8280e216c869f03d6155336dc3b08a1ed..7e3e79ac75db8c5c18b9526b89c3d4830ff8073e 100644 (file)
@@ -27,6 +27,7 @@
 
 #include "command.h"
 #include "gdbcore.h"
+#include "gdbthread.h"
 #include "inferior.h"
 #include "observer.h"
 #include "target.h"
 static struct target_ops *ttrace_ops_hack;
 \f
 
+/* HP-UX uses a threading model where each user-space thread
+   corresponds to a kernel thread.  These kernel threads are called
+   lwps.  The ttrace(2) interface gives us almost full control over
+   the threads, which makes it very easy to support them in GDB.  We
+   identify the threads by process ID and lwp ID.  The ttrace(2) also
+   provides us with a thread's user ID (in the `tts_user_tid' member
+   of `ttstate_t') but we don't use that (yet) as it isn't necessary
+   to uniquely label the thread.  */
+
+/* Number of active lwps.  */
+static int inf_ttrace_num_lwps;
+\f
+
 /* On HP-UX versions that have the ttrace(2) system call, we can
    implement "hardware" watchpoints by fiddling with the protection of
    pages in the address space that contain the variable being watched.
@@ -65,8 +79,8 @@ struct inf_ttrace_page_dict
   int count;                   /* Number of pages in this dictionary.  */
 } inf_ttrace_page_dict;
 
-/* Number of threads that are currently in a system call.  */
-static int inf_ttrace_num_threads_in_syscall;
+/* Number of lwps that are currently in a system call.  */
+static int inf_ttrace_num_lwps_in_syscall;
 
 /* Flag to indicate whether we should re-enable page protections after
    the next wait.  */
@@ -80,24 +94,24 @@ inf_ttrace_enable_syscall_events (pid_t pid)
   ttevent_t tte;
   ttstate_t tts;
 
-  gdb_assert (inf_ttrace_num_threads_in_syscall == 0);
+  gdb_assert (inf_ttrace_num_lwps_in_syscall == 0);
 
   if (ttrace (TT_PROC_GET_EVENT_MASK, pid, 0,
              (uintptr_t)&tte, sizeof tte, 0) == -1)
-    perror_with_name ("ttrace");
+    perror_with_name (("ttrace"));
 
   tte.tte_events |= (TTEVT_SYSCALL_ENTRY | TTEVT_SYSCALL_RETURN);
 
   if (ttrace (TT_PROC_SET_EVENT_MASK, pid, 0,
              (uintptr_t)&tte, sizeof tte, 0) == -1)
-    perror_with_name ("ttrace");
+    perror_with_name (("ttrace"));
 
   if (ttrace (TT_PROC_GET_FIRST_LWP_STATE, pid, 0,
              (uintptr_t)&tts, sizeof tts, 0) == -1)
-    perror_with_name ("ttrace");
+    perror_with_name (("ttrace"));
 
   if (tts.tts_flags & TTS_INSYSCALL)
-    inf_ttrace_num_threads_in_syscall++;
+    inf_ttrace_num_lwps_in_syscall++;
 
   /* FIXME: Handle multiple threads.  */
 }
@@ -113,15 +127,15 @@ inf_ttrace_disable_syscall_events (pid_t pid)
 
   if (ttrace (TT_PROC_GET_EVENT_MASK, pid, 0,
              (uintptr_t)&tte, sizeof tte, 0) == -1)
-    perror_with_name ("ttrace");
+    perror_with_name (("ttrace"));
 
   tte.tte_events &= ~(TTEVT_SYSCALL_ENTRY | TTEVT_SYSCALL_RETURN);
 
   if (ttrace (TT_PROC_SET_EVENT_MASK, pid, 0,
              (uintptr_t)&tte, sizeof tte, 0) == -1)
-    perror_with_name ("ttrace");
+    perror_with_name (("ttrace"));
 
-  inf_ttrace_num_threads_in_syscall = 0;
+  inf_ttrace_num_lwps_in_syscall = 0;
 }
 
 /* Get information about the page at address ADDR for process PID from
@@ -176,7 +190,7 @@ inf_ttrace_add_page (pid_t pid, CORE_ADDR addr)
 
       if (ttrace (TT_PROC_GET_MPROTECT, pid, 0,
                  addr, 0, (uintptr_t)&prot) == -1)
-       perror_with_name ("ttrace");
+       perror_with_name (("ttrace"));
       
       page = XMALLOC (struct inf_ttrace_page);
       page->addr = addr;
@@ -191,11 +205,11 @@ inf_ttrace_add_page (pid_t pid, CORE_ADDR addr)
       if (inf_ttrace_page_dict.count == 1)
        inf_ttrace_enable_syscall_events (pid);
 
-      if (inf_ttrace_num_threads_in_syscall == 0)
+      if (inf_ttrace_num_lwps_in_syscall == 0)
        {
          if (ttrace (TT_PROC_SET_MPROTECT, pid, 0,
                      addr, pagesize, prot & ~PROT_WRITE) == -1)
-           perror_with_name ("ttrace");
+           perror_with_name (("ttrace"));
        }
     }
 
@@ -231,11 +245,11 @@ inf_ttrace_remove_page (pid_t pid, CORE_ADDR addr)
 
   if (page->refcount == 0)
     {
-      if (inf_ttrace_num_threads_in_syscall == 0)
+      if (inf_ttrace_num_lwps_in_syscall == 0)
        {
          if (ttrace (TT_PROC_SET_MPROTECT, pid, 0,
                      addr, pagesize, page->prot) == -1)
-           perror_with_name ("ttrace");
+           perror_with_name (("ttrace"));
        }
 
       inf_ttrace_page_dict.count--;
@@ -269,7 +283,7 @@ inf_ttrace_mask_page_protections (pid_t pid, int prot)
        {
          if (ttrace (TT_PROC_SET_MPROTECT, pid, 0,
                      page->addr, pagesize, page->prot & ~prot) == -1)
-           perror_with_name ("ttrace");
+           perror_with_name (("ttrace"));
 
          page = page->next;
        }
@@ -365,7 +379,7 @@ inf_ttrace_stopped_by_watchpoint (void)
     {
       if (ttrace (TT_LWP_GET_STATE, pid, lwpid,
                  (uintptr_t)&tts, sizeof tts, 0) == -1)
-       perror_with_name ("ttrace");
+       perror_with_name (("ttrace"));
 
       if (tts.tts_event == TTEVT_SIGNAL
          && tts.tts_u.tts_signal.tts_signo == SIGBUS)
@@ -401,13 +415,13 @@ static void
 inf_ttrace_prepare (void)
 {
   if (pipe (inf_ttrace_pfd1) == -1)
-    perror_with_name ("pipe");
+    perror_with_name (("pipe"));
 
   if (pipe (inf_ttrace_pfd2) == -1)
     {
       close (inf_ttrace_pfd1[0]);
       close (inf_ttrace_pfd2[0]);
-      perror_with_name ("pipe");
+      perror_with_name (("pipe"));
     }
 }
 
@@ -421,15 +435,15 @@ inf_ttrace_me (void)
 
   /* "Trace me, Dr. Memory!"  */
   if (ttrace (TT_PROC_SETTRC, 0, 0, 0, TT_VERSION, 0) == -1)
-    perror_with_name ("ttrace");
+    perror_with_name (("ttrace"));
 
   /* Tell our parent that we are ready to be traced.  */
   if (write (inf_ttrace_pfd1[1], &c, sizeof c) != sizeof c)
-    perror_with_name ("write");
+    perror_with_name (("write"));
 
   /* Wait until our parent has set the initial event mask.  */
   if (read (inf_ttrace_pfd2[0], &c, sizeof c) != sizeof c)
-    perror_with_name ("read");
+    perror_with_name (("read"));
 
   do_cleanups (old_chain);
 }
@@ -445,19 +459,23 @@ inf_ttrace_him (int pid)
 
   /* Wait until our child is ready to be traced.  */
   if (read (inf_ttrace_pfd1[0], &c, sizeof c) != sizeof c)
-    perror_with_name ("read");
+    perror_with_name (("read"));
 
   /* Set the initial event mask.  */
   memset (&tte, 0, sizeof (tte));
-  tte.tte_events = TTEVT_EXEC | TTEVT_EXIT;
+  tte.tte_events |= TTEVT_EXEC | TTEVT_EXIT;
+  tte.tte_events |= TTEVT_LWP_CREATE | TTEVT_LWP_EXIT | TTEVT_LWP_TERMINATE;
+#ifdef TTEVT_BPT_SSTEP
+  tte.tte_events |= TTEVT_BPT_SSTEP;
+#endif
   tte.tte_opts = TTEO_NOSTRCCHLD;
   if (ttrace (TT_PROC_SET_EVENT_MASK, pid, 0,
              (uintptr_t)&tte, sizeof tte, 0) == -1)
-    perror_with_name ("ttrace");
+    perror_with_name (("ttrace"));
 
   /* Tell our child that we have set the initial event mask.  */
   if (write (inf_ttrace_pfd2[1], &c, sizeof c) != sizeof c)
-    perror_with_name ("write");
+    perror_with_name (("write"));
 
   do_cleanups (old_chain);
 
@@ -484,8 +502,9 @@ static void
 inf_ttrace_create_inferior (char *exec_file, char *allargs, char **env,
                            int from_tty)
 {
+  gdb_assert (inf_ttrace_num_lwps == 0);
+  gdb_assert (inf_ttrace_num_lwps_in_syscall == 0);
   gdb_assert (inf_ttrace_page_dict.count == 0);
-  gdb_assert (inf_ttrace_num_threads_in_syscall == 0);
   gdb_assert (inf_ttrace_reenable_page_protections == 0);
 
   fork_inferior (exec_file, allargs, env, inf_ttrace_me, inf_ttrace_him,
@@ -507,7 +526,7 @@ inf_ttrace_kill_inferior (void)
     return;
 
   if (ttrace (TT_PROC_EXIT, pid, 0, 0, 0, 0) == -1)
-    perror_with_name ("ttrace");
+    perror_with_name (("ttrace"));
   /* ??? Is it necessary to call ttrace_wait() here?  */
   target_mourn_inferior ();
 }
@@ -518,7 +537,8 @@ inf_ttrace_mourn_inferior (void)
   const int num_buckets = ARRAY_SIZE (inf_ttrace_page_dict.buckets);
   int bucket;
 
-  inf_ttrace_num_threads_in_syscall = 0;
+  inf_ttrace_num_lwps = 0;
+  inf_ttrace_num_lwps_in_syscall = 0;
 
   for (bucket = 0; bucket < num_buckets; bucket++)
     {
@@ -548,42 +568,48 @@ inf_ttrace_attach (char *args, int from_tty)
   ttevent_t tte;
 
   if (!args)
-    error_no_arg ("process-id to attach");
+    error_no_arg (_("process-id to attach"));
 
   dummy = args;
   pid = strtol (args, &dummy, 0);
   if (pid == 0 && args == dummy)
-    error ("Illegal process-id: %s\n", args);
+    error (_("Illegal process-id: %s."), args);
 
   if (pid == getpid ())                /* Trying to masturbate?  */
-    error ("I refuse to debug myself!");
+    error (_("I refuse to debug myself!"));
 
   if (from_tty)
     {
       exec_file = (char *) get_exec_file (0);
 
       if (exec_file)
-       printf_unfiltered ("Attaching to program: %s, %s\n", exec_file,
+       printf_unfiltered (_("Attaching to program: %s, %s\n"), exec_file,
                           target_pid_to_str (pid_to_ptid (pid)));
       else
-       printf_unfiltered ("Attaching to %s\n",
+       printf_unfiltered (_("Attaching to %s\n"),
                           target_pid_to_str (pid_to_ptid (pid)));
 
       gdb_flush (gdb_stdout);
     }
 
+  gdb_assert (inf_ttrace_num_lwps == 0);
+  gdb_assert (inf_ttrace_num_lwps_in_syscall == 0);
+
   if (ttrace (TT_PROC_ATTACH, pid, 0, TT_KILL_ON_EXIT, TT_VERSION, 0) == -1)
-    perror_with_name ("ttrace");
+    perror_with_name (("ttrace"));
   attach_flag = 1;
 
   /* Set the initial event mask.  */
-  gdb_assert (inf_ttrace_num_threads_in_syscall == 0);
   memset (&tte, 0, sizeof (tte));
-  tte.tte_events = TTEVT_EXEC | TTEVT_EXIT;
+  tte.tte_events |= TTEVT_EXEC | TTEVT_EXIT;
+  tte.tte_events |= TTEVT_LWP_CREATE | TTEVT_LWP_EXIT | TTEVT_LWP_TERMINATE;
+#ifdef TTEVT_BPT_SSTEP
+  tte.tte_events |= TTEVT_BPT_SSTEP;
+#endif
   tte.tte_opts = TTEO_NOSTRCCHLD;
   if (ttrace (TT_PROC_SET_EVENT_MASK, pid, 0,
              (uintptr_t)&tte, sizeof tte, 0) == -1)
-    perror_with_name ("ttrace");
+    perror_with_name (("ttrace"));
 
   inferior_ptid = pid_to_ptid (pid);
   push_target (ttrace_ops_hack);
@@ -604,7 +630,7 @@ inf_ttrace_detach (char *args, int from_tty)
       char *exec_file = get_exec_file (0);
       if (exec_file == 0)
        exec_file = "";
-      printf_unfiltered ("Detaching from program: %s, %s\n", exec_file,
+      printf_unfiltered (_("Detaching from program: %s, %s\n"), exec_file,
                         target_pid_to_str (pid_to_ptid (pid)));
       gdb_flush (gdb_stdout);
     }
@@ -614,14 +640,30 @@ inf_ttrace_detach (char *args, int from_tty)
   /* ??? The HP-UX 11.0 ttrace(2) manual page doesn't mention that we
      can pass a signal number here.  Does this really work?  */
   if (ttrace (TT_PROC_DETACH, pid, 0, 0, sig, 0) == -1)
-    perror_with_name ("ttrace");
+    perror_with_name (("ttrace"));
 
-  inf_ttrace_num_threads_in_syscall = 0;
+  inf_ttrace_num_lwps = 0;
+  inf_ttrace_num_lwps_in_syscall = 0;
 
   unpush_target (ttrace_ops_hack);
   inferior_ptid = null_ptid;
 }
 
+static int
+inf_ttrace_resume_callback (struct thread_info *info, void *arg)
+{
+  if (!ptid_equal (info->ptid, inferior_ptid))
+    {
+      pid_t pid = ptid_get_pid (info->ptid);
+      lwpid_t lwpid = ptid_get_lwp (info->ptid);
+
+      if (ttrace (TT_LWP_CONTINUE, pid, lwpid, TT_NOPC, 0, 0) == -1)
+       perror_with_name (("ttrace"));
+    }
+
+  return 0;
+}
+
 static void
 inf_ttrace_resume (ptid_t ptid, int step, enum target_signal signal)
 {
@@ -637,13 +679,12 @@ inf_ttrace_resume (ptid_t ptid, int step, enum target_signal signal)
     }
 
   if (ttrace (request, pid, lwpid, TT_NOPC, sig, 0) == -1)
-    perror_with_name ("ttrace");
+    perror_with_name (("ttrace"));
 
-  if (ptid_equal (ptid, minus_one_ptid))
+  if (ptid_equal (ptid, minus_one_ptid) && inf_ttrace_num_lwps > 0)
     {
       /* Let all the other threads run too.  */
-      if (ttrace (TT_PROC_CONTINUE, pid, 0, 0, 0, 0) == -1)
-       perror_with_name ("ttrace");
+      iterate_over_threads (inf_ttrace_resume_callback, NULL);
     }
 }
 
@@ -655,7 +696,7 @@ inf_ttrace_wait (ptid_t ptid, struct target_waitstatus *ourstatus)
   ttstate_t tts;
 
   /* Until proven otherwise.  */
-  ourstatus->kind = TARGET_WAITKIND_IGNORE;
+  ourstatus->kind = TARGET_WAITKIND_SPURIOUS;
 
   if (pid == -1)
     pid = 0;
@@ -668,7 +709,7 @@ inf_ttrace_wait (ptid_t ptid, struct target_waitstatus *ourstatus)
       set_sigio_trap ();
 
       if (ttrace_wait (pid, lwpid, TTRACE_WAITOK, &tts, sizeof tts) == -1)
-       perror_with_name ("ttrace_wait");
+       perror_with_name (("ttrace_wait"));
 
       clear_sigio_trap ();
       clear_sigint_trap ();
@@ -678,13 +719,23 @@ inf_ttrace_wait (ptid_t ptid, struct target_waitstatus *ourstatus)
   /* Now that we've waited, we can re-enable the page protections.  */
   if (inf_ttrace_reenable_page_protections)
     {
-      gdb_assert (inf_ttrace_num_threads_in_syscall == 0);
+      gdb_assert (inf_ttrace_num_lwps_in_syscall == 0);
       inf_ttrace_enable_page_protections (tts.tts_pid);
       inf_ttrace_reenable_page_protections = 0;
     }
 
+  ptid = ptid_build (tts.tts_pid, tts.tts_lwpid, 0);
+
   switch (tts.tts_event)
     {
+#ifdef TTEVT_BPT_SSTEP
+    case TTEVT_BPT_SSTEP:
+      /* Make it look like a breakpoint.  */
+      ourstatus->kind = TARGET_WAITKIND_STOPPED;
+      ourstatus->value.sig = TARGET_SIGNAL_TRAP;
+      break;
+#endif
+
     case TTEVT_EXEC:
       /* Make it look like a breakpoint.  */
       ourstatus->kind = TARGET_WAITKIND_STOPPED;
@@ -693,6 +744,40 @@ inf_ttrace_wait (ptid_t ptid, struct target_waitstatus *ourstatus)
 
     case TTEVT_EXIT:
       store_waitstatus (ourstatus, tts.tts_u.tts_exit.tts_exitcode);
+      inf_ttrace_num_lwps = 0;
+      break;
+
+    case TTEVT_LWP_CREATE:
+      lwpid = tts.tts_u.tts_thread.tts_target_lwpid;
+      ptid = ptid_build (tts.tts_pid, lwpid, 0);
+      if (inf_ttrace_num_lwps == 0)
+       {
+         /* Now that we're going to be multi-threaded, add the
+            origional thread to the list first.  */
+         add_thread (ptid_build (tts.tts_pid, tts.tts_lwpid, 0));
+         inf_ttrace_num_lwps++;
+       }
+      printf_filtered (_("[New %s]\n"), target_pid_to_str (ptid));
+      add_thread (ptid);
+      inf_ttrace_num_lwps++;
+      ptid = ptid_build (tts.tts_pid, tts.tts_lwpid, 0);
+      break;
+
+    case TTEVT_LWP_EXIT:
+      printf_filtered(_("[%s exited]\n"), target_pid_to_str (ptid));
+      delete_thread (ptid);
+      inf_ttrace_num_lwps--;
+      /* If we don't return -1 here, core GDB will re-add the thread.  */
+      ptid = minus_one_ptid;
+      break;
+
+    case TTEVT_LWP_TERMINATE:
+      lwpid = tts.tts_u.tts_thread.tts_target_lwpid;
+      ptid = ptid_build (tts.tts_pid, lwpid, 0);
+      printf_filtered(_("[%s has been terminated]\n"), target_pid_to_str (ptid));
+      delete_thread (ptid);
+      inf_ttrace_num_lwps--;
+      ptid = ptid_build (tts.tts_pid, tts.tts_lwpid, 0);
       break;
 
     case TTEVT_SIGNAL:
@@ -703,8 +788,8 @@ inf_ttrace_wait (ptid_t ptid, struct target_waitstatus *ourstatus)
 
     case TTEVT_SYSCALL_ENTRY:
       gdb_assert (inf_ttrace_reenable_page_protections == 0);
-      inf_ttrace_num_threads_in_syscall++;
-      if (inf_ttrace_num_threads_in_syscall == 1)
+      inf_ttrace_num_lwps_in_syscall++;
+      if (inf_ttrace_num_lwps_in_syscall == 1)
        {
          /* A thread has just entered a system call.  Disable any
              page protections as the kernel can't deal with them.  */
@@ -715,31 +800,35 @@ inf_ttrace_wait (ptid_t ptid, struct target_waitstatus *ourstatus)
       break;
 
     case TTEVT_SYSCALL_RETURN:
-      if (inf_ttrace_num_threads_in_syscall > 0)
+      if (inf_ttrace_num_lwps_in_syscall > 0)
        {
          /* If the last thread has just left the system call, this
             would be a logical place to re-enable the page
             protections, but that doesn't work.  We can't re-enable
             them until we've done another wait.  */
          inf_ttrace_reenable_page_protections = 
-           (inf_ttrace_num_threads_in_syscall == 1);
-         inf_ttrace_num_threads_in_syscall--;
+           (inf_ttrace_num_lwps_in_syscall == 1);
+         inf_ttrace_num_lwps_in_syscall--;
        }
       ourstatus->kind = TARGET_WAITKIND_SYSCALL_RETURN;
       ourstatus->value.syscall_id = tts.tts_scno;
       break;
+
+    default:
+      gdb_assert (!"Unexpected ttrace event");
+      break;
     }
 
   /* Make sure all threads within the process are stopped.  */
   if (ttrace (TT_PROC_STOP, tts.tts_pid, 0, 0, 0, 0) == -1)
-    perror_with_name ("ttrace");
+    perror_with_name (("ttrace"));
 
   /* HACK: Twiddle INFERIOR_PTID such that the initial thread of a
      process isn't recognized as a new thread.  */
   if (ptid_get_lwp (inferior_ptid) == 0)
-    inferior_ptid = ptid_build (tts.tts_pid, tts.tts_lwpid, tts.tts_user_tid);
+    inferior_ptid = ptid;
 
-  return ptid_build (tts.tts_pid, tts.tts_lwpid, tts.tts_user_tid);
+  return ptid;
 }
 
 /* Transfer LEN bytes from ADDR in the inferior's memory into READBUF,
@@ -801,10 +890,35 @@ inf_ttrace_xfer_partial (struct target_ops *ops, enum target_object object,
 static void
 inf_ttrace_files_info (struct target_ops *ignore)
 {
-  printf_unfiltered ("\tUsing the running image of %s %s.\n",
+  printf_unfiltered (_("\tUsing the running image of %s %s.\n"),
                     attach_flag ? "attached" : "child",
                     target_pid_to_str (inferior_ptid));
 }
+
+static int
+inf_ttrace_thread_alive (ptid_t ptid)
+{
+  return 1;
+}
+
+static char *
+inf_ttrace_pid_to_str (ptid_t ptid)
+{
+  if (inf_ttrace_num_lwps > 0)
+    {
+      pid_t pid = ptid_get_pid (ptid);
+      lwpid_t lwpid = ptid_get_lwp (ptid);
+      static char buf[128];
+      int size;
+
+      size = snprintf (buf, sizeof buf, "process %ld, lwp %ld",
+                      (long)pid, (long)lwpid);
+      gdb_assert (size < sizeof buf);
+      return buf;
+    }
+
+  return normal_pid_to_str (ptid);
+}
 \f
 
 struct target_ops *
@@ -821,6 +935,8 @@ inf_ttrace_target (void)
   t->to_wait = inf_ttrace_wait;
   t->to_xfer_partial = inf_ttrace_xfer_partial;
   t->to_files_info = inf_ttrace_files_info;
+  t->to_thread_alive = inf_ttrace_thread_alive;
+  t->to_pid_to_str = inf_ttrace_pid_to_str;
   t->to_can_use_hw_breakpoint = inf_ttrace_can_use_hw_breakpoint;
   t->to_region_size_ok_for_hw_watchpoint =
     inf_ttrace_region_size_ok_for_hw_watchpoint;
@@ -831,6 +947,7 @@ inf_ttrace_target (void)
   ttrace_ops_hack = t;
   return t;
 }
+#endif
 \f
 
 /* Prevent warning from -Wmissing-prototypes.  */
@@ -839,6 +956,7 @@ void _initialize_hppa_hpux_nat (void);
 void
 _initialize_inf_ttrace (void)
 {
+#ifdef HAVE_TTRACE
   inf_ttrace_page_dict.pagesize = getpagesize();
-}
 #endif
+}
This page took 0.031055 seconds and 4 git commands to generate.