This is the mail archive of the gdb-patches@sources.redhat.com mailing list for the GDB project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Re: [RFA]: Watchpoints per thread patch


Eli Zaretskii wrote:
Date: Wed, 27 Oct 2004 18:36:14 -0400
From: Jeff Johnston <jjohnstn@redhat.com>
Cc: Andrew Cagney <cagney@gnu.org>, gdb-patches@sources.redhat.com

The attached patch is the rework of my original attempt. It no longer uses configuration or magic defines. Per Mark's suggestion, it uses an observer to handle inserting watchpoints on a new thread and only the low-level code knows about inserting/removing watchpoints on all threads.

Ok to commit?


A few comments:


+/* External function to insert all existing watchpoints on a newly
+   attached thread.  IWPFN is a callback function to perform
+   the target insert watchpoint.  This function is used to support
+   platforms whereby a watchpoint must be inserted/removed on each
+   individual thread (e.g. ia64-linux and s390-linux).  For
+   ia64 and s390 linux, this function is called via a new thread
+   observer.  */


In this comment, the word "whereby" should be replaced by "where", I
think.


Ok, done.



--- target.h	8 Oct 2004 20:29:55 -0000	1.65
+++ target.h	27 Oct 2004 21:43:51 -0000
@@ -178,6 +178,15 @@ extern char *target_signal_to_name (enum
/* Given a name (SIGHUP, etc.), return its signal.  */
enum target_signal target_signal_from_name (char *);

+
+/* Watchpoint specification.  */
+struct target_watchpoint
+  {
+    CORE_ADDR addr;
+    int len;
+    int type;
+  };
+


Why do we put on target.h, which is a general header, a definition of
a struct used only on certain platforms?


I have moved this to linux-nat.h and renamed it struct linux_watchpoint.



--- doc/observer.texi 1 Sep 2004 17:59:37 -0000 1.8
+++ doc/observer.texi 27 Oct 2004 21:43:51 -0000
@@ -95,3 +95,7 @@ inferior, and before any information on The specified shared library has been discovered to be unloaded.
@end deftypefun


+@deftypefun void new_thread (ptid_t @var{ptid})
+A new thread has been attached to.


"A new thread has been attached" to what?  The description of the
observer should at least reference the argument @var{ptid}.


I have changed the definition to be more meaningful now that it is being used generically by all.


On Thu, Oct 28, 2004 at 03:47:22PM -0400, Jeff Johnston wrote:

>> Daniel Jacobowitz wrote:
>
>>> >On Wed, Oct 27, 2004 at 07:17:13PM -0400, Jeff Johnston wrote:
>>> >
>>
>>>> >>Were you thinking of add_thread()?  If so, we would have to move the
>>>> >>calls to add_thread so they never occur before an attach because the
>>>> >>low-level observers will need the thread already attached.
>>
>>> >
>>> >
>>> >Oh, that's a good point.  Do you think that's a reasonable change to
>>> >make?
>>> >
>
>>

Daniel, I have moved the observer notification to add_thread as suggested. To do this, I had to move a few things in attach_thread. As well, I had to add another part of my full patch in because the ptid that add_thread knows about is in the wrong format (pid, 0, tid). The low-level insert watchpoint code needs the lwp so I have added in my target_get_lwp change. I realize you have plans to change how the ptid is kept, but until that is fleshed out, this change is required. I used a call-back to allow breakpoint.c which knows how to handle watchpoints to communicate with the low-level linux code that knows how to insert/remove a watchpoint.

I have tested on ia64 and s390 linux. The ia64 requires another patch to make it pass the watchthreads.exp test. S390 linux can't pass that test without additional hardware support, however, I will note that s390 is properly recognizing hardware watchpoints on threads which is a major step forward.

Ok to commit?

2004-11-04 Jeff Johnston <jjohnstn@redhat.com>

        * breakpoint.c (insert_watchpoints_for_new_thread): New function.
        (print_it_typical): Do not issue an error for bp_thread_event
        if a subsequent event is on the chain.
        * breakpoint.h (insert_watchpoints_for_new_thread): New prototype.
        * ia64-linux-nat.c (ia64_linux_insert_one_watchpoint): New function.
        (ia64_linux_insert_watchpoint_callback): Ditto.
        (ia64_linux_insert_watchpoint): Change to iterate through lwps
        and insert the specified watchpoint per thread.
        (ia64_stopped_data_address): Call target_get_lwp to ensure
        the ptid has its lwp field filled in.
        (ia64_linux_remove_one_watchpoint): New function.
        (ia64_linux_remove_watchpoint_callback): Ditto.
        (ia64_linux_remove_watchpoint): Change to iterate through lwps and
        remove the specified watchpoint for each thread.
        (ia64_linux_new_thread): New thread observer.
        (_initialize_ia64_linux_nat): New function.  Initialize
        new thread observer.
        * linux-nat.h (struct linux_watchpoint): New structure.
        * thread-db.c (attach_thread): Add the thread after attaching
        to it.  Before allocating the thread private info area, check
        to see if it has already been allocated.
        (thread_db_get_info): Allocate a thread private info area if
        one doesn't already exist.
        (init_thread_db_ops): Point to_get_lwp to lwp_from_thread function.
        * thread.c (add_thread): Notify any observers of a new thread event.
        * s390-nat.c (s390_tid): New function.
        (s390_inferior_tid): Change to call s390_tid.
        (s390_remove_one_watchpoint): New function.
        (s390_remove_watchpoint_callback): Ditto.
        (s390_remove_watchpoint): Change to iterate through lwps and
        remove the specified watchpoint for each thread.
        (s390_insert_one_watchpoint): New function.
        (s390_insert_watchpoint_callback): Ditto.
        (s390_insert_watchpoint): Change to iterate through lwps and
        insert the specified watchpoint on each thread.
        (s390_new_thread): New thread observer.
        (_initialize_s390_nat): New function.  Initialize
        new thread observer.
        * target.c (return_ptid): New static function.
        (update_current_target): Add support for new to_get_lwp.
        (init_dummy_target): Ditto.
        * target.h (struct target_ops): Add to_get_lwp.
        (target_get_lwp): New macro.


doc/ChangeLog:


2004-11-04 Jeff Johnston <jjohnstn@redhat.com>

* observer.texi (new_thread): New observer.





Index: breakpoint.c
===================================================================
RCS file: /cvs/src/src/gdb/breakpoint.c,v
retrieving revision 1.184
diff -u -p -r1.184 breakpoint.c
--- breakpoint.c	29 Oct 2004 20:23:04 -0000	1.184
+++ breakpoint.c	4 Nov 2004 18:19:11 -0000
@@ -748,6 +748,91 @@ insert_catchpoint (struct ui_out *uo, vo
   return 0;
 }
 
+/* External function to insert all existing watchpoints on a newly
+   attached thread.  IWPFN is a callback function to perform
+   the target insert watchpoint.  This function is used to support
+   platforms where a watchpoint must be inserted/removed on each
+   individual thread (e.g. ia64-linux and s390-linux).  For
+   ia64 and s390 linux, this function is called via a new thread
+   observer.  */
+int
+insert_watchpoints_for_new_thread (ptid_t new_thread, 
+				   insert_watchpoint_ftype *iwpfn)
+{
+  struct bp_location *b;
+  int val = 0;
+  int return_val = 0;
+  struct ui_file *tmp_error_stream = mem_fileopen ();
+  make_cleanup_ui_file_delete (tmp_error_stream);
+
+  /* Explicitly mark the warning -- this will only be printed if
+     there was an error.  */
+  fprintf_unfiltered (tmp_error_stream, "Warning:\n");
+
+  ALL_BP_LOCATIONS (b)
+    {
+      /* Skip disabled breakpoints.  */
+      if (!breakpoint_enabled (b->owner))
+	continue;
+
+      /* For every active watchpoint, we need to insert the watchpoint on 
+         the new thread.  */
+      if ((b->loc_type == bp_loc_hardware_watchpoint
+	   || b->owner->type == bp_watchpoint))
+	{
+	  struct value *v = b->owner->val_chain;
+
+	  /* Look at each value on the value chain.  */
+	  for (; v; v = v->next)
+	    {
+	      /* If it's a memory location, and GDB actually needed
+		 its contents to evaluate the expression, then we
+		 must watch it.  */
+	      if (VALUE_LVAL (v) == lval_memory
+		  && ! VALUE_LAZY (v))
+		{
+		  struct type *vtype = check_typedef (VALUE_TYPE (v));
+		  
+		  /* We only watch structs and arrays if user asked
+		     for it explicitly, never if they just happen to
+		     appear in the middle of some value chain.  */
+		  if (v == b->owner->val_chain
+		      || (TYPE_CODE (vtype) != TYPE_CODE_STRUCT
+			  && TYPE_CODE (vtype) != TYPE_CODE_ARRAY))
+		    {
+		      CORE_ADDR addr;
+		      int len, type;
+		      
+		      addr = VALUE_ADDRESS (v) + VALUE_OFFSET (v);
+		      len = TYPE_LENGTH (VALUE_TYPE (v));
+		      type = hw_write;
+		      if (b->owner->type == bp_read_watchpoint)
+			type = hw_read;
+		      else if (b->owner->type == bp_access_watchpoint)
+			type = hw_access;
+		      val = (*iwpfn) (new_thread, addr, len, type); 
+		    }
+		}
+	    }
+	}
+
+      if (val)
+	return_val = val;
+    }
+
+  /* Failure to insert a watchpoint on any memory value in the
+     value chain brings us here.  */
+  if (return_val)
+    {
+      fprintf_unfiltered (tmp_error_stream,
+			  "%s\n",
+			  "Could not insert hardware watchpoints on new thread."); 
+      target_terminal_ours_for_output ();
+      error_stream (tmp_error_stream);
+    }
+  return return_val;
+}
+
 /* Helper routine: free the value chain for a breakpoint (watchpoint).  */
 
 static void free_valchain (struct bp_location *b)
@@ -2122,8 +2207,13 @@ print_it_typical (bpstat bs)
       break;
 
     case bp_thread_event:
-      /* Not sure how we will get here. 
-	 GDB should not stop for these breakpoints.  */
+      /* We can only get here legitimately if something further on the bs 
+	 list has caused the stop status to be noisy.  A valid example
+	 of this is a new thread event and a software watchpoint have
+	 both occurred.  */
+      if (bs->next)
+        return PRINT_UNKNOWN;
+
       printf_filtered ("Thread Event Breakpoint: gdb should not stop!\n");
       return PRINT_NOTHING;
       break;
Index: breakpoint.h
===================================================================
RCS file: /cvs/src/src/gdb/breakpoint.h,v
retrieving revision 1.34
diff -u -p -r1.34 breakpoint.h
--- breakpoint.h	13 May 2004 16:39:11 -0000	1.34
+++ breakpoint.h	4 Nov 2004 18:19:11 -0000
@@ -663,6 +663,12 @@ extern void tbreak_command (char *, int)
 
 extern int insert_breakpoints (void);
 
+/* The following provides a callback mechanism to insert watchpoints
+   for a new thread.  This is needed, for example, on ia64 linux.  */
+typedef int (insert_watchpoint_ftype) (ptid_t, CORE_ADDR, int, int);
+extern int insert_watchpoints_for_new_thread (ptid_t ptid,
+					      insert_watchpoint_ftype *fn);
+
 extern int remove_breakpoints (void);
 
 /* This function can be used to physically insert eventpoints from the
Index: ia64-linux-nat.c
===================================================================
RCS file: /cvs/src/src/gdb/ia64-linux-nat.c,v
retrieving revision 1.26
diff -u -p -r1.26 ia64-linux-nat.c
--- ia64-linux-nat.c	13 Oct 2004 21:40:41 -0000	1.26
+++ ia64-linux-nat.c	4 Nov 2004 18:19:11 -0000
@@ -39,6 +39,8 @@
 
 #include <asm/ptrace_offsets.h>
 #include <sys/procfs.h>
+#include "observer.h"
+#include "linux-nat.h"
 
 /* Prototypes for supply_gregset etc. */
 #include "gregset.h"
@@ -559,8 +561,9 @@ is_power_of_2 (int val)
   return onecount <= 1;
 }
 
-int
-ia64_linux_insert_watchpoint (ptid_t ptid, CORE_ADDR addr, int len, int rw)
+/* Internal routine to insert one watchpoint for a specified thread.  */
+static int
+ia64_linux_insert_one_watchpoint (ptid_t ptid, CORE_ADDR addr, int len, int rw)
 {
   int idx;
   long dbr_addr, dbr_mask;
@@ -606,8 +609,38 @@ ia64_linux_insert_watchpoint (ptid_t pti
   return 0;
 }
 
+/* Internal callback routine which can be used via iterate_over_lwps
+   to insert a specific watchpoint from all active threads.  */
+static int
+ia64_linux_insert_watchpoint_callback (struct lwp_info *lwp, void *data)
+{
+  struct linux_watchpoint *args = (struct linux_watchpoint *)data;
+
+  return ia64_linux_insert_one_watchpoint (lwp->ptid, args->addr,
+		 		     	   args->len, args->type);
+}
+
+/* Insert a watchpoint for all threads.  */
 int
-ia64_linux_remove_watchpoint (ptid_t ptid, CORE_ADDR addr, int len)
+ia64_linux_insert_watchpoint (ptid_t ptid, CORE_ADDR addr, int len, int rw)
+{
+  struct linux_watchpoint args;
+
+  args.addr = addr;
+  args.len = len;
+  args.type = rw;
+
+  /* For ia64, watchpoints must be inserted/removed on each thread so
+     we iterate over the lwp list.  */
+  if (iterate_over_lwps (&ia64_linux_insert_watchpoint_callback, &args))
+    return -1;
+
+  return 0;
+}
+
+/* Internal routine to remove one watchpoint for a specified thread.  */
+static int
+ia64_linux_remove_one_watchpoint (ptid_t ptid, CORE_ADDR addr, int len)
 {
   int idx;
   long dbr_addr, dbr_mask;
@@ -630,13 +663,41 @@ ia64_linux_remove_watchpoint (ptid_t pti
   return -1;
 }
 
+/* Internal callback routine which can be used via iterate_over_lwps
+   to remove a specific watchpoint from all active threads.  */
+static int
+ia64_linux_remove_watchpoint_callback (struct lwp_info *lwp, void *data)
+{
+  struct linux_watchpoint *args = (struct linux_watchpoint *)data;
+
+  return ia64_linux_remove_one_watchpoint (lwp->ptid, args->addr,
+		 		     	   args->len);
+}
+
+/* Remove a watchpoint for all threads.  */
+int
+ia64_linux_remove_watchpoint (ptid_t ptid, CORE_ADDR addr, int len)
+{
+  struct linux_watchpoint args;
+
+  args.addr = addr;
+  args.len = len;
+
+  /* For ia64, watchpoints must be inserted/removed on each thread so
+     we iterate over the lwp list.  */
+  if (iterate_over_lwps (&ia64_linux_remove_watchpoint_callback, &args))
+    return -1;
+
+  return 0;
+}
+
 int
 ia64_linux_stopped_data_address (CORE_ADDR *addr_p)
 {
   CORE_ADDR psr;
   int tid;
   struct siginfo siginfo;
-  ptid_t ptid = inferior_ptid;
+  ptid_t ptid = target_get_lwp (inferior_ptid);
 
   tid = TIDGET(ptid);
   if (tid == 0)
@@ -674,3 +735,31 @@ ia64_linux_xfer_unwind_table (struct tar
 {
   return syscall (__NR_getunwind, readbuf, len);
 }
+
+/* Internal callback for insert_watchpoints_for_new_thread to call.
+   The PTID will be in the thread-level format and must be
+   translated to the lwp-level format before calling
+   ia64_linux_insert_one_watchpoint to insert any watchpoint.  */
+static int
+ia64_linux_insert_watchpoint_for_thread (ptid_t ptid, CORE_ADDR addr, 
+		                         int len, int rw)
+{
+  ptid_t lwp_ptid = target_get_lwp (ptid);
+  return ia64_linux_insert_one_watchpoint (lwp_ptid, addr, len, rw);
+}
+  
+/* Observer function for a new thread attach.  We need to insert
+   existing watchpoints on the new thread.  */
+static void
+ia64_linux_new_thread (ptid_t ptid)
+{
+  insert_watchpoints_for_new_thread (ptid, 
+		  		     &ia64_linux_insert_watchpoint_for_thread);
+}
+
+void
+_initialize_ia64_linux_nat (void)
+{
+  observer_attach_new_thread (ia64_linux_new_thread);
+}
+    
Index: linux-nat.h
===================================================================
RCS file: /cvs/src/src/gdb/linux-nat.h,v
retrieving revision 1.6
diff -u -p -r1.6 linux-nat.h
--- linux-nat.h	29 Mar 2004 18:07:14 -0000	1.6
+++ linux-nat.h	4 Nov 2004 18:19:11 -0000
@@ -63,6 +63,14 @@ struct lwp_info
   struct lwp_info *next;
 };
 
+/* Watchpoint description.  */
+struct linux_watchpoint
+{
+  CORE_ADDR addr;
+  int len;
+  int type;
+};
+
 /* Read/write to target memory via the Linux kernel's "proc file
    system".  */
 struct mem_attrib;
Index: s390-nat.c
===================================================================
RCS file: /cvs/src/src/gdb/s390-nat.c,v
retrieving revision 1.12
diff -u -p -r1.12 s390-nat.c
--- s390-nat.c	18 Feb 2004 04:17:35 -0000	1.12
+++ s390-nat.c	4 Nov 2004 18:19:12 -0000
@@ -27,6 +27,8 @@
 #include "inferior.h"
 
 #include "s390-tdep.h"
+#include "linux-nat.h"
+#include "observer.h"
 
 #include <asm/ptrace.h>
 #include <sys/ptrace.h>
@@ -112,18 +114,32 @@ fill_fpregset (fpregset_t *regp, int reg
 			      ((char *)regp) + regmap_fpregset[i]);
 }
 
-/* Find the TID for the current inferior thread to use with ptrace.  */
+/* Find the TID for use with ptrace.  */
 static int
-s390_inferior_tid (void)
+s390_tid (ptid_t ptid)
 {
   /* GNU/Linux LWP ID's are process ID's.  */
-  int tid = TIDGET (inferior_ptid);
+  int tid = TIDGET (ptid);
   if (tid == 0)
-    tid = PIDGET (inferior_ptid); /* Not a threaded program.  */
+    {
+      /* In some cases, we have a thread-level format ptid which
+         must be converted to an lwp-level format ptid.  */
+      ptid_t lwp_ptid = target_get_lwp (ptid);
+      tid = TIDGET (lwp_ptid);
+      if (tid == 0)
+        tid = PIDGET (lwp_ptid); /* Not a threaded program.  */
+    }
 
   return tid;
 }
 
+/* Find the TID for the current inferior thread to use with ptrace.  */
+static int
+s390_inferior_tid (void)
+{
+  return s390_tid (inferior_ptid);
+}
+
 /* Fetch all general-purpose registers from process/thread TID and
    store their values in GDB's register cache.  */
 static void
@@ -269,9 +285,9 @@ s390_stopped_by_watchpoint (void)
 }
 
 static void
-s390_fix_watch_points (void)
+s390_fix_watch_points (ptid_t ptid)
 {
-  int tid = s390_inferior_tid ();
+  int tid = s390_tid (ptid);
 
   per_struct per_info;
   ptrace_area parea;
@@ -308,8 +324,9 @@ s390_fix_watch_points (void)
     perror_with_name ("Couldn't modify watchpoint status");
 }
 
-int
-s390_insert_watchpoint (CORE_ADDR addr, int len)
+/* Insert a specified watchpoint on a specified thread.  */
+static int
+s390_insert_one_watchpoint (ptid_t ptid, CORE_ADDR addr, int len, int type)
 {
   struct watch_area *area = xmalloc (sizeof (struct watch_area));
   if (!area)
@@ -321,12 +338,36 @@ s390_insert_watchpoint (CORE_ADDR addr, 
   area->next = watch_base;
   watch_base = area;
 
-  s390_fix_watch_points ();
+  s390_fix_watch_points (ptid);
   return 0;
 }
 
+/* Callback routine to use with iterate_over_lwps to insert a specified
+   watchpoint on all threads.  */
+static int
+s390_insert_watchpoint_callback (struct lwp_info *lwp, void *data)
+{
+  struct linux_watchpoint *args = (struct linux_watchpoint *)data;
+
+  return s390_insert_one_watchpoint (lwp->ptid, args->addr, args->len, 0);
+}
+
+/* Insert a specified watchpoint on all threads.  */
 int
-s390_remove_watchpoint (CORE_ADDR addr, int len)
+s390_insert_watchpoint (CORE_ADDR addr, int len)
+{
+  struct linux_watchpoint args;
+
+  args.addr = addr;
+  args.len = len;
+  /* For the S390, a watchpoint must be inserted/removed for each
+     thread so we iterate over the list of existing lwps.  */
+  return iterate_over_lwps (&s390_insert_watchpoint_callback, &args);
+}
+
+/* Remove a specified watchpoint from a specified thread.  */
+static int
+s390_remove_one_watchpoint (ptid_t ptid, CORE_ADDR addr, int len)
 {
   struct watch_area *area, **parea;
 
@@ -346,10 +387,32 @@ s390_remove_watchpoint (CORE_ADDR addr, 
   *parea = area->next;
   xfree (area);
 
-  s390_fix_watch_points ();
+  s390_fix_watch_points (ptid);
   return 0;
 }
 
+/* Callback routine to use with iterate_over_lwps to remove a specified
+   watchpoint from all threads.  */
+static int
+s390_remove_watchpoint_callback (struct lwp_info *lwp, void *data)
+{
+  struct linux_watchpoint *args = (struct linux_watchpoint *)data;
+
+  return s390_remove_one_watchpoint (lwp->ptid, args->addr, args->len);
+}
+
+/* Remove a specified watchpoint from all threads.  */
+int
+s390_remove_watchpoint (CORE_ADDR addr, int len)
+{
+  struct linux_watchpoint args;
+
+  args.addr = addr;
+  args.len = len;
+  /* For the S390, a watchpoint must be inserted/removed for each
+     thread so we iterate over the list of existing lwps.  */
+  return iterate_over_lwps (&s390_remove_watchpoint_callback, &args);
+}
 
 int
 kernel_u_size (void)
@@ -357,3 +420,18 @@ kernel_u_size (void)
   return sizeof (struct user);
 }
 
+/* New thread observer that inserts all existing watchpoints on the
+   new thread.  */
+static void
+s390_new_thread (ptid_t ptid)
+{
+  insert_watchpoints_for_new_thread (ptid, &s390_insert_one_watchpoint);
+}
+
+void
+_initialize_s390_nat (void)
+{
+  observer_attach_new_thread (s390_new_thread);
+}
+
+
Index: target.c
===================================================================
RCS file: /cvs/src/src/gdb/target.c,v
retrieving revision 1.90
diff -u -p -r1.90 target.c
--- target.c	8 Oct 2004 20:29:55 -0000	1.90
+++ target.c	4 Nov 2004 18:19:12 -0000
@@ -61,6 +61,8 @@ static int return_one (void);
 
 static int return_minus_one (void);
 
+static ptid_t return_ptid (ptid_t ptid);
+
 void target_ignore (void);
 
 static void target_command (char *, int);
@@ -430,6 +432,7 @@ update_current_target (void)
       INHERIT (to_notice_signals, t);
       INHERIT (to_thread_alive, t);
       INHERIT (to_find_new_threads, t);
+      INHERIT (to_get_lwp, t);
       INHERIT (to_pid_to_str, t);
       INHERIT (to_extra_thread_info, t);
       INHERIT (to_stop, t);
@@ -606,6 +609,9 @@ update_current_target (void)
   de_fault (to_find_new_threads, 
 	    (void (*) (void)) 
 	    target_ignore);
+  de_fault (to_get_lwp,
+            (ptid_t (*) (ptid_t))
+            return_ptid);
   de_fault (to_extra_thread_info, 
 	    (char *(*) (struct thread_info *)) 
 	    return_zero);
@@ -1541,6 +1547,12 @@ return_minus_one (void)
   return -1;
 }
 
+static ptid_t
+return_ptid (ptid_t ptid)
+{
+  return ptid;
+}
+
 /*
  * Resize the to_sections pointer.  Also make sure that anyone that
  * was holding on to an old value of it gets updated.
@@ -1793,6 +1805,7 @@ init_dummy_target (void)
   dummy_target.to_find_memory_regions = dummy_find_memory_regions;
   dummy_target.to_make_corefile_notes = dummy_make_corefile_notes;
   dummy_target.to_xfer_partial = default_xfer_partial;
+  dummy_target.to_get_lwp = return_ptid;
   dummy_target.to_magic = OPS_MAGIC;
 }
 
Index: target.h
===================================================================
RCS file: /cvs/src/src/gdb/target.h,v
retrieving revision 1.65
diff -u -p -r1.65 target.h
--- target.h	8 Oct 2004 20:29:55 -0000	1.65
+++ target.h	4 Nov 2004 18:19:12 -0000
@@ -372,6 +372,7 @@ struct target_ops
     void (*to_notice_signals) (ptid_t ptid);
     int (*to_thread_alive) (ptid_t ptid);
     void (*to_find_new_threads) (void);
+    ptid_t (*to_get_lwp) (ptid_t ptid);
     char *(*to_pid_to_str) (ptid_t);
     char *(*to_extra_thread_info) (struct thread_info *);
     void (*to_stop) (void);
@@ -802,6 +803,10 @@ extern void target_load (char *arg, int 
 #define target_find_new_threads() \
      (*current_target.to_find_new_threads) (); \
 
+/* Get the lwp for a thread.  */
+#define target_get_lwp(ptid) \
+     (*current_target.to_get_lwp) (ptid); \
+
 /* Make target stop in a continuable fashion.  (For instance, under
    Unix, this should act like SIGSTOP).  This function is normally
    used by GUIs to implement a stop button.  */
Index: thread-db.c
===================================================================
RCS file: /cvs/src/src/gdb/thread-db.c,v
retrieving revision 1.46
diff -u -p -r1.46 thread-db.c
--- thread-db.c	8 Oct 2004 20:29:56 -0000	1.46
+++ thread-db.c	4 Nov 2004 18:19:12 -0000
@@ -34,6 +34,7 @@
 #include "target.h"
 #include "regcache.h"
 #include "solib-svr4.h"
+#include "observer.h"
 
 #ifdef HAVE_GNU_LIBC_VERSION_H
 #include <gnu/libc-version.h>
@@ -333,6 +334,17 @@ thread_db_get_info (struct thread_info *
 {
   td_err_e err;
 
+  /* Allocate a private area if needed.  This can occur for ia64 or
+     s390 linux which must insert breakpoints on newly found threads.
+     The observer for a new thread event will be called on an add_thread
+     call before the private area has been set up and will need to
+     get the lwp for the new ptid using this function.  */
+  if (!thread_info->private)
+    {
+      thread_info->private = xmalloc (sizeof (struct private_thread_info));
+      memset (thread_info->private, 0, sizeof (struct private_thread_info));
+    }
+
   if (thread_info->private->ti_valid)
     return &thread_info->private->ti;
 
@@ -746,14 +758,6 @@ attach_thread (ptid_t ptid, const td_thr
 
   check_thread_signals ();
 
-  /* Add the thread to GDB's thread list.  */
-  tp = add_thread (ptid);
-  tp->private = xmalloc (sizeof (struct private_thread_info));
-  memset (tp->private, 0, sizeof (struct private_thread_info));
-
-  if (verbose)
-    printf_unfiltered ("[New %s]\n", target_pid_to_str (ptid));
-
   if (ti_p->ti_state == TD_THR_UNKNOWN || ti_p->ti_state == TD_THR_ZOMBIE)
     return;			/* A zombie thread -- do not attach.  */
 
@@ -762,6 +766,21 @@ attach_thread (ptid_t ptid, const td_thr
   ATTACH_LWP (BUILD_LWP (ti_p->ti_lid, GET_PID (ptid)), 0);
 #endif
 
+  /* Add the thread to GDB's thread list.  
+     We do this after attaching so any observers of a new
+     thread event can perform PTRACE operations on the thread
+     if needed.  An observer may end up allocating the
+     private info area, so check first.  */
+  tp = add_thread (ptid);
+  if (!tp->private)
+    {
+      tp->private = xmalloc (sizeof (struct private_thread_info));
+      memset (tp->private, 0, sizeof (struct private_thread_info));
+    }
+
+  if (verbose)
+    printf_unfiltered ("[New %s]\n", target_pid_to_str (ptid));
+
   /* Enable thread event reporting for this thread.  */
   err = td_thr_event_enable_p (th_p, 1);
   if (err != TD_OK)
@@ -1346,6 +1365,7 @@ init_thread_db_ops (void)
   thread_db_ops.to_mourn_inferior = thread_db_mourn_inferior;
   thread_db_ops.to_thread_alive = thread_db_thread_alive;
   thread_db_ops.to_find_new_threads = thread_db_find_new_threads;
+  thread_db_ops.to_get_lwp = lwp_from_thread;
   thread_db_ops.to_pid_to_str = thread_db_pid_to_str;
   thread_db_ops.to_stratum = thread_stratum;
   thread_db_ops.to_has_thread_control = tc_schedlock;
Index: thread.c
===================================================================
RCS file: /cvs/src/src/gdb/thread.c,v
retrieving revision 1.39
diff -u -p -r1.39 thread.c
--- thread.c	29 Oct 2004 20:23:13 -0000	1.39
+++ thread.c	4 Nov 2004 18:19:12 -0000
@@ -130,6 +130,10 @@ add_thread (ptid_t ptid)
   tp->num = ++highest_thread_num;
   tp->next = thread_list;
   thread_list = tp;
+
+  /* Inform any observers of the new thread.  */
+  observer_notify_new_thread (ptid);
+
   return tp;
 }
 
Index: doc/observer.texi
===================================================================
RCS file: /cvs/src/src/gdb/doc/observer.texi,v
retrieving revision 1.8
diff -u -p -r1.8 observer.texi
--- doc/observer.texi	1 Sep 2004 17:59:37 -0000	1.8
+++ doc/observer.texi	4 Nov 2004 18:19:12 -0000
@@ -95,3 +95,7 @@ inferior, and before any information on 
 The specified shared library has been discovered to be unloaded.
 @end deftypefun
 
+@deftypefun void new_thread (ptid_t @var{ptid})
+A new thread described by @var{ptid} has been detected by gdb.
+@end deftypefun
+

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]