Blob Blame History Raw
2004-12-13  Jeff Johnston  <jjohnstn@redhat.com>

        * linux-nat.c: (stop_wait_callback, linux-nat-wait): Notify
	observers of a sigtrap.
	(delete_lwp): Free the saved_trap_data if present.
	* linux-nat.h (struct lwp_info): Add saved_trap_data field.
	(struct linux_watchpoint): New struct.
	* linux-thread-db.c: Add support to always keep lwp info in ptids.
	(attach_thread): Notify observers of a linux
	new thread.
	(thread_db_wait): Call check_event if SIGILL occurs.
	* infrun.c: (handle_inferior_event): For platforms that
	hit watchpoints prior to the data write, mark the watchpoints
	so we know to check them after we step through the write.
	* breakpoint.c (bpstat_stop_status): Fix up watchpoint code.
	(insert_watchpoints_for_new_thread): New function.
	(mark_triggered_watchpoints): Ditto.
	* breakpoint.h (insert_watchpoints_for_new_thread): New prototype.
	(mark_triggered_watchpoints): Ditto.
	* i386-linux-nat.c (i386_linux_dr_get, i386_linux_dr_set): Use
	TIDGET to get PTRACE lpw, otherwise fall back to PIDGET.
	* amd64-linux-nat.c (amd64_linux_dr_get, amd64_linux_dr_set): Ditto.
	* ia64-linux-nat.c: Add support for removing and inserting watchpoints
	on all threads.
	* s390-nat.c: Ditto.
	* Makefile.in: Add observer.h and linux-nat.h to ia64-linux-nat.o
	and s390-nat.o.
	* doc/observer.texi: Add two new observers for linux_new_thread
	and sigtrap.

2007-10-13  Jan Kratochvil  <jan.kratochvil@redhat.com>

	Port to GDB-6.7.

Index: gdb-6.7/gdb/doc/observer.texi
===================================================================
--- gdb-6.7.orig/gdb/doc/observer.texi	2007-05-11 21:55:20.000000000 +0200
+++ gdb-6.7/gdb/doc/observer.texi	2007-10-13 04:51:21.000000000 +0200
@@ -129,3 +129,12 @@ Called with @var{objfile} equal to @code
 previously loaded symbol table data has now been invalidated.
 @end deftypefun
 
+@deftypefun void linux_new_thread (ptid_t @var{ptid})
+A new linux thread described by @var{ptid} has been officially attached
+to by gdb.
+@end deftypefun
+
+@deftypefun void sigtrap (void * @var{data})
+A low-level SIGTRAP has been discovered.  This notification can be used to save
+additional state necessary if the trap is deferred for later handling.
+@end deftypefun
Index: gdb-6.7/gdb/infrun.c
===================================================================
--- gdb-6.7.orig/gdb/infrun.c	2007-10-12 22:35:58.000000000 +0200
+++ gdb-6.7/gdb/infrun.c	2007-10-13 04:50:11.000000000 +0200
@@ -1784,9 +1784,19 @@ handle_inferior_event (struct execution_
      single step over a watchpoint without disabling the watchpoint.  */
   if (HAVE_STEPPABLE_WATCHPOINT && STOPPED_BY_WATCHPOINT (ecs->ws))
     {
+      CORE_ADDR addr = 0;
+
       if (debug_infrun)
 	fprintf_unfiltered (gdb_stdlog, "infrun: STOPPED_BY_WATCHPOINT\n");
-      resume (1, 0);
+
+      target_stopped_data_address (&current_target, &addr);
+      mark_triggered_watchpoints (addr);
+      registers_changed ();
+      target_resume (ecs->ptid, 1, TARGET_SIGNAL_0);	/* Single step */
+
+      ecs->waiton_ptid = ecs->ptid;
+      ecs->wp = &(ecs->ws);
+      ecs->infwait_state = infwait_nonstep_watch_state;
       prepare_to_wait (ecs);
       return;
     }
@@ -1797,6 +1807,8 @@ handle_inferior_event (struct execution_
   if (gdbarch_have_nonsteppable_watchpoint (current_gdbarch)
       && STOPPED_BY_WATCHPOINT (ecs->ws))
     {
+      CORE_ADDR addr = 0;
+
       /* At this point, we are stopped at an instruction which has
          attempted to write to a piece of memory under control of
          a watchpoint.  The instruction hasn't actually executed
@@ -1804,15 +1816,12 @@ handle_inferior_event (struct execution_
          now, we would get the old value, and therefore no change
          would seem to have occurred.
 
-         In order to make watchpoints work `right', we really need
-         to complete the memory write, and then evaluate the
-         watchpoint expression.  The following code does that by
-         removing the watchpoint (actually, all watchpoints and
-         breakpoints), single-stepping the target, re-inserting
-         watchpoints, and then falling through to let normal
-         single-step processing handle proceed.  Since this
-         includes evaluating watchpoints, things will come to a
-         stop in the correct manner.  */
+         In order to make watchpoints work `right', we mark the
+	 triggered watchpoints so that after we single step,
+	 we will check for a value change.  */
+
+      target_stopped_data_address (&current_target, &addr);
+      mark_triggered_watchpoints (addr);
 
       if (debug_infrun)
 	fprintf_unfiltered (gdb_stdlog, "infrun: STOPPED_BY_WATCHPOINT\n");
@@ -1883,6 +1892,41 @@ handle_inferior_event (struct execution_
 	}
     }
 
+  if (stop_signal == TARGET_SIGNAL_TRAP
+      && trap_expected
+      && gdbarch_single_step_through_delay_p (current_gdbarch)
+      && currently_stepping (ecs))
+    {
+      /* We're trying to step of a breakpoint.  Turns out that we're
+	 also on an instruction that needs to be stepped multiple
+	 times before it's been fully executing. E.g., architectures
+	 with a delay slot.  It needs to be stepped twice, once for
+	 the instruction and once for the delay slot.  */
+      int step_through_delay
+	= gdbarch_single_step_through_delay (current_gdbarch,
+					     get_current_frame ());
+      if (debug_infrun && step_through_delay)
+	fprintf_unfiltered (gdb_stdlog, "infrun: step through delay\n");
+      if (step_range_end == 0 && step_through_delay)
+	{
+	  /* The user issued a continue when stopped at a breakpoint.
+	     Set up for another trap and get out of here.  */
+         ecs->another_trap = 1;
+         keep_going (ecs);
+         return;
+	}
+      else if (step_through_delay)
+	{
+	  /* The user issued a step when stopped at a breakpoint.
+	     Maybe we should stop, maybe we should not - the delay
+	     slot *might* correspond to a line of source.  In any
+	     case, don't decide that here, just set ecs->another_trap,
+	     making sure we single-step again before breakpoints are
+	     re-inserted.  */
+	  ecs->another_trap = 1;
+	}
+    }
+
   /* Look at the cause of the stop, and decide what to do.
      The alternatives are:
      1) break; to really stop and return to the debugger,
@@ -1935,6 +1979,8 @@ handle_inferior_event (struct execution_
          See more comments in inferior.h.  */
       if (stop_soon == STOP_QUIETLY_NO_SIGSTOP)
 	{
+          if (debug_infrun)
+	    fprintf_unfiltered (gdb_stdlog, "infrun: quietly stopped\n");
 	  stop_stepping (ecs);
 	  if (stop_signal == TARGET_SIGNAL_STOP)
 	    stop_signal = TARGET_SIGNAL_0;
Index: gdb-6.7/gdb/breakpoint.c
===================================================================
--- gdb-6.7.orig/gdb/breakpoint.c	2007-08-30 00:07:47.000000000 +0200
+++ gdb-6.7/gdb/breakpoint.c	2007-10-13 04:50:11.000000000 +0200
@@ -806,6 +806,90 @@ insert_catchpoint (struct ui_out *uo, vo
     }
 }
 
+/* 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)
+	{
+	  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
@@ -1294,6 +1378,7 @@ remove_breakpoints (void)
 {
   struct bp_location *b;
   int val;
+  int return_val = 0;
 
   ALL_BP_LOCATIONS (b)
   {
@@ -1301,10 +1386,10 @@ remove_breakpoints (void)
       {
 	val = remove_breakpoint (b, mark_uninserted);
 	if (val != 0)
-	  return val;
+	  return_val = val;
       }
   }
-  return 0;
+  return return_val;
 }
 
 int
@@ -2187,8 +2272,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;
@@ -2636,6 +2726,54 @@ which its expression is valid.\n");     
     }
 }
 
+/* Check watchpoints for a match with a stopped data address.
+  
+   STOPPED_DATA_ADDRESS is the address of a triggered watchpoint.
+   A match with an existing watchpoint will cause that watchpoint
+   to be marked as triggered.
+
+   This function is only used for platforms where a watchpoint
+   triggers prior to the data being accessed.  */
+
+void
+mark_triggered_watchpoints (CORE_ADDR stopped_data_address)
+{
+  struct breakpoint *b, *temp;
+  CORE_ADDR addr = stopped_data_address;
+  struct value *v;
+  
+  ALL_BREAKPOINTS_SAFE (b, temp)
+  {
+    if (b->type == bp_hardware_watchpoint
+	|| b->type == bp_read_watchpoint
+	|| b->type == bp_access_watchpoint)
+      {
+	for (v = b->val_chain; v; v = v->next)
+	  {
+	    if (VALUE_LVAL (v) == lval_memory
+	        && ! VALUE_LAZY (v))
+	      {
+	        struct type *vtype = check_typedef (VALUE_TYPE (v));
+		    
+		if (v == b->val_chain
+		    || (TYPE_CODE (vtype) != TYPE_CODE_STRUCT
+		    && TYPE_CODE (vtype) != TYPE_CODE_ARRAY))
+		  {
+		    CORE_ADDR vaddr;
+			
+		    vaddr = VALUE_ADDRESS (v) + VALUE_OFFSET (v);
+		    /* Exact match not required.  Within range is
+		       sufficient.  */
+		    if (addr >= vaddr &&
+		        addr < vaddr + TYPE_LENGTH (VALUE_TYPE (v)))
+		      b->watchpoint_triggered = 1;
+		  }
+	      }
+	  }
+      }
+  }
+}
+
 /* Get a bpstat associated with having just stopped at address
    BP_ADDR in thread PTID.  STOPPED_BY_WATCHPOINT is 1 if the
    target thinks we stopped due to a hardware watchpoint, 0 if we
@@ -2766,82 +2904,61 @@ bpstat_stop_status (CORE_ADDR bp_addr, p
     bs->stop = 1;
     bs->print = 1;
 
-    if (b->type == bp_watchpoint ||
-	b->type == bp_hardware_watchpoint)
-      {
-	char *message = xstrprintf ("Error evaluating expression for watchpoint %d\n",
-				    b->number);
-	struct cleanup *cleanups = make_cleanup (xfree, message);
-	int e = catch_errors (watchpoint_check, bs, message, 
-			      RETURN_MASK_ALL);
-	do_cleanups (cleanups);
-	switch (e)
-	  {
-	  case WP_DELETED:
-	    /* We've already printed what needs to be printed.  */
-	    /* Actually this is superfluous, because by the time we
-               call print_it_typical() the wp will be already deleted,
-               and the function will return immediately. */
-	    bs->print_it = print_it_done;
-	    /* Stop.  */
-	    break;
-	  case WP_VALUE_CHANGED:
-	    /* Stop.  */
-	    ++(b->hit_count);
-	    break;
-	  case WP_VALUE_NOT_CHANGED:
-	    /* Don't stop.  */
-	    bs->print_it = print_it_noop;
-	    bs->stop = 0;
-	    continue;
-	  default:
-	    /* Can't happen.  */
-	    /* FALLTHROUGH */
-	  case 0:
-	    /* Error from catch_errors.  */
-	    printf_filtered (_("Watchpoint %d deleted.\n"), b->number);
-	    if (b->related_breakpoint)
-	      b->related_breakpoint->disposition = disp_del_at_next_stop;
-	    b->disposition = disp_del_at_next_stop;
-	    /* We've already printed what needs to be printed.  */
-	    bs->print_it = print_it_done;
-
-	    /* Stop.  */
-	    break;
-	  }
-      }
-    else if (b->type == bp_read_watchpoint || 
-	     b->type == bp_access_watchpoint)
+    if (b->type == bp_watchpoint
+	     || b->type == bp_read_watchpoint 
+	     || b->type == bp_access_watchpoint
+	     || b->type == bp_hardware_watchpoint)
       {
 	CORE_ADDR addr;
 	struct value *v;
-	int found = 0;
+	int must_check_value = 0;
 
-	if (!target_stopped_data_address (&current_target, &addr))
-	  continue;
-	for (v = b->val_chain; v; v = value_next (v))
+ 	if (b->type == bp_watchpoint
+	    || b->watchpoint_triggered
+	    || (b->type == bp_hardware_watchpoint
+		&& !target_stopped_data_address_p (&current_target)))
 	  {
-	    if (VALUE_LVAL (v) == lval_memory
-		&& ! value_lazy (v))
+	    /* We either have a software watchpoint, a triggered watchpoint 
+	       which we have stepped over, or we cannot ascertain what data 
+	       address causes a write watchpoint.  In all these
+	       cases, we must check the watchpoint value.  */
+	    b->watchpoint_triggered = 0;
+	    must_check_value = 1;
+	  }
+	else
+	  {
+	    /* At this point, we know target_stopped_data_address () works or 
+	       we have a read or access watchpoint and have no alternatives.  */
+	    if (!target_stopped_data_address (&current_target, &addr))
 	      {
-		struct type *vtype = check_typedef (value_type (v));
-
-		if (v == b->val_chain
-		    || (TYPE_CODE (vtype) != TYPE_CODE_STRUCT
-			&& TYPE_CODE (vtype) != TYPE_CODE_ARRAY))
+		bs->print_it = print_it_noop;
+		bs->stop = 0;
+		continue;
+	      }
+	    for (v = b->val_chain; v; v = v->next)
+	      {
+		if (VALUE_LVAL (v) == lval_memory
+		    && ! VALUE_LAZY (v))
 		  {
-		    CORE_ADDR vaddr;
-
-		    vaddr = VALUE_ADDRESS (v) + value_offset (v);
-		    /* Exact match not required.  Within range is
-                       sufficient.  */
-		    if (addr >= vaddr &&
-			addr < vaddr + TYPE_LENGTH (value_type (v)))
-		      found = 1;
+		    struct type *vtype = check_typedef (VALUE_TYPE (v));
+		    
+		    if (v == b->val_chain
+			|| (TYPE_CODE (vtype) != TYPE_CODE_STRUCT
+			    && TYPE_CODE (vtype) != TYPE_CODE_ARRAY))
+		      {
+			CORE_ADDR vaddr;
+			
+			vaddr = VALUE_ADDRESS (v) + VALUE_OFFSET (v);
+			/* Exact match not required.  Within range is
+			   sufficient.  */
+			if (addr >= vaddr &&
+			    addr < vaddr + TYPE_LENGTH (VALUE_TYPE (v)))
+			  must_check_value = 1;
+		      }
 		  }
 	      }
 	  }
-	if (found)
+ 	if (must_check_value)
 	  {
 	    char *message = xstrprintf ("Error evaluating expression for watchpoint %d\n",
 					b->number);
@@ -2870,6 +2987,15 @@ bpstat_stop_status (CORE_ADDR bp_addr, p
 		break;
 	      case WP_VALUE_NOT_CHANGED:
 		/* Stop.  */
+		if (b->type == bp_hardware_watchpoint
+		    || b->type == bp_watchpoint)
+		  {
+		    /* Don't stop: write watchpoints shouldn't fire if
+		       the value hasn't changed.  */
+		    bs->print_it = print_it_noop;
+		    bs->stop = 0;
+		    continue;
+		  }
 		++(b->hit_count);
 		break;
 	      default:
@@ -2885,7 +3011,7 @@ bpstat_stop_status (CORE_ADDR bp_addr, p
 		break;
 	      }
 	  }
-	else	/* found == 0 */
+	else	/* must_check_value == 0 */
 	  {
 	    /* This is a case where some watchpoint(s) triggered,
 	       but not at the address of this watchpoint (FOUND
@@ -4186,6 +4312,7 @@ set_raw_breakpoint (struct symtab_and_li
   b->exec_pathname = NULL;
   b->ops = NULL;
   b->pending = 0;
+  b->watchpoint_triggered = 0;
 
   /* Add this breakpoint to the end of the chain
      so that a list of breakpoints will come out in order
Index: gdb-6.7/gdb/breakpoint.h
===================================================================
--- gdb-6.7.orig/gdb/breakpoint.h	2007-08-23 20:08:26.000000000 +0200
+++ gdb-6.7/gdb/breakpoint.h	2007-10-13 04:50:11.000000000 +0200
@@ -420,6 +420,11 @@ struct breakpoint
 
     /* Is breakpoint pending on shlib loads?  */
     int pending;
+
+    /* Has a watchpoint been triggered?  This is only used for 
+       non-continuable watchpoints which trigger prior to the data
+       being modified.  */
+    int watchpoint_triggered;
   };
 
 /* The following stuff is an abstract data type "bpstat" ("breakpoint
@@ -688,6 +693,14 @@ 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 void mark_triggered_watchpoints (CORE_ADDR);
+
 extern int remove_breakpoints (void);
 
 /* This function can be used to physically insert eventpoints from the
Index: gdb-6.7/gdb/linux-nat.c
===================================================================
--- gdb-6.7.orig/gdb/linux-nat.c	2007-10-12 22:35:58.000000000 +0200
+++ gdb-6.7/gdb/linux-nat.c	2007-10-13 04:50:11.000000000 +0200
@@ -34,6 +34,7 @@
 #include "gdbthread.h"
 #include "gdbcmd.h"
 #include "regcache.h"
+#include "observer.h"
 #include "regset.h"
 #include "inf-ptrace.h"
 #include "auxv.h"
@@ -704,6 +705,9 @@ delete_lwp (ptid_t ptid)
   else
     lwp_list = lp->next;
 
+  if (lp->saved_trap_data)
+    xfree (lp->saved_trap_data);
+
   xfree (lp);
 }
 
@@ -1501,6 +1505,13 @@ stop_wait_callback (struct lwp_info *lp,
 	         user will delete or disable the breakpoint, but the
 	         thread will have already tripped on it.  */
 
+              /* Notify any observers that we have a SIGTRAP.
+                 This is needed on platforms that must save more state
+                 than just the trap.  For example, ia64 linux uses
+                 siginfo to determine if a watchpoint has occurred and
+                 this information gets trashed by a SIGSTOP.  */
+              observer_notify_sigtrap (lp);
+
 	      /* Now resume this LWP and get the SIGSTOP event. */
 	      errno = 0;
 	      ptrace (PTRACE_CONT, GET_LWP (lp->ptid), 0, 0);
@@ -2061,6 +2072,14 @@ retry:
 				 target_pid_to_str (lp->ptid));
 	    }
 
+          /* For platforms such as ia64, a hardware watchpoint is
+             determined by looking at special information available
+	     at the time time of the trap (siginfo).  This information
+	     is not preserved if we choose to take an event on another
+	     thread and later come back to this event, thus we must
+	     notify an observer so the information can be stored.  */
+          observer_notify_sigtrap (lp);   
+
 	  /* Handle GNU/Linux's extended waitstatus for trace events.  */
 	  if (WIFSTOPPED (status) && WSTOPSIG (status) == SIGTRAP && status >> 16 != 0)
 	    {
Index: gdb-6.7/gdb/linux-nat.h
===================================================================
--- gdb-6.7.orig/gdb/linux-nat.h	2007-10-12 22:35:58.000000000 +0200
+++ gdb-6.7/gdb/linux-nat.h	2007-10-13 04:50:11.000000000 +0200
@@ -61,6 +61,18 @@ struct lwp_info
 
   /* Next LWP in list.  */
   struct lwp_info *next;
+
+  /* Optional saved trap state for when a trap gets pushed back
+     due to multiple events occurring at the same time.  */
+  void *saved_trap_data;
+};
+
+/* Watchpoint description.  */
+struct linux_watchpoint
+{
+  CORE_ADDR addr;
+  int len;
+  int type;
 };
 
 /* Attempt to initialize libthread_db.  */
Index: gdb-6.7/gdb/Makefile.in
===================================================================
--- gdb-6.7.orig/gdb/Makefile.in	2007-09-05 02:14:02.000000000 +0200
+++ gdb-6.7/gdb/Makefile.in	2007-10-13 04:50:53.000000000 +0200
@@ -2160,7 +2160,7 @@ i387-tdep.o: i387-tdep.c $(defs_h) $(dou
 	$(gdb_assert_h) $(gdb_string_h) $(i386_tdep_h) $(i387_tdep_h)
 ia64-linux-nat.o: ia64-linux-nat.c $(defs_h) $(gdb_string_h) $(inferior_h) \
 	$(target_h) $(gdbcore_h) $(regcache_h) $(ia64_tdep_h) $(gdb_wait_h) \
-	$(gregset_h) $(linux_nat_h)
+	$(gregset_h) $(observer_h) $(linux_nat_h)
 ia64-linux-tdep.o: ia64-linux-tdep.c $(defs_h) $(ia64_tdep_h) \
 	$(arch_utils_h) $(gdbcore_h) $(regcache_h) $(osabi_h) $(solib_svr4_h) \
 	$(symtab_h)
@@ -2541,7 +2541,7 @@ rs6000-tdep.o: rs6000-tdep.c $(defs_h) $
 rs6000-aix-tdep.o: rs6000-aix-tdep.c $(defs_h) $(gdb_string_h) $(osabi_h) \
 	$(regcache_h) $(regset_h) $(rs6000_tdep_h) $(ppc_tdep_h)
 s390-nat.o: s390-nat.c $(defs_h) $(regcache_h) $(inferior_h) \
-	$(s390_tdep_h) $(target_h) $(linux_nat_h)
+	$(s390_tdep_h) $(target_h) $(linux_nat_h) $(observer_h)
 s390-tdep.o: s390-tdep.c $(defs_h) $(arch_utils_h) $(frame_h) $(inferior_h) \
 	$(symtab_h) $(target_h) $(gdbcore_h) $(gdbcmd_h) $(objfiles_h) \
 	$(floatformat_h) $(regcache_h) $(trad_frame_h) $(frame_base_h) \
Index: gdb-6.7/gdb/linux-thread-db.c
===================================================================
--- gdb-6.7.orig/gdb/linux-thread-db.c	2007-08-23 20:08:35.000000000 +0200
+++ gdb-6.7/gdb/linux-thread-db.c	2007-10-13 04:53:59.000000000 +0200
@@ -34,6 +34,7 @@
 #include "target.h"
 #include "regcache.h"
 #include "solib-svr4.h"
+#include "observer.h"
 #include "gdbcore.h"
 #include "observer.h"
 #include "linux-nat.h"
@@ -673,6 +674,7 @@ attach_thread (ptid_t ptid, const td_thr
 {
   struct thread_info *tp;
   td_err_e err;
+  ptid_t new_ptid;
 
   /* If we're being called after a TD_CREATE event, we may already
      know about this thread.  There are two ways this can happen.  We
@@ -700,8 +702,10 @@ attach_thread (ptid_t ptid, const td_thr
   if (ti_p->ti_state == TD_THR_UNKNOWN || ti_p->ti_state == TD_THR_ZOMBIE)
     return;			/* A zombie thread -- do not attach.  */
 
+  new_ptid = BUILD_LWP (ti_p->ti_lid, GET_PID (ptid));
+
   /* Under GNU/Linux, we have to attach to each and every thread.  */
-  if (lin_lwp_attach_lwp (BUILD_LWP (ti_p->ti_lid, GET_PID (ptid)), 0) < 0)
+  if (lin_lwp_attach_lwp (new_ptid, 0) < 0)
     return;
 
   /* Add the thread to GDB's thread list.  */
@@ -712,6 +716,11 @@ attach_thread (ptid_t ptid, const td_thr
   if (verbose)
     printf_unfiltered (_("[New %s]\n"), target_pid_to_str (ptid));
 
+  /* Notify any observers of a new linux thread.  This
+     would include any linux platforms that have to insert hardware
+     watchpoints on every thread.  */
+  observer_notify_linux_new_thread (new_ptid);
+
   /* Enable thread event reporting for this thread.  */
   err = td_thr_event_enable_p (th_p, 1);
   if (err != TD_OK)
@@ -891,7 +900,8 @@ thread_db_wait (ptid_t ptid, struct targ
     thread_db_find_new_threads ();
 
   if (ourstatus->kind == TARGET_WAITKIND_STOPPED
-      && ourstatus->value.sig == TARGET_SIGNAL_TRAP)
+      && (ourstatus->value.sig == TARGET_SIGNAL_TRAP
+          || ourstatus->value.sig == TARGET_SIGNAL_ILL))
     /* Check for a thread event.  */
     check_event (ptid);
 
Index: gdb-6.7/gdb/i386-linux-nat.c
===================================================================
--- gdb-6.7.orig/gdb/i386-linux-nat.c	2007-08-23 20:08:34.000000000 +0200
+++ gdb-6.7/gdb/i386-linux-nat.c	2007-10-13 04:50:11.000000000 +0200
@@ -585,10 +585,9 @@ i386_linux_dr_get (int regnum)
   int tid;
   unsigned long value;
 
-  /* FIXME: kettenis/2001-01-29: It's not clear what we should do with
-     multi-threaded processes here.  For now, pretend there is just
-     one thread.  */
-  tid = PIDGET (inferior_ptid);
+  tid = TIDGET (inferior_ptid);
+  if (tid == 0)
+    tid = PIDGET (inferior_ptid);
 
   /* FIXME: kettenis/2001-03-27: Calling perror_with_name if the
      ptrace call fails breaks debugging remote targets.  The correct
@@ -613,10 +612,9 @@ i386_linux_dr_set (int regnum, unsigned 
 {
   int tid;
 
-  /* FIXME: kettenis/2001-01-29: It's not clear what we should do with
-     multi-threaded processes here.  For now, pretend there is just
-     one thread.  */
-  tid = PIDGET (inferior_ptid);
+  tid = TIDGET (inferior_ptid);
+  if (tid == 0)
+    tid = PIDGET (inferior_ptid);
 
   errno = 0;
   ptrace (PTRACE_POKEUSER, tid,
Index: gdb-6.7/gdb/ia64-linux-nat.c
===================================================================
--- gdb-6.7.orig/gdb/ia64-linux-nat.c	2007-08-23 20:08:35.000000000 +0200
+++ gdb-6.7/gdb/ia64-linux-nat.c	2007-10-13 05:07:58.000000000 +0200
@@ -27,6 +27,7 @@
 #include "regcache.h"
 #include "ia64-tdep.h"
 #include "linux-nat.h"
+#include "observer.h"
 
 #include <signal.h>
 #include <sys/ptrace.h>
@@ -550,10 +551,10 @@ is_power_of_2 (int val)
   return onecount <= 1;
 }
 
+/* Internal routine to insert one watchpoint for a specified thread.  */
 static int
-ia64_linux_insert_watchpoint (CORE_ADDR addr, int len, int rw)
+ia64_linux_insert_one_watchpoint (ptid_t ptid, CORE_ADDR addr, int len, int rw)
 {
-  ptid_t ptid = inferior_ptid;
   int idx;
   long dbr_addr, dbr_mask;
   int max_watchpoints = 4;
@@ -598,10 +599,39 @@ ia64_linux_insert_watchpoint (CORE_ADDR 
   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_remove_watchpoint (CORE_ADDR addr, int len, int type)
+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.  */
+static int
+ia64_linux_insert_watchpoint (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 type)
 {
-  ptid_t ptid = inferior_ptid;
   int idx;
   long dbr_addr, dbr_mask;
   int max_watchpoints = 4;
@@ -623,13 +653,55 @@ ia64_linux_remove_watchpoint (CORE_ADDR 
   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.  */
+static int
+ia64_linux_remove_watchpoint (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;
+}
+
+/* Callback to find lwp_info struct for a given lwp.  */
+static int
+find_lwp_info (struct lwp_info *lp, void *data)
+{ 
+  int lwp = *(int *)data;
+    
+  if (lwp == TIDGET (lp->ptid))
+    return 1;
+
+  return 0;
+}
+
 static int
 ia64_linux_stopped_data_address (struct target_ops *ops, CORE_ADDR *addr_p)
 {
   CORE_ADDR psr;
   int tid;
   struct siginfo siginfo;
+  struct siginfo *siginfo_p;
   ptid_t ptid = inferior_ptid;
+  struct lwp_info *lp;
   struct regcache *regcache = get_current_regcache ();
 
   tid = TIDGET(ptid);
@@ -637,10 +709,19 @@ ia64_linux_stopped_data_address (struct 
     tid = PIDGET (ptid);
   
   errno = 0;
-  ptrace (PTRACE_GETSIGINFO, tid, (PTRACE_TYPE_ARG3) 0, &siginfo);
+  /* Check to see if we have already cached the siginfo for this
+     event.  */
+  lp = iterate_over_lwps (find_lwp_info, &tid);
+  if (lp && lp->saved_trap_data != NULL)
+    siginfo_p = (struct siginfo *)lp->saved_trap_data;
+  else
+    {
+      siginfo_p = &siginfo;
+      ptrace (PTRACE_GETSIGINFO, tid, (PTRACE_TYPE_ARG3) 0, siginfo_p);
+    }
 
-  if (errno != 0 || siginfo.si_signo != SIGTRAP || 
-      (siginfo.si_code & 0xffff) != 0x0004 /* TRAP_HWBKPT */)
+  if (errno != 0 || siginfo_p->si_signo != SIGTRAP || 
+      (siginfo_p->si_code & 0xffff) != 0x0004 /* TRAP_HWBKPT */)
     return 0;
 
   regcache_cooked_read_unsigned (regcache, IA64_PSR_REGNUM, &psr);
@@ -648,7 +729,7 @@ ia64_linux_stopped_data_address (struct 
                            for the next instruction */
   regcache_cooked_write_unsigned (regcache, IA64_PSR_REGNUM, psr);
 
-  *addr_p = (CORE_ADDR)siginfo.si_addr;
+  *addr_p = (CORE_ADDR)siginfo_p->si_addr;
   return 1;
 }
 
@@ -796,6 +877,31 @@ ia64_linux_xfer_partial (struct target_o
 			     offset, len);
 }
 
+/* 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_one_watchpoint);
+}
+
+/* For ia64 linux, we must save the siginfo data as part of the state
+   of a queued SIGTRAP.  This is because siginfo is used to determine
+   if a watchpoint has occurred and the information will be lost if
+   a SIGSTOP is issued to the thread.  */
+void
+ia64_linux_save_sigtrap_info (void *queue_data)
+{
+  struct lwp_info *lp = (struct lwp_info *)queue_data;
+
+  if (lp->saved_trap_data == NULL)
+    lp->saved_trap_data = xmalloc (sizeof(struct siginfo));
+
+  ptrace (PTRACE_GETSIGINFO, ptid_get_lwp (lp->ptid), (PTRACE_ARG3_TYPE) 0,
+          lp->saved_trap_data);
+}
+
 void _initialize_ia64_linux_nat (void);
 
 void
@@ -834,4 +940,7 @@ _initialize_ia64_linux_nat (void)
 
   /* Register the target.  */
   linux_nat_add_target (t);
+
+  observer_attach_linux_new_thread (ia64_linux_new_thread);
+  observer_attach_sigtrap (ia64_linux_save_sigtrap_info);
 }
Index: gdb-6.7/gdb/amd64-linux-nat.c
===================================================================
--- gdb-6.7.orig/gdb/amd64-linux-nat.c	2007-08-23 20:08:26.000000000 +0200
+++ gdb-6.7/gdb/amd64-linux-nat.c	2007-10-13 04:50:11.000000000 +0200
@@ -240,10 +240,9 @@ amd64_linux_dr_get (int regnum)
   int tid;
   unsigned long value;
 
-  /* FIXME: kettenis/2001-01-29: It's not clear what we should do with
-     multi-threaded processes here.  For now, pretend there is just
-     one thread.  */
-  tid = PIDGET (inferior_ptid);
+  tid = TIDGET (inferior_ptid);
+  if (tid == 0)
+    tid = PIDGET (inferior_ptid);
 
   /* FIXME: kettenis/2001-03-27: Calling perror_with_name if the
      ptrace call fails breaks debugging remote targets.  The correct
@@ -268,10 +267,9 @@ amd64_linux_dr_set (int regnum, unsigned
 {
   int tid;
 
-  /* FIXME: kettenis/2001-01-29: It's not clear what we should do with
-     multi-threaded processes here.  For now, pretend there is just
-     one thread.  */
-  tid = PIDGET (inferior_ptid);
+  tid = TIDGET (inferior_ptid);
+  if (tid == 0)
+    tid = PIDGET (inferior_ptid);
 
   errno = 0;
   ptrace (PT_WRITE_U, tid, offsetof (struct user, u_debugreg[regnum]), value);
Index: gdb-6.7/gdb/s390-nat.c
===================================================================
--- gdb-6.7.orig/gdb/s390-nat.c	2007-08-23 20:08:37.000000000 +0200
+++ gdb-6.7/gdb/s390-nat.c	2007-10-13 04:50:11.000000000 +0200
@@ -27,6 +27,7 @@
 #include "linux-nat.h"
 
 #include "s390-tdep.h"
+#include "observer.h"
 
 #include <asm/ptrace.h>
 #include <sys/ptrace.h>
@@ -111,14 +112,14 @@ fill_fpregset (const struct regcache *re
 			      (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.  */
+    tid = PIDGET (ptid); /* Not a threaded program.  */
 
   return tid;
 }
@@ -202,7 +203,7 @@ store_fpregs (const struct regcache *reg
 static void
 s390_linux_fetch_inferior_registers (struct regcache *regcache, int regnum)
 {
-  int tid = s390_inferior_tid ();
+  int tid = s390_tid (inferior_ptid);
 
   if (regnum == -1 
       || (regnum < S390_NUM_REGS && regmap_gregset[regnum] != -1))
@@ -218,7 +219,7 @@ s390_linux_fetch_inferior_registers (str
 static void
 s390_linux_store_inferior_registers (struct regcache *regcache, int regnum)
 {
-  int tid = s390_inferior_tid ();
+  int tid = s390_tid (inferior_ptid);
 
   if (regnum == -1 
       || (regnum < S390_NUM_REGS && regmap_gregset[regnum] != -1))
@@ -260,7 +261,7 @@ s390_stopped_by_watchpoint (void)
   parea.len = sizeof (per_lowcore);
   parea.process_addr = (addr_t) & per_lowcore;
   parea.kernel_addr = offsetof (struct user_regs_struct, per_info.lowcore);
-  if (ptrace (PTRACE_PEEKUSR_AREA, s390_inferior_tid (), &parea) < 0)
+  if (ptrace (PTRACE_PEEKUSR_AREA, s390_tid (inferior_ptid), &parea) < 0)
     perror_with_name (_("Couldn't retrieve watchpoint status"));
 
   return per_lowcore.perc_storage_alteration == 1
@@ -268,9 +269,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;
@@ -307,6 +308,16 @@ s390_fix_watch_points (void)
     perror_with_name (_("Couldn't modify watchpoint status"));
 }
 
+/* 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)
+{
+  s390_fix_watch_points (lwp->ptid);
+  return 0;
+}
+
+/* Insert a specified watchpoint on all threads.  */
 static int
 s390_insert_watchpoint (CORE_ADDR addr, int len, int type)
 {
@@ -320,10 +331,24 @@ s390_insert_watchpoint (CORE_ADDR addr, 
   area->next = watch_base;
   watch_base = area;
 
-  s390_fix_watch_points ();
+  /* For the S390, a watchpoint must be inserted/removed for each
+     thread so we iterate over the list of existing lwps.  */
+  if (iterate_over_lwps (&s390_insert_watchpoint_callback, NULL))
+    return -1;
+
   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)
+{
+  s390_fix_watch_points (lwp->ptid);
+  return 0;
+}
+
+/* Remove a specified watchpoint from all threads.  */
 static int
 s390_remove_watchpoint (CORE_ADDR addr, int len, int type)
 {
@@ -345,7 +370,11 @@ s390_remove_watchpoint (CORE_ADDR addr, 
   *parea = area->next;
   xfree (area);
 
-  s390_fix_watch_points ();
+  /* For the S390, a watchpoint must be inserted/removed for each
+     thread so we iterate over the list of existing lwps.  */
+  if (iterate_over_lwps (&s390_remove_watchpoint_callback, NULL))
+    return -1;
+
   return 0;
 }
 
@@ -361,6 +390,15 @@ s390_region_ok_for_hw_watchpoint (CORE_A
   return 1;
 }
 
+/* New thread observer that inserts all existing watchpoints on the
+   new thread.  */
+static void
+s390_linux_new_thread (ptid_t ptid)
+{
+  /* Add existing watchpoints to new thread.  */
+  s390_fix_watch_points (ptid);
+}
+
 
 void _initialize_s390_nat (void);
 
@@ -386,4 +424,6 @@ _initialize_s390_nat (void)
 
   /* Register the target.  */
   linux_nat_add_target (t);
+
+  observer_attach_linux_new_thread (s390_linux_new_thread);
 }