* inf-ttrace.c: Include "gdbthread.h".
authorMark Kettenis <kettenis@gnu.org>
Tue, 7 Dec 2004 19:57:21 +0000 (19:57 +0000)
committerMark Kettenis <kettenis@gnu.org>
Tue, 7 Dec 2004 19:57:21 +0000 (19:57 +0000)
(inf_ttrace_num_lwps): New variable.
(inf_ttrace_num_lwps_in_syscall): Renamed from
inf_ttrace_num_threads_in_syscall.
(inf_ttrace_him): Track TTEVT_LWP_CREATE, TTEVT_LWP_EXIT and
TTEVT_LWP_TERMINATE events.
(inf_ttrace_create_inferior): Assert that INF_TTRACE_NUM_LWPS is
zero.
(inf_ttrace_mourn_inferior): Set INF_TTRACE_NUM_LWPS to zero.
(inf_ttrace_attach): Assert that INF_TTRACE_NUM_LWPS is zero.
Track TTEVT_LWP_CREATE, TTEVT_LWP_EXIT and TTEVT_LWP_TERMINATE
events.
(inf_ttrace_wait): Report status as TARGET_WAITKIND_SPURIOUS by
default.  Handle TTEVT_LWP_CREATE, TTEVT_LWP_EXIT and
TTEVT_LWP_TERMINATE events.
(inf_ttrace_thread_alive, inf_ttrace_pid_to_str): New functions.
(inf_ttrace_target): Set to_thread_alive and to_pid_to_str.
* Makefile.in (inf-ttrace.o): Update dependencies.

gdb/ChangeLog
gdb/Makefile.in
gdb/inf-ttrace.c

index 49d9e5f70ba5aa256da1e066fd53f0acdd067c8f..6cf5b2904f88adc67ad96eda8a74c63f1a86ce06 100644 (file)
@@ -1,5 +1,24 @@
 2004-12-07  Mark Kettenis  <kettenis@gnu.org>
 
+       * inf-ttrace.c: Include "gdbthread.h".
+       (inf_ttrace_num_lwps): New variable.
+       (inf_ttrace_num_lwps_in_syscall): Renamed from
+       inf_ttrace_num_threads_in_syscall.
+       (inf_ttrace_him): Track TTEVT_LWP_CREATE, TTEVT_LWP_EXIT and
+       TTEVT_LWP_TERMINATE events.
+       (inf_ttrace_create_inferior): Assert that INF_TTRACE_NUM_LWPS is
+       zero.
+       (inf_ttrace_mourn_inferior): Set INF_TTRACE_NUM_LWPS to zero.
+       (inf_ttrace_attach): Assert that INF_TTRACE_NUM_LWPS is zero.
+       Track TTEVT_LWP_CREATE, TTEVT_LWP_EXIT and TTEVT_LWP_TERMINATE
+       events.
+       (inf_ttrace_wait): Report status as TARGET_WAITKIND_SPURIOUS by
+       default.  Handle TTEVT_LWP_CREATE, TTEVT_LWP_EXIT and
+       TTEVT_LWP_TERMINATE events.
+       (inf_ttrace_thread_alive, inf_ttrace_pid_to_str): New functions.
+       (inf_ttrace_target): Set to_thread_alive and to_pid_to_str.
+       * Makefile.in (inf-ttrace.o): Update dependencies.
+
        * hppa-tdep.h (hppa_read_pc, hppa_write_pc, hppa_unwind_pc): New
        prototypes.
        * hppa-tdep.c (hppa_read_pc): Rename from hppa_target_read_pc.
index ddac59950d5cb98275671251de1ad9a0cd255a80..08b7bfdd3adc8a10273490332573a00ca29f7ef4 100644 (file)
@@ -2088,9 +2088,9 @@ inflow.o: inflow.c $(defs_h) $(frame_h) $(inferior_h) $(command_h) \
 inf-ptrace.o: inf-ptrace.c $(defs_h) $(command_h) $(inferior_h) $(inflow_h) \
        $(gdbcore_h) $(observer_h) $(gdb_string_h) $(gdb_ptrace_h) \
        $(gdb_wait_h) $(inf_child_h)
-inf-ttrace.o: inf-ttrace.c $(defs_h) $(command_h) $(inferior_h) \
-       $(observer_h) $(target_h) $(gdb_assert_h) $(gdb_string_h) \
-       $(inf_child_h) $(inf_ttrace_h)
+inf-ttrace.o: inf-ttrace.c $(defs_h) $(command_h) $(gdbcore_h) \
+       $(gdbthread_h)$(inferior_h) $(observer_h) $(target_h) \
+       $(gdb_assert_h) $(gdb_string_h) $(inf_child_h) $(inf_ttrace_h)
 infptrace.o: infptrace.c $(defs_h) $(command_h) $(frame_h) $(gdbcore_h) \
        $(inferior_h) $(regcache_h) $(target_h) $(gdb_assert_h) \
        $(gdb_wait_h) $(gdb_string_h) $(gdb_dirent_h) $(gdb_ptrace_h)
index 2d2074d8280e216c869f03d6155336dc3b08a1ed..136896109e0a113b9feb9263da09118b51856c28 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,7 +94,7 @@ 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)
@@ -97,7 +111,7 @@ inf_ttrace_enable_syscall_events (pid_t pid)
     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.  */
 }
@@ -121,7 +135,7 @@ inf_ttrace_disable_syscall_events (pid_t pid)
              (uintptr_t)&tte, sizeof tte, 0) == -1)
     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
@@ -191,7 +205,7 @@ 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)
@@ -231,7 +245,7 @@ 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)
@@ -449,7 +463,8 @@ inf_ttrace_him (int pid)
 
   /* 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;
   tte.tte_opts = TTEO_NOSTRCCHLD;
   if (ttrace (TT_PROC_SET_EVENT_MASK, pid, 0,
              (uintptr_t)&tte, sizeof tte, 0) == -1)
@@ -484,8 +499,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,
@@ -518,7 +534,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++)
     {
@@ -572,14 +589,17 @@ inf_ttrace_attach (char *args, int from_tty)
       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");
   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;
   tte.tte_opts = TTEO_NOSTRCCHLD;
   if (ttrace (TT_PROC_SET_EVENT_MASK, pid, 0,
              (uintptr_t)&tte, sizeof tte, 0) == -1)
@@ -616,7 +636,8 @@ inf_ttrace_detach (char *args, int from_tty)
   if (ttrace (TT_PROC_DETACH, pid, 0, 0, sig, 0) == -1)
     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;
@@ -655,7 +676,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;
@@ -678,11 +699,13 @@ 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)
     {
     case TTEVT_EXEC:
@@ -693,6 +716,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 +760,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,19 +772,23 @@ 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.  */
@@ -737,9 +798,9 @@ inf_ttrace_wait (ptid_t ptid, struct target_waitstatus *ourstatus)
   /* 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,
@@ -805,6 +866,28 @@ inf_ttrace_files_info (struct target_ops *ignore)
                     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[80];
+
+      sprintf (buf, "process %ld, lwp %ld", (long)pid, (long)lwpid);
+      return buf;
+    }
+
+  return normal_pid_to_str (ptid);
+}
 \f
 
 struct target_ops *
@@ -821,6 +904,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;