public inbox for gdb-patches@sourceware.org
 help / color / mirror / Atom feed
* [RFA] Implement support for PowerPC BookE masked watchpoints
@ 2011-01-13 20:55 Thiago Jung Bauermann
  2011-01-31 20:09 ` Thiago Jung Bauermann
  2011-02-17 15:10 ` Ulrich Weigand
  0 siblings, 2 replies; 38+ messages in thread
From: Thiago Jung Bauermann @ 2011-01-13 20:55 UTC (permalink / raw)
  To: gdb-patches ml

Hi,

I'm almost done with the series adding suport for PowerPC BookE
features... There's only this patch adding masked watchpoints, and
another one adding ranged hardware breakpoints (to be posted later). So
please bear with me a little longer. :-)

The documentation part of the patch was already reviewed and approved.
No regressions on ppc-linux, ppc64-linux or i386-linux. Ok to commit?

To ease review, here are the changes on parsing the command line in
watch_command_1, with a diff ignoring whitespace changes:

---- 8< ---- 8< ----

@@ -8219,64 +8463,93 @@ watch_command_1 (char *arg, int accessflag, int from_tty,
   int reg_cnt = 0;
   int thread = -1;
   int pc = 0;
+  /* Flag to indicate whether we are going to use masks for
+     the hardware watchpoint.  */
+  int use_mask = 0;
+  CORE_ADDR hw_wp_mask = 0;
 
   /* Make sure that we actually have parameters to parse.  */
   if (arg != NULL && arg[0] != '\0')
     {
-      toklen = strlen (arg); /* Size of argument list.  */
+      char *value_start;
 
-      /* Points tok to the end of the argument list.  */
-      tok = arg + toklen - 1;
-
-      /* Go backwards in the parameters list. Skip the last parameter.
-         If we're expecting a 'thread <thread_num>' parameter, this should
-         be the thread identifier.  */
+      /* Look for "parameter value" pairs at the end
+	 of the arguments string.  */
+      for (tok = arg + strlen (arg) - 1; tok > arg; tok--)
+	{
+	  /* Skip whitespace at the end of the argument list.  */
       while (tok > arg && (*tok == ' ' || *tok == '\t'))
         tok--;
+
+	  /* Find the beginning of the last token.
+	     This is the value of the parameter.  */
       while (tok > arg && (*tok != ' ' && *tok != '\t'))
         tok--;
+	  value_start = tok + 1;
 
-      /* Points end_tok to the beginning of the last token.  */
-      id_tok_start = tok + 1;
-
-      /* Go backwards in the parameters list. Skip one more parameter.
-         If we're expecting a 'thread <thread_num>' parameter, we should
-         reach a "thread" token.  */
+	  /* Skip whitespace.  */
       while (tok > arg && (*tok == ' ' || *tok == '\t'))
         tok--;
 
       end_tok = tok;
 
+	  /* Find the beginning of the second to last token.
+	     This is the parameter itself.  */
       while (tok > arg && (*tok != ' ' && *tok != '\t'))
         tok--;
-
-      /* Move the pointer forward to skip the whitespace and
-         calculate the length of the token.  */
       tok++;
-      toklen = end_tok - tok;
+	  toklen = end_tok - tok + 1;
 
-      if (toklen >= 1 && strncmp (tok, "thread", toklen) == 0)
+	  if (toklen == 6 && !strncmp (tok, "thread", 6))
         {
           /* At this point we've found a "thread" token, which means
              the user is trying to set a watchpoint that triggers
              only in a specific thread.  */
           char *endp;
 
+	      if (thread != -1)
+		error(_("You can specify only one thread."));
+
           /* Extract the thread ID from the next token.  */
-          thread = strtol (id_tok_start, &endp, 0);
+	      thread = strtol (value_start, &endp, 0);
 
           /* Check if the user provided a valid numeric value for the
              thread ID.  */
           if (*endp != ' ' && *endp != '\t' && *endp != '\0')
-            error (_("Invalid thread ID specification %s."), id_tok_start);
+		error (_("Invalid thread ID specification %s."), value_start);
 
           /* Check if the thread actually exists.  */
           if (!valid_thread_id (thread))
             error (_("Unknown thread %d."), thread);
+	    }
+	  else if (toklen == 4 && !strncmp (tok, "mask", 4))
+	    {
+	      /* We've found a "mask" token, which means the user wants to
+		 create a hardware watchpoint that is going to have the mask
+		 facility.  */
+	      struct value *mask_value, *mark;
+
+	      /* Does the target support masked watchpoints?  */
+	      if (!target_masked_watch_num_extra_regs () < 0)
+		error (_("\
+This target does not support the usage of masks with hardware watchpoints."));
 
-          /* Truncate the string and get rid of the thread <thread_num>
-             parameter before the parameter list is parsed by the
-             evaluate_expression() function.  */
+	      if (use_mask)
+		error(_("You can specify only one mask."));
+
+	      use_mask = 1;
+
+	      mark = value_mark ();
+	      mask_value = parse_to_comma_and_eval (&value_start);
+	      hw_wp_mask = value_as_address (mask_value);
+	      value_free_to_mark (mark);
+	    }
+	  else
+	    /* We didn't recognize what we found.  We should stop here.  */
+	    break;
+
+	  /* Truncate the string and get rid of the "parameter value" pair before
+	     the arguments string is parsed by the parse_exp_1 function.  */
           *tok = '\0';
         }
     }

---- >8 ---- >8 ----

-- 
[]'s
Thiago Jung Bauermann
IBM Linux Technology Center


2011-01-13  Sergio Durigan Junior  <sergiodj@linux.vnet.ibm.com>
	    Thiago Jung Bauermann  <bauerman@br.ibm.com>

	Implement support for PowerPC BookE masked watchpoints.

gdb/
	*NEWS: Mention masked watchpoint support.  Create "Changed commands"
	sections and populate it based on other NEWS items.
	* breakpoint.h (struct ui_out): New opaque declaration.
	(struct breakpoint_ops) <works_in_software_mode>,
	<print_one_detail>: New methods.  Initialize them to NULL in all
	existing breakpoint_ops instances.
	(struct breakpoint_ops) <print_it>: Add OLD_VAL parameter.  Update all
	implementations of the method.
	(struct breakpoint) <hw_wp_mask>: New field.
	* breakpoint.c (is_masked_watchpoint): Add prototype.
	(update_watchpoint): Call breakpoint's
	breakpoint_ops.works_in_software_mode if available.
	(watchpoints_triggered): Handle the case of a hardware masked
	watchpoint trigger.
	(watchpoint_check): Likewise.
	(print_one_breakpoint_location): Call breakpoint's
	breakpoint_ops.print_one_detail if available.
	(insert_masked_watchpoint, remove_masked_watchpoint)
	(resources_needed_masked_watchpoint)
	(works_in_software_mode_masked_watchpoint, print_it_masked_watchpoint)
	(print_one_detail_masked_watchpoint, print_mention_masked_watchpoint)
	(print_recreate_masked_watchpoint, is_masked_watchpoint): New
	functions.
	(masked_watchpoint_breakpoint_ops): New structure.
	(watch_command_1): Check for the existence of the `mask' parameter.
	Set b->ops according to the type of hardware watchpoint being created.
	* ppc-linux-nat.c (ppc_linux_insert_mask_watchpoint)
	(ppc_linux_remove_mask_watchpoint)
	(ppc_linux_masked_watch_num_registers): New functions.
	(_initialize_ppc_linux_nat): Initialize to_insert_mask_watchpoint,
	to_remove_mask_watchpoint and to_masked_watch_num_registers.
	* target.c (update_current_target): Mention to_insert_mask_watchpoint,
	to_remove_mask_watchpoint, and to_masked_watch_num_registers.
	(target_insert_mask_watchpoint, target_remove_mask_watchpoint)
	(target_masked_watch_num_registers): New functions.
	* target.h (struct target_ops) <to_insert_mask_watchpoint>,
	<to_remove_mask_watchpoint>, <to_masked_watch_num_registers>: New
	methods.
	(target_insert_mask_watchpoint, target_remove_mask_watchpoint)
	(target_masked_watch_num_registers): Add prototypes.

gdb/doc/
	* gdb.texinfo (Set Watchpoints): Document mask parameter.
	(PowerPC Embedded): Document masked watchpoints.


diff --git a/gdb/NEWS b/gdb/NEWS
index 9283e15..bf89a6d 100644
--- a/gdb/NEWS
+++ b/gdb/NEWS
@@ -112,6 +112,14 @@
   libthread_db library with the "set libthread-db-search-path"
   command.  See the user manual for more details on this command.
 
+* When locally debugging programs on PowerPC BookE processors running
+  a Linux kernel version 2.6.34 or later, GDB supports masked hardware
+  watchpoints, which specifiy a mask in addition to an address to watch.
+  The mask specifies that some bits of an address (the bits which are
+  reset in the mask) should be ignored when matching the address accessed
+  by the inferior against the watchpoint address.  See the "PowerPC Embedded"
+  section in the user manual for more details.
+
 * New features in the GDB remote stub, GDBserver
 
   ** GDBserver is now supported on PowerPC LynxOS (versions 4.x and 5.x),
@@ -134,6 +142,19 @@ Analog Devices, Inc. Blackfin Processor	bfin-*
 
   ** The --map-info flag lists all known core mappings.
 
+* Changed commands
+
+watch EXPRESSION mask MASK_VALUE
+  The watch command now supports the mask argument which allows creation
+  of masked watchpoints, if the current architecture supports this feature.
+
+watch -location EXPRESSION
+watch -l EXPRESSION
+  The "watch" command now accepts an optional "-location" argument.
+  When used, this causes GDB to watch the memory referred to by the
+  expression.  Such a watchpoint is never deleted due to it going out
+  of scope.
+
 *** Changes in GDB 7.2
 
 * Shared library support for remote targets by default
diff --git a/gdb/ada-lang.c b/gdb/ada-lang.c
index 890e091..2fda77f 100644
--- a/gdb/ada-lang.c
+++ b/gdb/ada-lang.c
@@ -10875,7 +10875,7 @@ print_recreate_exception (enum exception_catchpoint_kind ex,
 /* Virtual table for "catch exception" breakpoints.  */
 
 static enum print_stop_action
-print_it_catch_exception (struct breakpoint *b)
+print_it_catch_exception (struct breakpoint *b, const struct value *old_val)
 {
   return print_it_exception (ex_catch_exception, b);
 }
@@ -10904,8 +10904,10 @@ static struct breakpoint_ops catch_exception_breakpoint_ops =
   NULL, /* remove */
   NULL, /* breakpoint_hit */
   NULL, /* resources_needed */
+  NULL, /* works_in_software_mode */
   print_it_catch_exception,
   print_one_catch_exception,
+  NULL, /* print_one_detail */
   print_mention_catch_exception,
   print_recreate_catch_exception
 };
@@ -10913,7 +10915,8 @@ static struct breakpoint_ops catch_exception_breakpoint_ops =
 /* Virtual table for "catch exception unhandled" breakpoints.  */
 
 static enum print_stop_action
-print_it_catch_exception_unhandled (struct breakpoint *b)
+print_it_catch_exception_unhandled (struct breakpoint *b,
+				    const struct value *old_val)
 {
   return print_it_exception (ex_catch_exception_unhandled, b);
 }
@@ -10943,8 +10946,10 @@ static struct breakpoint_ops catch_exception_unhandled_breakpoint_ops = {
   NULL, /* remove */
   NULL, /* breakpoint_hit */
   NULL, /* resources_needed */
+  NULL, /* works_in_software_mode */
   print_it_catch_exception_unhandled,
   print_one_catch_exception_unhandled,
+  NULL, /* print_one_detail */
   print_mention_catch_exception_unhandled,
   print_recreate_catch_exception_unhandled
 };
@@ -10952,7 +10957,7 @@ static struct breakpoint_ops catch_exception_unhandled_breakpoint_ops = {
 /* Virtual table for "catch assert" breakpoints.  */
 
 static enum print_stop_action
-print_it_catch_assert (struct breakpoint *b)
+print_it_catch_assert (struct breakpoint *b, const struct value *old_val)
 {
   return print_it_exception (ex_catch_assert, b);
 }
@@ -10980,8 +10985,10 @@ static struct breakpoint_ops catch_assert_breakpoint_ops = {
   NULL, /* remove */
   NULL, /* breakpoint_hit */
   NULL, /* resources_needed */
+  NULL, /* works_in_software_mode */
   print_it_catch_assert,
   print_one_catch_assert,
+  NULL, /* print_one_detail */
   print_mention_catch_assert,
   print_recreate_catch_assert
 };
diff --git a/gdb/breakpoint.c b/gdb/breakpoint.c
index 8d0692b..7eef1b4 100644
--- a/gdb/breakpoint.c
+++ b/gdb/breakpoint.c
@@ -220,6 +220,8 @@ static void disable_trace_command (char *, int);
 
 static void trace_pass_command (char *, int);
 
+static int is_masked_watchpoint (const struct breakpoint *b);
+
 /* Assuming we're creating a static tracepoint, does S look like a
    static tracepoint marker spec ("-m MARKER_ID")?  */
 #define is_marker_spec(s)						\
@@ -1494,6 +1496,7 @@ update_watchpoint (struct breakpoint *b, int reparse)
 	    {
 	      int i, target_resources_ok, other_type_used;
 	      enum enable_state orig_enable_state;
+	      enum bptype orig_type;
 
 	      /* We need to determine how many resources are already
 		 used for all other hardware watchpoints plus this one
@@ -1502,6 +1505,7 @@ update_watchpoint (struct breakpoint *b, int reparse)
 		 hw_watchpoint_used_count call below counts this
 		 watchpoint, make sure that it is marked as a hardware
 		 watchpoint.  */
+	      orig_type = b->type;
 	      b->type = bp_hardware_watchpoint;
 
 	      /* hw_watchpoint_used_count ignores disabled watchpoints,
@@ -1518,10 +1522,26 @@ update_watchpoint (struct breakpoint *b, int reparse)
 	      target_resources_ok = target_can_use_hardware_watchpoint
 		    (bp_hardware_watchpoint, i, other_type_used);
 	      if (target_resources_ok <= 0)
-		b->type = bp_watchpoint;
+		{
+		  if (orig_type == bp_hardware_watchpoint
+		      && b->ops && b->ops->works_in_software_mode
+		      && !b->ops->works_in_software_mode (b))
+		    error (_("This watchpoint cannot be used "
+			     "in software mode."));
+		  else
+		    b->type = bp_watchpoint;
+		}
 	    }
 	  else
-	    b->type = bp_watchpoint;
+	    {
+	      if (b->type == bp_hardware_watchpoint
+		  && b->ops && b->ops->works_in_software_mode
+		  && !b->ops->works_in_software_mode (b))
+		error (_("This watchpoint cannot be used "
+			 "in software mode."));
+	      else
+		b->type = bp_watchpoint;
+	    }
 
 	  loc_type = (b->type == bp_watchpoint? bp_loc_other
 		      : bp_loc_hardware_watchpoint);
@@ -3500,7 +3520,7 @@ print_bp_stop_message (bpstat bs)
 	   print_it_typical.  */
 	/* FIXME: how breakpoint can ever be NULL here?  */
 	if (b != NULL && b->ops != NULL && b->ops->print_it != NULL)
-	  return b->ops->print_it (b);
+	  return b->ops->print_it (b, bs->old_val);
 	else
 	  return print_it_typical (bs);
       }
@@ -3636,15 +3656,30 @@ watchpoints_triggered (struct target_waitstatus *ws)
 
 	b->watchpoint_triggered = watch_triggered_no;
 	for (loc = b->loc; loc; loc = loc->next)
-	  /* Exact match not required.  Within range is
-	     sufficient.  */
-	  if (target_watchpoint_addr_within_range (&current_target,
-						   addr, loc->address,
-						   loc->length))
-	    {
-	      b->watchpoint_triggered = watch_triggered_yes;
-	      break;
-	    }
+	  {
+	    CORE_ADDR newaddr, start;
+
+	    if (is_masked_watchpoint (loc->owner))
+	      {
+		newaddr = addr & loc->owner->hw_wp_mask;
+		start = loc->address & loc->owner->hw_wp_mask;
+	      }
+	    else
+	      {
+		newaddr = addr;
+		start = loc->address;
+	      }
+
+	    /* Exact match not required.  Within range is
+	       sufficient.  */
+	    if (target_watchpoint_addr_within_range (&current_target,
+						     newaddr, start,
+						     loc->length))
+	      {
+		b->watchpoint_triggered = watch_triggered_yes;
+		break;
+	      }
+	  }
       }
 
   return 1;
@@ -3761,6 +3796,11 @@ watchpoint_check (void *p)
 	  b->val_valid = 1;
 	  return WP_VALUE_CHANGED;
 	}
+      else if (is_masked_watchpoint (b))
+	/* Since we don't know the exact trigger address (from
+	   stopped_data_address), just tell the user we've triggered
+	   a mask watchpoint.  */
+	return WP_VALUE_CHANGED;
       else
 	{
 	  /* Nothing changed.  */
@@ -4846,9 +4886,12 @@ print_one_breakpoint_location (struct breakpoint *b,
 	  ui_out_field_int (uiout, "task", b->task);
 	}
     }
-  
+
   ui_out_text (uiout, "\n");
-  
+
+  if (!part_of_multiple && b->ops && b->ops->print_one_detail)
+    b->ops->print_one_detail (b, uiout);
+
   if (!part_of_multiple && b->static_trace_marker_id)
     {
       gdb_assert (b->type == bp_static_tracepoint);
@@ -6050,7 +6093,7 @@ breakpoint_hit_catch_fork (struct breakpoint *b)
    catchpoints.  */
 
 static enum print_stop_action
-print_it_catch_fork (struct breakpoint *b)
+print_it_catch_fork (struct breakpoint *b, const struct value *old_val)
 {
   annotate_catchpoint (b->number);
   printf_filtered (_("\nCatchpoint %d (forked process %d), "),
@@ -6110,8 +6153,10 @@ static struct breakpoint_ops catch_fork_breakpoint_ops =
   remove_catch_fork,
   breakpoint_hit_catch_fork,
   NULL, /* resources_needed */
+  NULL, /* works_in_software_mode */
   print_it_catch_fork,
   print_one_catch_fork,
+  NULL, /* print_one_detail */
   print_mention_catch_fork,
   print_recreate_catch_fork
 };
@@ -6147,7 +6192,7 @@ breakpoint_hit_catch_vfork (struct breakpoint *b)
    catchpoints.  */
 
 static enum print_stop_action
-print_it_catch_vfork (struct breakpoint *b)
+print_it_catch_vfork (struct breakpoint *b, const struct value *old_val)
 {
   annotate_catchpoint (b->number);
   printf_filtered (_("\nCatchpoint %d (vforked process %d), "),
@@ -6206,8 +6251,10 @@ static struct breakpoint_ops catch_vfork_breakpoint_ops =
   remove_catch_vfork,
   breakpoint_hit_catch_vfork,
   NULL, /* resources_needed */
+  NULL, /* works_in_software_mode */
   print_it_catch_vfork,
   print_one_catch_vfork,
+  NULL, /* print_one_detail */
   print_mention_catch_vfork,
   print_recreate_catch_vfork
 };
@@ -6329,7 +6376,7 @@ breakpoint_hit_catch_syscall (struct breakpoint *b)
    catchpoints.  */
 
 static enum print_stop_action
-print_it_catch_syscall (struct breakpoint *b)
+print_it_catch_syscall (struct breakpoint *b, const struct value *old_val)
 {
   /* These are needed because we want to know in which state a
      syscall is.  It can be in the TARGET_WAITKIND_SYSCALL_ENTRY
@@ -6490,8 +6537,10 @@ static struct breakpoint_ops catch_syscall_breakpoint_ops =
   remove_catch_syscall,
   breakpoint_hit_catch_syscall,
   NULL, /* resources_needed */
+  NULL, /* works_in_software_mode */
   print_it_catch_syscall,
   print_one_catch_syscall,
+  NULL, /* print_one_detail */
   print_mention_catch_syscall,
   print_recreate_catch_syscall
 };
@@ -6593,7 +6642,7 @@ breakpoint_hit_catch_exec (struct breakpoint *b)
 }
 
 static enum print_stop_action
-print_it_catch_exec (struct breakpoint *b)
+print_it_catch_exec (struct breakpoint *b, const struct value *old_val)
 {
   annotate_catchpoint (b->number);
   printf_filtered (_("\nCatchpoint %d (exec'd %s), "), b->number,
@@ -6644,8 +6693,10 @@ static struct breakpoint_ops catch_exec_breakpoint_ops =
   remove_catch_exec,
   breakpoint_hit_catch_exec,
   NULL, /* resources_needed */
+  NULL, /* works_in_software_mode */
   print_it_catch_exec,
   print_one_catch_exec,
+  NULL, /* print_one_detail */
   print_mention_catch_exec,
   print_recreate_catch_exec
 };
@@ -8291,12 +8342,211 @@ static struct breakpoint_ops watchpoint_breakpoint_ops =
   remove_watchpoint,
   NULL, /* breakpoint_hit */
   resources_needed_watchpoint,
+  NULL, /* works_in_software_mode */
   NULL, /* print_it */
   NULL, /* print_one */
+  NULL, /* print_one_detail */
   NULL, /* print_mention */
   NULL  /* print_recreate */
 };
 
+/* Implement the "insert" breakpoint_ops method for
+   masked hardware watchpoints.  */
+
+static int
+insert_masked_watchpoint (struct bp_location *bl)
+{
+  return target_insert_mask_watchpoint (bl->address, bl->owner->hw_wp_mask,
+					bl->watchpoint_type);
+}
+
+/* Implement the "remove" breakpoint_ops method for
+   masked hardware watchpoints.  */
+
+static int
+remove_masked_watchpoint (struct bp_location *bl)
+{
+  return target_remove_mask_watchpoint (bl->address, bl->owner->hw_wp_mask,
+				        bl->watchpoint_type);
+}
+
+/* Implement the "resources_needed" breakpoint_ops method for
+   masked hardware watchpoints.  */
+
+static int
+resources_needed_masked_watchpoint (const struct bp_location *bl)
+{
+  return target_masked_watch_num_registers ();
+}
+
+/* Implement the "works_in_software_mode" breakpoint_ops method for
+   masked hardware watchpoints.  */
+
+static int
+works_in_software_mode_masked_watchpoint (const struct breakpoint *b)
+{
+  return 0;
+}
+
+/* Implement the "print_it" breakpoint_ops method for
+   masked hardware watchpoints.  */
+
+static enum print_stop_action
+print_it_masked_watchpoint (struct breakpoint *b,
+			    const struct value *old_val)
+{
+  struct ui_stream *stb;
+  struct cleanup *old_chain;
+
+  stb = ui_out_stream_new (uiout);
+  old_chain = make_cleanup_ui_out_stream_delete (stb);
+
+  switch (b->type)
+    {
+    case bp_hardware_watchpoint:
+      annotate_watchpoint (b->number);
+      if (ui_out_is_mi_like_p (uiout))
+	ui_out_field_string
+	  (uiout, "reason",
+	   async_reason_lookup (EXEC_ASYNC_WATCHPOINT_TRIGGER));
+      break;
+
+    case bp_read_watchpoint:
+      if (ui_out_is_mi_like_p (uiout))
+	ui_out_field_string
+	  (uiout, "reason",
+	   async_reason_lookup (EXEC_ASYNC_READ_WATCHPOINT_TRIGGER));
+      break;
+
+    case bp_access_watchpoint:
+      if (old_val != NULL)
+	annotate_watchpoint (b->number);
+      if (ui_out_is_mi_like_p (uiout))
+	ui_out_field_string
+	  (uiout, "reason",
+	   async_reason_lookup (EXEC_ASYNC_ACCESS_WATCHPOINT_TRIGGER));
+      break;
+    default:
+      internal_error (__FILE__, __LINE__,
+		      _("Invalid hardware watchpoint type."));
+    }
+
+  mention (b);
+  ui_out_text (uiout, _("\n\
+Check the underlying instruction at PC for the memory\n\
+address and value which triggered this watchpoint.\n"));
+  ui_out_text (uiout, "\n");
+
+  do_cleanups (old_chain);
+
+  /* More than one watchpoint may have been triggered.  */
+  return PRINT_UNKNOWN;
+}
+
+/* Implement the "print_one_detail" breakpoint_ops method for
+   masked hardware watchpoints.  */
+
+static void
+print_one_detail_masked_watchpoint (const struct breakpoint *b,
+				    struct ui_out *uiout)
+{
+  ui_out_text (uiout, "\tmask ");
+
+  /* I don't know whether it's possible to get here without a b->loc,
+     but we can handle the situation.  */
+  if (b->loc)
+    ui_out_field_core_addr (uiout, "mask", b->loc->gdbarch, b->hw_wp_mask);
+  else
+    ui_out_field_string (uiout, "mask", core_addr_to_string (b->hw_wp_mask));
+
+  ui_out_text (uiout, "\n");
+}
+
+/* Implement the "print_mention" breakpoint_ops method for
+   masked hardware watchpoints.  */
+
+static void
+print_mention_masked_watchpoint (struct breakpoint *b)
+{
+  struct cleanup *ui_out_chain;
+
+  switch (b->type)
+    {
+    case bp_hardware_watchpoint:
+      ui_out_text (uiout, "Masked hardware watchpoint ");
+      ui_out_chain = make_cleanup_ui_out_tuple_begin_end (uiout, "wpt");
+      break;
+    case bp_read_watchpoint:
+      ui_out_text (uiout, "Masked hardware read watchpoint ");
+      ui_out_chain = make_cleanup_ui_out_tuple_begin_end (uiout, "hw-rwpt");
+      break;
+    case bp_access_watchpoint:
+      ui_out_text (uiout, "Masked hardware access (read/write) watchpoint ");
+      ui_out_chain = make_cleanup_ui_out_tuple_begin_end (uiout, "hw-awpt");
+      break;
+    default:
+      internal_error (__FILE__, __LINE__,
+		      _("Invalid hardware watchpoint type."));
+    }
+
+  ui_out_field_int (uiout, "number", b->number);
+  ui_out_text (uiout, ": ");
+  ui_out_field_string (uiout, "exp", b->exp_string);
+  do_cleanups (ui_out_chain);
+}
+
+/* Implement the "print_recreate" breakpoint_ops method for
+   masked hardware watchpoints.  */
+
+static void
+print_recreate_masked_watchpoint (struct breakpoint *b, struct ui_file *fp)
+{
+  char tmp[40];
+
+  switch (b->type)
+    {
+    case bp_hardware_watchpoint:
+      fprintf_unfiltered (fp, "watch");
+      break;
+    case bp_read_watchpoint:
+      fprintf_unfiltered (fp, "rwatch");
+      break;
+    case bp_access_watchpoint:
+      fprintf_unfiltered (fp, "awatch");
+      break;
+    default:
+      internal_error (__FILE__, __LINE__,
+		      _("Invalid hardware watchpoint type."));
+    }
+
+  sprintf_vma (tmp, b->hw_wp_mask);
+  fprintf_unfiltered (fp, " %s mask 0x%s", b->exp_string, tmp);
+}
+
+/* The breakpoint_ops structure to be used in masked hardware watchpoints.  */
+
+static struct breakpoint_ops masked_watchpoint_breakpoint_ops =
+{
+  insert_masked_watchpoint,
+  remove_masked_watchpoint,
+  NULL, /* breakpoint_hit */
+  resources_needed_masked_watchpoint,
+  works_in_software_mode_masked_watchpoint,
+  print_it_masked_watchpoint,
+  NULL, /* print_one */
+  print_one_detail_masked_watchpoint,
+  print_mention_masked_watchpoint,
+  print_recreate_masked_watchpoint
+};
+
+/* Tell whether the given watchpoint is a masked hardware watchpoint.  */
+
+static int
+is_masked_watchpoint (const struct breakpoint *b)
+{
+  return b->ops == &masked_watchpoint_breakpoint_ops;
+}
+
 /* accessflag:  hw_write:  watch write, 
                 hw_read:   watch read, 
 		hw_access: watch access (read or write) */
@@ -8311,8 +8561,8 @@ watch_command_1 (char *arg, int accessflag, int from_tty,
   struct frame_info *frame;
   char *exp_start = NULL;
   char *exp_end = NULL;
-  char *tok, *id_tok_start, *end_tok;
-  int toklen;
+  char *tok, *end_tok;
+  int toklen = -1;
   char *cond_start = NULL;
   char *cond_end = NULL;
   int i, other_type_used, target_resources_ok = 0;
@@ -8320,66 +8570,95 @@ watch_command_1 (char *arg, int accessflag, int from_tty,
   int reg_cnt = 0;
   int thread = -1;
   int pc = 0;
+  /* Flag to indicate whether we are going to use masks for
+     the hardware watchpoint.  */
+  int use_mask = 0;
+  CORE_ADDR hw_wp_mask = 0;
 
   /* Make sure that we actually have parameters to parse.  */
   if (arg != NULL && arg[0] != '\0')
     {
-      toklen = strlen (arg); /* Size of argument list.  */
+      char *value_start;
+
+      /* Look for "parameter value" pairs at the end
+	 of the arguments string.  */
+      for (tok = arg + strlen (arg) - 1; tok > arg; tok--)
+	{
+	  /* Skip whitespace at the end of the argument list.  */
+	  while (tok > arg && (*tok == ' ' || *tok == '\t'))
+	    tok--;
+
+	  /* Find the beginning of the last token.
+	     This is the value of the parameter.  */
+	  while (tok > arg && (*tok != ' ' && *tok != '\t'))
+	    tok--;
+	  value_start = tok + 1;
+
+	  /* Skip whitespace.  */
+	  while (tok > arg && (*tok == ' ' || *tok == '\t'))
+	    tok--;
+
+	  end_tok = tok;
+
+	  /* Find the beginning of the second to last token.
+	     This is the parameter itself.  */
+	  while (tok > arg && (*tok != ' ' && *tok != '\t'))
+	    tok--;
+	  tok++;
+	  toklen = end_tok - tok + 1;
+
+	  if (toklen == 6 && !strncmp (tok, "thread", 6))
+	    {
+	      /* At this point we've found a "thread" token, which means
+		 the user is trying to set a watchpoint that triggers
+		 only in a specific thread.  */
+	      char *endp;
 
-      /* Points tok to the end of the argument list.  */
-      tok = arg + toklen - 1;
+	      if (thread != -1)
+		error(_("You can specify only one thread."));
 
-      /* Go backwards in the parameters list.  Skip the last
-         parameter.  If we're expecting a 'thread <thread_num>'
-         parameter, this should be the thread identifier.  */
-      while (tok > arg && (*tok == ' ' || *tok == '\t'))
-        tok--;
-      while (tok > arg && (*tok != ' ' && *tok != '\t'))
-        tok--;
+	      /* Extract the thread ID from the next token.  */
+	      thread = strtol (value_start, &endp, 0);
 
-      /* Points end_tok to the beginning of the last token.  */
-      id_tok_start = tok + 1;
+	      /* Check if the user provided a valid numeric value for the
+		 thread ID.  */
+	      if (*endp != ' ' && *endp != '\t' && *endp != '\0')
+		error (_("Invalid thread ID specification %s."), value_start);
 
-      /* Go backwards in the parameters list.  Skip one more
-         parameter.  If we're expecting a 'thread <thread_num>'
-         parameter, we should reach a "thread" token.  */
-      while (tok > arg && (*tok == ' ' || *tok == '\t'))
-        tok--;
+	      /* Check if the thread actually exists.  */
+	      if (!valid_thread_id (thread))
+		error (_("Unknown thread %d."), thread);
+	    }
+	  else if (toklen == 4 && !strncmp (tok, "mask", 4))
+	    {
+	      /* We've found a "mask" token, which means the user wants to
+		 create a hardware watchpoint that is going to have the mask
+		 facility.  */
+	      struct value *mask_value, *mark;
 
-      end_tok = tok;
+	      /* Does the target support masked watchpoints?  */
+	      if (!target_masked_watch_num_registers () < 0)
+		error (_("This target does not support the usage of "
+			 "masks with hardware watchpoints."));
 
-      while (tok > arg && (*tok != ' ' && *tok != '\t'))
-        tok--;
+	      if (use_mask)
+		error(_("You can specify only one mask."));
 
-      /* Move the pointer forward to skip the whitespace and
-         calculate the length of the token.  */
-      tok++;
-      toklen = end_tok - tok;
+	      use_mask = 1;
 
-      if (toklen >= 1 && strncmp (tok, "thread", toklen) == 0)
-        {
-          /* At this point we've found a "thread" token, which means
-             the user is trying to set a watchpoint that triggers
-             only in a specific thread.  */
-          char *endp;
-
-          /* Extract the thread ID from the next token.  */
-          thread = strtol (id_tok_start, &endp, 0);
-
-          /* Check if the user provided a valid numeric value for the
-             thread ID.  */
-          if (*endp != ' ' && *endp != '\t' && *endp != '\0')
-            error (_("Invalid thread ID specification %s."), id_tok_start);
-
-          /* Check if the thread actually exists.  */
-          if (!valid_thread_id (thread))
-            error (_("Unknown thread %d."), thread);
-
-          /* Truncate the string and get rid of the thread <thread_num>
-             parameter before the parameter list is parsed by the
-             evaluate_expression() function.  */
-          *tok = '\0';
-        }
+	      mark = value_mark ();
+	      mask_value = parse_to_comma_and_eval (&value_start);
+	      hw_wp_mask = value_as_address (mask_value);
+	      value_free_to_mark (mark);
+	    }
+	  else
+	    /* We didn't recognize what we found.  We should stop here.  */
+	    break;
+
+	  /* Truncate the string and get rid of the "parameter value" pair before
+	     the arguments string is parsed by the parse_exp_1 function.  */
+	  *tok = '\0';
+	}
     }
 
   /* Parse the rest of the arguments.  */
@@ -8457,6 +8736,11 @@ watch_command_1 (char *arg, int accessflag, int from_tty,
     error (_("Expression cannot be implemented with read/access watchpoint."));
   if (reg_cnt != 0)
     {
+      /* If we are going to use masks, then we may need more
+	 slots in order to use the hardware watchpoint.  */
+      if (use_mask)
+	reg_cnt = target_masked_watch_num_registers ();
+
       i = hw_watchpoint_used_count (bp_type, &other_type_used);
       target_resources_ok = 
 	target_can_use_hardware_watchpoint (bp_type, i + reg_cnt,
@@ -8469,10 +8753,18 @@ watch_command_1 (char *arg, int accessflag, int from_tty,
 		 "of HW watchpoint at a time."));
     }
 
-  /* Change the type of breakpoint to an ordinary watchpoint if a
-     hardware watchpoint could not be set.  */
   if (!reg_cnt || target_resources_ok <= 0)
-    bp_type = bp_watchpoint;
+    {
+      if (use_mask && !reg_cnt)
+	error (_("Cannot use masks with the given expression."));
+      else if (use_mask && target_resources_ok <= 0)
+	error (_("Cannot use masks without enough available "
+		 "hardware watchpoints (need %d)."), reg_cnt);
+      else
+	/* Change the type of breakpoint to an ordinary watchpoint if a
+	   hardware watchpoint could not be set.  */
+	bp_type = bp_watchpoint;
+    }
 
   frame = block_innermost_frame (exp_valid_block);
 
@@ -8540,7 +8832,14 @@ watch_command_1 (char *arg, int accessflag, int from_tty,
     b->exp_string = savestring (exp_start, exp_end - exp_start);
   b->val = val;
   b->val_valid = 1;
-  b->ops = &watchpoint_breakpoint_ops;
+
+  if (use_mask)
+    {
+      b->hw_wp_mask = hw_wp_mask;
+      b->ops = &masked_watchpoint_breakpoint_ops;
+    }
+  else
+    b->ops = &watchpoint_breakpoint_ops;
 
   /* Use an exact watchpoint when there's only one memory region to be
      watched, and only one debug register is needed to watch it.  */
@@ -8993,7 +9292,8 @@ catch_exec_command_1 (char *arg, int from_tty,
 }
 
 static enum print_stop_action
-print_exception_catchpoint (struct breakpoint *b)
+print_it_exception_catchpoint (struct breakpoint *b,
+			       const struct value *old_val)
 {
   int bp_temp, bp_throw;
 
@@ -9084,8 +9384,10 @@ static struct breakpoint_ops gnu_v3_exception_catchpoint_ops = {
   NULL, /* remove */
   NULL, /* breakpoint_hit */
   NULL, /* resources_needed */
-  print_exception_catchpoint,
+  NULL, /* works_in_software_mode */
+  print_it_exception_catchpoint,
   print_one_exception_catchpoint,
+  NULL, /* print_one_detail */
   print_mention_exception_catchpoint,
   print_recreate_exception_catchpoint
 };
diff --git a/gdb/breakpoint.h b/gdb/breakpoint.h
index 69598a7..3195124 100644
--- a/gdb/breakpoint.h
+++ b/gdb/breakpoint.h
@@ -28,6 +28,7 @@
 struct value;
 struct block;
 struct breakpoint_object;
+struct ui_out;
 
 /* This is the maximum number of bytes a breakpoint instruction can
    take.  Feel free to increase it.  It's just used in a few places to
@@ -390,14 +391,34 @@ struct breakpoint_ops
      the breakpoint or watchpoint needs one debug register.  */
   int (*resources_needed) (const struct bp_location *);
 
+  /* Tell whether we can downgrade from a hardware watchpoint to a software
+     one.  If not, the user will not be able to enable the watchpoint when
+     there are not enough hardware resources available.  */
+  int (*works_in_software_mode) (const struct breakpoint *);
+
   /* The normal print routine for this breakpoint, called when we
      hit it.  */
-  enum print_stop_action (*print_it) (struct breakpoint *);
+  enum print_stop_action (*print_it) (struct breakpoint *,
+				      const struct value *old_val);
 
   /* Display information about this breakpoint, for "info
      breakpoints".  */
   void (*print_one) (struct breakpoint *, struct bp_location **);
 
+  /* Display extra information about this breakpoint, below the normal
+     breakpoint description in "info breakpoints".
+
+     In the example below, the line with "mask 0xffffff00" was printed
+     by print_one_detail_ranged_watchpoint.
+
+     (gdb) info breakpoints
+     Num     Type           Disp Enb Address    What
+     2       hw watchpoint  keep y              *0x10094420
+	     mask 0xffffff00
+
+     */
+  void (*print_one_detail) (const struct breakpoint *, struct ui_out *);
+
   /* Display information about this breakpoint after setting it
      (roughly speaking; this is called from "mention").  */
   void (*print_mention) (struct breakpoint *);
@@ -610,6 +631,9 @@ struct breakpoint
 
     /* Whether this watchpoint is exact (see target_exact_watchpoints).  */
     int exact;
+
+    /* The mask address for a masked hardware watchpoint.  */
+    CORE_ADDR hw_wp_mask;
   };
 
 typedef struct breakpoint *breakpoint_p;
diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo
index d48d95c..355afcb 100644
--- a/gdb/doc/gdb.texinfo
+++ b/gdb/doc/gdb.texinfo
@@ -3688,7 +3688,7 @@ watchpoints, which do not slow down the running of your program.
 
 @table @code
 @kindex watch
-@item watch @r{[}-l@r{|}-location@r{]} @var{expr} @r{[}thread @var{threadnum}@r{]}
+@item watch @r{[}-l@r{|}-location@r{]} @var{expr} @r{[}thread @var{threadnum}@r{]} @r{[}mask @var{maskvalue}@r{]}
 Set a watchpoint for an expression.  @value{GDBN} will break when the
 expression @var{expr} is written into by the program and its value
 changes.  The simplest (and the most popular) use of this command is
@@ -3699,12 +3699,17 @@ to watch the value of a single variable:
 @end smallexample
 
 If the command includes a @code{@r{[}thread @var{threadnum}@r{]}}
-clause, @value{GDBN} breaks only when the thread identified by
+argument, @value{GDBN} breaks only when the thread identified by
 @var{threadnum} changes the value of @var{expr}.  If any other threads
 change the value of @var{expr}, @value{GDBN} will not break.  Note
 that watchpoints restricted to a single thread in this way only work
 with Hardware Watchpoints.
 
+The @code{@r{[}mask @var{maskvalue}@r{]}} argument allows creation
+of masked watchpoints, if the current architecture supports this
+feature.  (Currently, this is only available on PowerPC Embedded
+architecture, see @ref{PowerPC Embedded}.)
+
 Ordinarily a watchpoint respects the scope of variables in @var{expr}
 (see below).  The @code{-location} argument tells @value{GDBN} to
 instead watch the memory referred to by @var{expr}.  In this case,
@@ -3715,12 +3720,12 @@ result does not have an address, then @value{GDBN} will print an
 error.
 
 @kindex rwatch
-@item rwatch @r{[}-l@r{|}-location@r{]} @var{expr} @r{[}thread @var{threadnum}@r{]}
+@item rwatch @r{[}-l@r{|}-location@r{]} @var{expr} @r{[}thread @var{threadnum}@r{]} @r{[}mask @var{maskvalue}@r{]}
 Set a watchpoint that will break when the value of @var{expr} is read
 by the program.
 
 @kindex awatch
-@item awatch @r{[}-l@r{|}-location@r{]} @var{expr} @r{[}thread @var{threadnum}@r{]}
+@item awatch @r{[}-l@r{|}-location@r{]} @var{expr} @r{[}thread @var{threadnum}@r{]} @r{[}mask @var{maskvalue}@r{]}
 Set a watchpoint that will break when @var{expr} is either read from
 or written into by the program.
 
@@ -18684,6 +18689,23 @@ region using one of the following commands (@pxref{Expressions}):
 (@value{GDBP}) watch @{char[@var{length}]@} @var{address}
 @end smallexample
 
+PowerPC embedded processors support masked watchpoints.
+
+A @dfn{masked watchpoint} specifies a mask in addition to an address
+to watch.  The mask specifies that some bits of an address (the bits
+which are reset in the mask) should be ignored when matching the
+address accessed by the inferior against the watchpoint address.
+Thus, a masked watchpoint watches many addresses
+simultaneously---those addresses whose unmasked bits are identical
+to the unmasked bits in the watchpoint address.
+
+To set a masked watchpoint in @value{GDBN}, use the @code{mask} argument in
+the @code{watch} command (@pxref{Set Watchpoints}), as in:
+
+@smallexample
+(@value{GDBP}) watch *0xdeadbeef mask 0xffffff00
+@end smallexample
+
 @value{GDBN} provides the following PowerPC-specific commands:
 
 @table @code
diff --git a/gdb/ppc-linux-nat.c b/gdb/ppc-linux-nat.c
index 0c5563e..140ad97 100644
--- a/gdb/ppc-linux-nat.c
+++ b/gdb/ppc-linux-nat.c
@@ -1702,6 +1702,69 @@ get_trigger_type (int rw)
   return t;
 }
 
+/* Insert a new masked watchpoint at ADDR using the mask MASK.
+   RW may be hw_read for a read watchpoint, hw_write for a write watchpoint
+   or hw_access for an access watchpoint.  Returns 0 on success and throws
+   an error on failure.  */
+
+static int
+ppc_linux_insert_mask_watchpoint (struct target_ops *ops, CORE_ADDR addr,
+				  CORE_ADDR mask, int rw)
+{
+  ptid_t ptid;
+  struct lwp_info *lp;
+  struct ppc_hw_breakpoint p;
+
+  gdb_assert (have_ptrace_booke_interface ());
+
+  if ((mask & 0xC0000000) != 0xC0000000)
+    error (_("\
+The given mask covers kernel address space and cannot be used.\n\
+You have to delete the masked watchpoint to continue the debugging session."));
+
+  p.version = PPC_DEBUG_CURRENT_VERSION;
+  p.trigger_type = get_trigger_type (rw);
+  p.addr_mode = PPC_BREAKPOINT_MODE_MASK;
+  p.condition_mode = PPC_BREAKPOINT_CONDITION_NONE;
+  p.addr = addr;
+  p.addr2 = mask;
+  p.condition_value = 0;
+
+  ALL_LWPS (lp, ptid)
+    booke_insert_point (&p, TIDGET (ptid));
+
+  return 0;
+}
+
+/* Remove a masked watchpoint at ADDR with the mask MASK.
+   RW may be hw_read for a read watchpoint, hw_write for a write watchpoint
+   or hw_access for an access watchpoint.  Returns 0 on success and throws
+   an error on failure.  */
+
+static int
+ppc_linux_remove_mask_watchpoint (struct target_ops *ops, CORE_ADDR addr,
+				  CORE_ADDR mask, int rw)
+{
+  ptid_t ptid;
+  struct lwp_info *lp;
+  struct ppc_hw_breakpoint p;
+
+  gdb_assert (have_ptrace_booke_interface ());
+
+  p.version = PPC_DEBUG_CURRENT_VERSION;
+  p.trigger_type = get_trigger_type (rw);
+  p.addr_mode = PPC_BREAKPOINT_MODE_MASK;
+  p.condition_mode = PPC_BREAKPOINT_CONDITION_NONE;
+  p.addr = addr;
+  p.addr2 = mask;
+  p.condition_value = 0;
+
+  ALL_LWPS (lp, ptid)
+    booke_remove_point (&p, TIDGET (ptid));
+
+  return 0;
+}
+
 /* Check whether we have at least one free DVC register.  */
 static int
 can_use_watchpoint_cond_accel (void)
@@ -2173,6 +2236,16 @@ ppc_linux_watchpoint_addr_within_range (struct target_ops *target,
   return start <= addr + mask && start + length - 1 >= addr;
 }
 
+/* Return the number of registers needed for a masked hardware watchpoint.  */
+
+static int
+ppc_linux_masked_watch_num_registers (struct target_ops *target)
+{
+  return ((have_ptrace_booke_interface ()
+	   && booke_debug_info.features & PPC_DEBUG_FEATURE_DATA_BP_MASK)?
+	  2 : -1);
+}
+
 static void
 ppc_linux_store_inferior_registers (struct target_ops *ops,
 				    struct regcache *regcache, int regno)
@@ -2387,11 +2460,14 @@ _initialize_ppc_linux_nat (void)
   t->to_region_ok_for_hw_watchpoint = ppc_linux_region_ok_for_hw_watchpoint;
   t->to_insert_watchpoint = ppc_linux_insert_watchpoint;
   t->to_remove_watchpoint = ppc_linux_remove_watchpoint;
+  t->to_insert_mask_watchpoint = ppc_linux_insert_mask_watchpoint;
+  t->to_remove_mask_watchpoint = ppc_linux_remove_mask_watchpoint;
   t->to_stopped_by_watchpoint = ppc_linux_stopped_by_watchpoint;
   t->to_stopped_data_address = ppc_linux_stopped_data_address;
   t->to_watchpoint_addr_within_range = ppc_linux_watchpoint_addr_within_range;
   t->to_can_accel_watchpoint_condition
     = ppc_linux_can_accel_watchpoint_condition;
+  t->to_masked_watch_num_registers = ppc_linux_masked_watch_num_registers;
 
   t->to_read_description = ppc_linux_read_description;
   t->to_auxv_parse = ppc_linux_auxv_parse;
diff --git a/gdb/target.c b/gdb/target.c
index ff87931..d14ec6a 100644
--- a/gdb/target.c
+++ b/gdb/target.c
@@ -606,6 +606,8 @@ update_current_target (void)
       INHERIT (to_remove_hw_breakpoint, t);
       INHERIT (to_insert_watchpoint, t);
       INHERIT (to_remove_watchpoint, t);
+      /* Do not inherit to_insert_mask_watchpoint.  */
+      /* Do not inherit to_remove_mask_watchpoint.  */
       INHERIT (to_stopped_data_address, t);
       INHERIT (to_have_steppable_watchpoint, t);
       INHERIT (to_have_continuable_watchpoint, t);
@@ -613,6 +615,7 @@ update_current_target (void)
       INHERIT (to_watchpoint_addr_within_range, t);
       INHERIT (to_region_ok_for_hw_watchpoint, t);
       INHERIT (to_can_accel_watchpoint_condition, t);
+      /* Do not inherit to_masked_watch_num_registers.  */
       INHERIT (to_terminal_init, t);
       INHERIT (to_terminal_inferior, t);
       INHERIT (to_terminal_ours_for_output, t);
@@ -3345,6 +3348,75 @@ target_verify_memory (const gdb_byte *data, CORE_ADDR memaddr, ULONGEST size)
   tcomplain ();
 }
 
+/* The documentation for this function is in its prototype declaration in
+   target.h.  */
+
+int
+target_insert_mask_watchpoint (CORE_ADDR addr, CORE_ADDR mask, int rw)
+{
+  struct target_ops *t;
+
+  for (t = current_target.beneath; t != NULL; t = t->beneath)
+    if (t->to_insert_mask_watchpoint != NULL)
+      {
+	int ret;
+
+	ret = t->to_insert_mask_watchpoint (t, addr, mask, rw);
+
+	if (targetdebug)
+	  fprintf_unfiltered (gdb_stdlog, "\
+target_insert_mask_watchpoint (%s, %s, %d) = %d\n",
+			      core_addr_to_string (addr),
+			      core_addr_to_string (mask), rw, ret);
+
+	return ret;
+      }
+
+  return return_one ();
+}
+
+/* The documentation for this function is in its prototype declaration in
+   target.h.  */
+
+int
+target_remove_mask_watchpoint (CORE_ADDR addr, CORE_ADDR mask, int rw)
+{
+  struct target_ops *t;
+
+  for (t = current_target.beneath; t != NULL; t = t->beneath)
+    if (t->to_remove_mask_watchpoint != NULL)
+      {
+	int ret;
+
+	ret = t->to_remove_mask_watchpoint (t, addr, mask, rw);
+
+	if (targetdebug)
+	  fprintf_unfiltered (gdb_stdlog, "\
+target_remove_mask_watchpoint (%s, %s, %d) = %d\n",
+			      core_addr_to_string (addr),
+			      core_addr_to_string (mask), rw, ret);
+
+	return ret;
+      }
+
+  return return_one ();
+}
+
+/* The documentation for this function is in its prototype declaration
+   in target.h.  */
+
+int
+target_masked_watch_num_registers (void)
+{
+  struct target_ops *t;
+
+  for (t = current_target.beneath; t != NULL; t = t->beneath)
+    if (t->to_masked_watch_num_registers != NULL)
+      return t->to_masked_watch_num_registers (t);
+
+  return return_minus_one ();
+}
+
 static void
 debug_to_prepare_to_store (struct regcache *regcache)
 {
diff --git a/gdb/target.h b/gdb/target.h
index a1288d0..3f895cf 100644
--- a/gdb/target.h
+++ b/gdb/target.h
@@ -447,6 +447,10 @@ struct target_ops
     int (*to_remove_watchpoint) (CORE_ADDR, int, int, struct expression *);
     int (*to_insert_watchpoint) (CORE_ADDR, int, int, struct expression *);
 
+    int (*to_insert_mask_watchpoint) (struct target_ops *,
+				      CORE_ADDR, CORE_ADDR, int);
+    int (*to_remove_mask_watchpoint) (struct target_ops *,
+				      CORE_ADDR, CORE_ADDR, int);
     int (*to_stopped_by_watchpoint) (void);
     int to_have_steppable_watchpoint;
     int to_have_continuable_watchpoint;
@@ -460,6 +464,7 @@ struct target_ops
 
     int (*to_can_accel_watchpoint_condition) (CORE_ADDR, int, int,
 					      struct expression *);
+    int (*to_masked_watch_num_registers) (struct target_ops *);
     void (*to_terminal_init) (void);
     void (*to_terminal_inferior) (void);
     void (*to_terminal_ours_for_output) (void);
@@ -1331,6 +1336,20 @@ extern char *normal_pid_to_str (ptid_t ptid);
 #define	target_remove_watchpoint(addr, len, type, cond) \
      (*current_target.to_remove_watchpoint) (addr, len, type, cond)
 
+/* Insert a new masked watchpoint at ADDR using the mask MASK.
+   RW may be hw_read for a read watchpoint, hw_write for a write watchpoint
+   or hw_access for an access watchpoint.  Returns 0 for success, 1 if
+   masked watchpoints are not supported, -1 for failure.  */
+
+extern int target_insert_mask_watchpoint (CORE_ADDR, CORE_ADDR, int);
+
+/* Remove a masked watchpoint at ADDR with the mask MASK.
+   RW may be hw_read for a read watchpoint, hw_write for a write watchpoint
+   or hw_access for an access watchpoint.  Returns 0 for success, non-zero
+   for failure.  */
+
+extern int target_remove_mask_watchpoint (CORE_ADDR, CORE_ADDR, int);
+
 #define target_insert_hw_breakpoint(gdbarch, bp_tgt) \
      (*current_target.to_insert_hw_breakpoint) (gdbarch, bp_tgt)
 
@@ -1359,6 +1378,11 @@ extern char *normal_pid_to_str (ptid_t ptid);
 #define target_can_accel_watchpoint_condition(addr, len, type, cond) \
   (*current_target.to_can_accel_watchpoint_condition) (addr, len, type, cond)
 
+/* Return number of debug registers needed for a masked watchpoint,
+   or -1 if masked watchpoints are not supported.  */
+
+extern int target_masked_watch_num_registers (void);
+
 /* Target can execute in reverse?  */
 #define target_can_execute_reverse \
      (current_target.to_can_execute_reverse ? \


^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [RFA] Implement support for PowerPC BookE masked watchpoints
  2011-01-13 20:55 [RFA] Implement support for PowerPC BookE masked watchpoints Thiago Jung Bauermann
@ 2011-01-31 20:09 ` Thiago Jung Bauermann
  2011-02-17 15:10 ` Ulrich Weigand
  1 sibling, 0 replies; 38+ messages in thread
From: Thiago Jung Bauermann @ 2011-01-31 20:09 UTC (permalink / raw)
  To: gdb-patches ml

On Thu, 2011-01-13 at 18:06 -0200, Thiago Jung Bauermann wrote:
> The documentation part of the patch was already reviewed and approved.
> No regressions on ppc-linux, ppc64-linux or i386-linux. Ok to commit?
> 
> To ease review, here are the changes on parsing the command line in
> watch_command_1, with a diff ignoring whitespace changes:

Ping.
-- 
[]'s
Thiago Jung Bauermann
IBM Linux Technology Center

^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [RFA] Implement support for PowerPC BookE masked watchpoints
  2011-01-13 20:55 [RFA] Implement support for PowerPC BookE masked watchpoints Thiago Jung Bauermann
  2011-01-31 20:09 ` Thiago Jung Bauermann
@ 2011-02-17 15:10 ` Ulrich Weigand
  2011-04-18 21:22   ` [RFA 2/3] Demote to sw watchpoint only in update_watchpoint Thiago Jung Bauermann
                     ` (2 more replies)
  1 sibling, 3 replies; 38+ messages in thread
From: Ulrich Weigand @ 2011-02-17 15:10 UTC (permalink / raw)
  To: Thiago Jung Bauermann; +Cc: gdb-patches ml

Thiago Jung Bauermann wrote:

> I'm almost done with the series adding suport for PowerPC BookE
> features... There's only this patch adding masked watchpoints, and
> another one adding ranged hardware breakpoints (to be posted later). So
> please bear with me a little longer. :-)

I have one basic issue with this patch: the semantics of the new masked
watchpoint commands seems not quite fully defined.

The semantics of a GDB watchpoint usually is: stop execution whenever
the value of an expression changes.  To implement this, GDB will parse
the expression, and create a set of low-level watchpoints to be
implemented by hardware (which are usually along the lines of: stop
execution whenever a store to a contiguous region of memory happens).

Now, the "masked breakpoints" feature is at its core defined at that
lower level: stop execution whenever a store to a memory region
happens, where that region of memory is defined in a more complex
manner (via masked address matching).

The problem with the patch in its current form seems to me that it
confuses the two levels.  On the GDB command line, the user specifies
an expression, just like with normal watchpoints, and a mask, which
is passed directly to the hardware feature.

The effect is that GDB will parse the expression, create the list of
memory regions it needs to watch to implement its high-level semantics.
Then, it will just add the mask to each of the addresses generated
in that manner.  It seems to me that in general, the effects of what
will actually happen now are hard to predict, and will generally not
be what the user expects.

Of course, the feature *can* be used in ways the user understands,
like in the example you show in the documentation:
   watch *0xdeadbeef mask 0xffffff00

But if used in a more complex way, like
   watch p->x mask 0xffffff00
for some local variable p, this doesn't seem to have very useful
(or even well-defined) semantics ...


Now, I'm not sure how exactly the GDB command line syntax ought to
be modified to implement this.  But most fundamentally, we should
go away from specifying "the value of an expression", and rather
go to specifying a memory region via address and mask.

We've recently added the -location feature that already prevents
GDB from fully tracking the expression, but rather just evaluate
it one time for its address.   Maybe one simple fix could be to
restrict the "mask" feature to watch -location (or have the 
presence of "mask" automatically imply -location, or maybe have
instead a new keyword -masked-location or so).

However, even so there are still differences: even with -location,
GDB watchpoint code will still treat a watchpoint as refering to
one value, and track it (e.g. remember the value we saw last time;
re-evaluate it each time execution stops etc.).  This is really
not appropriate for the masked watchpoint case, because we do not
*have* any contiguous region that would define any single value.
Therefore, it seems to me that all this code ought to be disabled
for masked watchpoints.


A couple of more specific comments on the patch:

> @@ -1518,10 +1522,26 @@ update_watchpoint (struct breakpoint *b, int reparse)
>  	      target_resources_ok = target_can_use_hardware_watchpoint
>  		    (bp_hardware_watchpoint, i, other_type_used);
>  	      if (target_resources_ok <= 0)
> -		b->type = bp_watchpoint;
> +		{
> +		  if (orig_type == bp_hardware_watchpoint
> +		      && b->ops && b->ops->works_in_software_mode
> +		      && !b->ops->works_in_software_mode (b))
> +		    error (_("This watchpoint cannot be used "
> +			     "in software mode."));
> +		  else
> +		    b->type = bp_watchpoint;
> +		}
>  	    }
>  	  else
> -	    b->type = bp_watchpoint;
> +	    {
> +	      if (b->type == bp_hardware_watchpoint
> +		  && b->ops && b->ops->works_in_software_mode
> +		  && !b->ops->works_in_software_mode (b))
> +		error (_("This watchpoint cannot be used "
> +			 "in software mode."));
> +	      else
> +		b->type = bp_watchpoint;
> +	    }

What is the point of checking the original type?  If works_in_software_mode
returns false, the original type couldn't have been a software watchpoint
anyway, could it?

>  	   print_it_typical.  */
>  	/* FIXME: how breakpoint can ever be NULL here?  */
>  	if (b != NULL && b->ops != NULL && b->ops->print_it != NULL)
> -	  return b->ops->print_it (b);
> +	  return b->ops->print_it (b, bs->old_val);
>  	else
>  	  return print_it_typical (bs);
>        }

I don't understand this change.  You add the "old_val" argument to the
print_it routine, and the new instance of print_it for masked watchpoints
then uses it (for what purpose?) ...  But for masked watchpoints, the
whole concept of its "value", new or old, doesn't make sense to start
with ...

> @@ -3761,6 +3796,11 @@ watchpoint_check (void *p)
>  	  b->val_valid = 1;
>  	  return WP_VALUE_CHANGED;
>  	}
> +      else if (is_masked_watchpoint (b))
> +	/* Since we don't know the exact trigger address (from
> +	   stopped_data_address), just tell the user we've triggered
> +	   a mask watchpoint.  */
> +	return WP_VALUE_CHANGED;

This goes back to the issue discussed above: this should not even
attempt to "compute the old value" which doesn't make sense for a
masked watchpoint.  Instead, it should simply report a stop to the
user whenever the hardware reports a hit.

> +static void
> +print_one_detail_masked_watchpoint (const struct breakpoint *b,
> +				    struct ui_out *uiout)
> +{
> +  ui_out_text (uiout, "\tmask ");
> +
> +  /* I don't know whether it's possible to get here without a b->loc,
> +     but we can handle the situation.  */
> +  if (b->loc)
> +    ui_out_field_core_addr (uiout, "mask", b->loc->gdbarch, b->hw_wp_mask);
> +  else
> +    ui_out_field_string (uiout, "mask", core_addr_to_string (b->hw_wp_mask));

I think we should enforce that there is always exactly one location on
masked watchpoints, just like we do e.g. for catchpoints.

> +/* Implement the "print_recreate" breakpoint_ops method for
> +   masked hardware watchpoints.  */
> +
> +static void
> +print_recreate_masked_watchpoint (struct breakpoint *b, struct ui_file *fp)
> +{
> +  char tmp[40];
> +
> +  switch (b->type)
> +    {
> +    case bp_hardware_watchpoint:
> +      fprintf_unfiltered (fp, "watch");
> +      break;
> +    case bp_read_watchpoint:
> +      fprintf_unfiltered (fp, "rwatch");
> +      break;
> +    case bp_access_watchpoint:
> +      fprintf_unfiltered (fp, "awatch");
> +      break;
> +    default:
> +      internal_error (__FILE__, __LINE__,
> +		      _("Invalid hardware watchpoint type."));
> +    }
> +
> +  sprintf_vma (tmp, b->hw_wp_mask);
> +  fprintf_unfiltered (fp, " %s mask 0x%s", b->exp_string, tmp);

Depending on the discussion on command syntax this may need to change anyway,
but even with the current syntax, it ignores any -location flag that may have
been given initially ...

> @@ -8540,7 +8832,14 @@ watch_command_1 (char *arg, int accessflag, int from_tty,
>      b->exp_string = savestring (exp_start, exp_end - exp_start);
>    b->val = val;
>    b->val_valid = 1;
> -  b->ops = &watchpoint_breakpoint_ops;
> +
> +  if (use_mask)
> +    {
> +      b->hw_wp_mask = hw_wp_mask;
> +      b->ops = &masked_watchpoint_breakpoint_ops;
> +    }
> +  else
> +    b->ops = &watchpoint_breakpoint_ops;

We shouldn't compute an intial value or set val_valid for masked watchpoints.

> +/* Insert a new masked watchpoint at ADDR using the mask MASK.
> +   RW may be hw_read for a read watchpoint, hw_write for a write watchpoint
> +   or hw_access for an access watchpoint.  Returns 0 on success and throws
> +   an error on failure.  */
> +
> +static int
> +ppc_linux_insert_mask_watchpoint (struct target_ops *ops, CORE_ADDR addr,
> +				  CORE_ADDR mask, int rw)
> +{
> +  ptid_t ptid;
> +  struct lwp_info *lp;
> +  struct ppc_hw_breakpoint p;
> +
> +  gdb_assert (have_ptrace_booke_interface ());
> +
> +  if ((mask & 0xC0000000) != 0xC0000000)
> +    error (_("\
> +The given mask covers kernel address space and cannot be used.\n\
> +You have to delete the masked watchpoint to continue the debugging session."));

Huh, this interface seems a bit odd.  Shouldn't such watchpoints be rejected
right from the start, using something like the region_ok_for_watchpoint
callback?

> +/* Return the number of registers needed for a masked hardware watchpoint.  */
> +
> +static int
> +ppc_linux_masked_watch_num_registers (struct target_ops *target)
> +{
> +  return ((have_ptrace_booke_interface ()
> +	   && booke_debug_info.features & PPC_DEBUG_FEATURE_DATA_BP_MASK)?
> +	  2 : -1);
> +}

So maybe this interface ought to get parameters to be able to check
whether specific watchpoints are valid?

>        INHERIT (to_insert_watchpoint, t);
>        INHERIT (to_remove_watchpoint, t);
> +      /* Do not inherit to_insert_mask_watchpoint.  */
> +      /* Do not inherit to_remove_mask_watchpoint.  */

Why should this differ between regular and masked watchpoints?  Shouldn't
they either both use inheritance or none?

Bye,
Ulrich

-- 
  Dr. Ulrich Weigand
  GNU Toolchain for Linux on System z and Cell BE
  Ulrich.Weigand@de.ibm.com

^ permalink raw reply	[flat|nested] 38+ messages in thread

* [RFA 2/3] Demote to sw watchpoint only in update_watchpoint
  2011-02-17 15:10 ` Ulrich Weigand
@ 2011-04-18 21:22   ` Thiago Jung Bauermann
  2011-04-29 17:26     ` Ulrich Weigand
  2011-04-18 21:22   ` [RFA 1/3] Change watchpoint's enable state in do_enable_breakpoint Thiago Jung Bauermann
  2011-04-18 21:24   ` [RFA 3/3] Implement support for PowerPC BookE masked watchpoints Thiago Jung Bauermann
  2 siblings, 1 reply; 38+ messages in thread
From: Thiago Jung Bauermann @ 2011-04-18 21:22 UTC (permalink / raw)
  To: Ulrich Weigand; +Cc: gdb-patches ml

Hi,

watch_command_1 duplicates logic from update_watchpoint to decide
whether the newly created watchpoint should be a software watchpoint or
a hardware watchpoint, and also to error out if trying to set up a read
or access watchpoint without having debug registers available.

I was trying to adapt the logic in both places for masked watchpoints,
but it's hard to anticipate in watch_command_1 what update_watchpoint
will ultimately do without duplicating a good portion of the latter. The
code in watch_command_1 was getting complicated and hard to get right in
all situations for something which would be done again later anyway.

I decided that it was cleaner if watch_command_1 just delegated
everything to update_watchpoint. This patch makes it create a
watchpoint, call update_watchpoint and then delete it if some error is
hit. The only drawback I can think of is that the aborted watchpoint
will "consume" one breakpoint number, and thus GDB will skip one number
when creating the next breakpoint/watchpoint. This doesn't seem
important to me.

Tested without regressions on ppc-linux, ppc64-linux and i386-linux. Ok?
-- 
[]'s
Thiago Jung Bauermann
IBM Linux Technology Center


2011-04-18  Thiago Jung Bauermann  <bauerman@br.ibm.com>

	* breakpoint.c (update_watchpoint): Change between software and
	hardware watchpoint for all kinds of watchpoints, not just
	read/write ones.  Determine b->exact value here instead of
	in watch_command_1.  Error out if there are not enough resources
	for a read or access hardware watchpoint.
	(watch_command_1): Remove logic of checking whether there are
	enough resources available, since update_watchpoint will do that
	work now.  Don't set b->exact here.  Catch exceptions thrown by
	update_watchpoint and delete the watchpoint.
	(can_use_hardware_watchpoint): Remove exact_watchpoints argument.
	Use target_exact_watchpoints instead.
	(delete_breakpoint): Add announce argument to control whether
	observers are notified of the deletion.  Update all callers.

diff --git a/gdb/breakpoint.c b/gdb/breakpoint.c
index 744057a..2bfdfb0 100644
--- a/gdb/breakpoint.c
+++ b/gdb/breakpoint.c
@@ -101,7 +101,7 @@ static void clear_command (char *, int);
 
 static void catch_command (char *, int);
 
-static int can_use_hardware_watchpoint (struct value *, int);
+static int can_use_hardware_watchpoint (struct value *);
 
 static void break_command_1 (char *, int, int);
 
@@ -1404,19 +1404,22 @@ update_watchpoint (struct breakpoint *b, int reparse)
 	 an ordinary watchpoint depending on the hardware support
 	 and free hardware slots.  REPARSE is set when the inferior
 	 is started.  */
-      if ((b->type == bp_watchpoint || b->type == bp_hardware_watchpoint)
-	  && reparse)
+      if (reparse)
 	{
 	  int reg_cnt;
 	  enum bp_loc_type loc_type;
 	  struct bp_location *bl;
 
-	  reg_cnt = can_use_hardware_watchpoint (val_chain, b->exact);
+	  reg_cnt = can_use_hardware_watchpoint (val_chain);
 
 	  if (reg_cnt)
 	    {
 	      int i, target_resources_ok, other_type_used;
 
+	      /* Use an exact watchpoint when there's only one memory region to be
+		 watched, and only one debug register is needed to watch it.  */
+	      b->exact = target_exact_watchpoints && reg_cnt == 1;
+
 	      /* We need to determine how many resources are already
 		 used for all other hardware watchpoints plus this one
 		 to see if we still have enough resources to also fit
@@ -1424,7 +1427,8 @@ update_watchpoint (struct breakpoint *b, int reparse)
 		 hw_watchpoint_used_count call below counts this
 		 watchpoint, make sure that it is marked as a hardware
 		 watchpoint.  */
-	      b->type = bp_hardware_watchpoint;
+	      if (b->type == bp_watchpoint)
+		b->type = bp_hardware_watchpoint;
 
 	      i = hw_watchpoint_used_count (bp_hardware_watchpoint,
 					    &other_type_used);
@@ -1432,8 +1436,22 @@ update_watchpoint (struct breakpoint *b, int reparse)
 	      target_resources_ok = target_can_use_hardware_watchpoint
 		    (bp_hardware_watchpoint, i, other_type_used);
 	      if (target_resources_ok <= 0)
-		b->type = bp_watchpoint;
+		{
+		  if (target_resources_ok == 0
+		      && b->type != bp_hardware_watchpoint)
+		    error (_("Target does not support this type of "
+			     "hardware watchpoint."));
+		  else if (target_resources_ok < 0
+		      && b->type != bp_hardware_watchpoint)
+		    error (_("Target can only support one kind "
+			     "of HW watchpoint at a time."));
+		  else
+		    b->type = bp_watchpoint;
+		}
 	    }
+	  else if (b->type != bp_hardware_watchpoint)
+	    error (_("Expression cannot be implemented with "
+		     "read/access watchpoint."));
 	  else
 	    b->type = bp_watchpoint;
 
@@ -1796,7 +1814,7 @@ breakpoint_program_space_exit (struct program_space *pspace)
   ALL_BREAKPOINTS_SAFE (b, b_temp)
     {
       if (b->pspace == pspace)
-	delete_breakpoint (b);
+	delete_breakpoint (b, 1);
     }
 
   /* Breakpoints set through other program spaces could have locations
@@ -2382,14 +2400,14 @@ update_breakpoints_after_exec (void)
     /* Solib breakpoints must be explicitly reset after an exec().  */
     if (b->type == bp_shlib_event)
       {
-	delete_breakpoint (b);
+	delete_breakpoint (b, 1);
 	continue;
       }
 
     /* JIT breakpoints must be explicitly reset after an exec().  */
     if (b->type == bp_jit_event)
       {
-	delete_breakpoint (b);
+	delete_breakpoint (b, 1);
 	continue;
       }
 
@@ -2399,14 +2417,14 @@ update_breakpoints_after_exec (void)
 	|| b->type == bp_longjmp_master || b->type == bp_std_terminate_master
 	|| b->type == bp_exception_master)
       {
-	delete_breakpoint (b);
+	delete_breakpoint (b, 1);
 	continue;
       }
 
     /* Step-resume breakpoints are meaningless after an exec().  */
     if (b->type == bp_step_resume)
       {
-	delete_breakpoint (b);
+	delete_breakpoint (b, 1);
 	continue;
       }
 
@@ -2415,7 +2433,7 @@ update_breakpoints_after_exec (void)
     if (b->type == bp_longjmp || b->type == bp_longjmp_resume
 	|| b->type == bp_exception || b->type == bp_exception_resume)
       {
-	delete_breakpoint (b);
+	delete_breakpoint (b, 1);
 	continue;
       }
 
@@ -2464,7 +2482,7 @@ update_breakpoints_after_exec (void)
        a.out.  */
     if (b->addr_string == NULL)
       {
-	delete_breakpoint (b);
+	delete_breakpoint (b, 1);
 	continue;
       }
   }
@@ -2736,7 +2754,7 @@ breakpoint_init_inferior (enum inf_context context)
 	   (gdb) tar rem :9999     # remote Windows gdbserver.
 	*/
 
-	delete_breakpoint (b);
+	delete_breakpoint (b, 1);
 	break;
 
       case bp_watchpoint:
@@ -2746,7 +2764,7 @@ breakpoint_init_inferior (enum inf_context context)
 
 	/* Likewise for watchpoints on local expressions.  */
 	if (b->exp_valid_block != NULL)
-	  delete_breakpoint (b);
+	  delete_breakpoint (b, 1);
 	else if (context == inf_starting) 
 	  {
 	    /* Reset val field to force reread of starting value in
@@ -5970,7 +5988,7 @@ delete_longjmp_breakpoint (int thread)
     if (b->type == bp_longjmp || b->type == bp_exception)
       {
 	if (b->thread == thread)
-	  delete_breakpoint (b);
+	  delete_breakpoint (b, 1);
       }
 }
 
@@ -6026,7 +6044,7 @@ delete_std_terminate_breakpoint (void)
 
   ALL_BREAKPOINTS_SAFE (b, b_tmp)
     if (b->type == bp_std_terminate)
-      delete_breakpoint (b);
+      delete_breakpoint (b, 1);
 }
 
 struct breakpoint *
@@ -6054,7 +6072,7 @@ remove_thread_event_breakpoints (void)
   ALL_BREAKPOINTS_SAFE (b, b_tmp)
     if (b->type == bp_thread_event
 	&& b->loc->pspace == current_program_space)
-      delete_breakpoint (b);
+      delete_breakpoint (b, 1);
 }
 
 struct lang_and_radix
@@ -6085,7 +6103,7 @@ remove_jit_event_breakpoints (void)
   ALL_BREAKPOINTS_SAFE (b, b_tmp)
     if (b->type == bp_jit_event
 	&& b->loc->pspace == current_program_space)
-      delete_breakpoint (b);
+      delete_breakpoint (b, 1);
 }
 
 void
@@ -6096,7 +6114,7 @@ remove_solib_event_breakpoints (void)
   ALL_BREAKPOINTS_SAFE (b, b_tmp)
     if (b->type == bp_shlib_event
 	&& b->loc->pspace == current_program_space)
-      delete_breakpoint (b);
+      delete_breakpoint (b, 1);
 }
 
 struct breakpoint *
@@ -8789,6 +8807,7 @@ static void
 watch_command_1 (char *arg, int accessflag, int from_tty,
 		 int just_location, int internal)
 {
+  volatile struct gdb_exception e;
   struct breakpoint *b, *scope_breakpoint = NULL;
   struct expression *exp;
   struct block *exp_valid_block = NULL, *cond_exp_valid_block = NULL;
@@ -8800,9 +8819,7 @@ watch_command_1 (char *arg, int accessflag, int from_tty,
   int toklen;
   char *cond_start = NULL;
   char *cond_end = NULL;
-  int i, other_type_used, target_resources_ok = 0;
   enum bptype bp_type;
-  int reg_cnt = 0;
   int thread = -1;
   int pc = 0;
 
@@ -8932,28 +8949,6 @@ watch_command_1 (char *arg, int accessflag, int from_tty,
   else
     bp_type = bp_hardware_watchpoint;
 
-  reg_cnt = can_use_hardware_watchpoint (val, target_exact_watchpoints);
-  if (reg_cnt == 0 && bp_type != bp_hardware_watchpoint)
-    error (_("Expression cannot be implemented with read/access watchpoint."));
-  if (reg_cnt != 0)
-    {
-      i = hw_watchpoint_used_count (bp_type, &other_type_used);
-      target_resources_ok = 
-	target_can_use_hardware_watchpoint (bp_type, i + reg_cnt,
-					    other_type_used);
-      if (target_resources_ok == 0 && bp_type != bp_hardware_watchpoint)
-	error (_("Target does not support this type of hardware watchpoint."));
-
-      if (target_resources_ok < 0 && bp_type != bp_hardware_watchpoint)
-	error (_("Target can only support one kind "
-		 "of HW watchpoint at a time."));
-    }
-
-  /* Change the type of breakpoint to an ordinary watchpoint if a
-     hardware watchpoint could not be set.  */
-  if (!reg_cnt || target_resources_ok <= 0)
-    bp_type = bp_watchpoint;
-
   frame = block_innermost_frame (exp_valid_block);
 
   /* If the expression is "local", then set up a "watchpoint scope"
@@ -9022,10 +9017,6 @@ watch_command_1 (char *arg, int accessflag, int from_tty,
   b->val_valid = 1;
   b->ops = &watchpoint_breakpoint_ops;
 
-  /* Use an exact watchpoint when there's only one memory region to be
-     watched, and only one debug register is needed to watch it.  */
-  b->exact = target_exact_watchpoints && reg_cnt == 1;
-
   if (cond_start)
     b->cond_string = savestring (cond_start, cond_end - cond_start);
   else
@@ -9053,9 +9044,18 @@ watch_command_1 (char *arg, int accessflag, int from_tty,
   if (!just_location)
     value_free_to_mark (mark);
 
-  /* Finally update the new watchpoint.  This creates the locations
-     that should be inserted.  */
-  update_watchpoint (b, 1);
+  TRY_CATCH (e, RETURN_MASK_ALL)
+    {
+      /* Finally update the new watchpoint.  This creates the locations
+	 that should be inserted.  */
+      update_watchpoint (b, 1);
+    }
+  if (e.reason < 0)
+    {
+      delete_breakpoint (b, 0);
+      throw_exception (e);
+    }
+
   if (internal)
     /* Do not mention breakpoints with a negative number, but do
        notify observers.  */
@@ -9066,14 +9066,10 @@ watch_command_1 (char *arg, int accessflag, int from_tty,
 }
 
 /* Return count of debug registers needed to watch the given expression.
-   If EXACT_WATCHPOINTS is 1, then consider that only the address of
-   the start of the watched region will be monitored (i.e., all accesses
-   will be aligned).  This uses less debug registers on some targets.
-
    If the watchpoint cannot be handled in hardware return zero.  */
 
 static int
-can_use_hardware_watchpoint (struct value *v, int exact_watchpoints)
+can_use_hardware_watchpoint (struct value *v)
 {
   int found_memory_cnt = 0;
   struct value *head = v;
@@ -9129,7 +9125,7 @@ can_use_hardware_watchpoint (struct value *v, int exact_watchpoints)
 		  int len;
 		  int num_regs;
 
-		  len = (exact_watchpoints
+		  len = (target_exact_watchpoints
 			 && is_scalar_type_recursive (vtype))?
 		    1 : TYPE_LENGTH (value_type (v));
 
@@ -9245,9 +9241,9 @@ until_break_command_continuation (void *arg)
 {
   struct until_break_command_continuation_args *a = arg;
 
-  delete_breakpoint (a->breakpoint);
+  delete_breakpoint (a->breakpoint, 1);
   if (a->breakpoint2)
-    delete_breakpoint (a->breakpoint2);
+    delete_breakpoint (a->breakpoint2, 1);
   delete_longjmp_breakpoint (a->thread_num);
 }
 
@@ -9976,7 +9972,7 @@ clear_command (char *arg, int from_tty)
     {
       if (from_tty)
 	printf_unfiltered ("%d ", b->number);
-      delete_breakpoint (b);
+      delete_breakpoint (b, 1);
     }
   if (from_tty)
     putchar_unfiltered ('\n');
@@ -9995,12 +9991,12 @@ breakpoint_auto_delete (bpstat bs)
     if (bs->breakpoint_at
 	&& bs->breakpoint_at->disposition == disp_del
 	&& bs->stop)
-      delete_breakpoint (bs->breakpoint_at);
+      delete_breakpoint (bs->breakpoint_at, 1);
 
   ALL_BREAKPOINTS_SAFE (b, b_tmp)
   {
     if (b->disposition == disp_del_at_next_stop)
-      delete_breakpoint (b);
+      delete_breakpoint (b, 1);
   }
 }
 
@@ -10441,10 +10437,11 @@ bpstat_remove_breakpoint_callback (struct thread_info *th, void *data)
 }
 
 /* Delete a breakpoint and clean up all traces of it in the data
-   structures.  */
+   structures.  If ANNOUNCE is 1, then notifies observers that
+   the breakpoint was deleted.  */
 
 void
-delete_breakpoint (struct breakpoint *bpt)
+delete_breakpoint (struct breakpoint *bpt, int announce)
 {
   struct breakpoint *b;
 
@@ -10487,7 +10484,8 @@ delete_breakpoint (struct breakpoint *bpt)
       bpt->related_breakpoint = bpt;
     }
 
-  observer_notify_breakpoint_deleted (bpt->number);
+  if (announce)
+    observer_notify_breakpoint_deleted (bpt->number);
 
   if (breakpoint_chain == bpt)
     breakpoint_chain = bpt->next;
@@ -10544,7 +10542,7 @@ delete_breakpoint (struct breakpoint *bpt)
 static void
 do_delete_breakpoint_cleanup (void *b)
 {
-  delete_breakpoint (b);
+  delete_breakpoint (b, 1);
 }
 
 struct cleanup *
@@ -10559,7 +10557,7 @@ make_cleanup_delete_breakpoint (struct breakpoint *b)
 static void
 do_delete_breakpoint (struct breakpoint *b, void *ignore)
 {
-  delete_breakpoint (b);
+  delete_breakpoint (b, 1);
 }
 
 void
@@ -10610,7 +10608,7 @@ delete_command (char *arg, int from_tty)
 		&& b->type != bp_std_terminate_master
 		&& b->type != bp_exception_master
 		&& b->number >= 0)
-	      delete_breakpoint (b);
+	      delete_breakpoint (b, 1);
 	  }
 	}
     }
@@ -11073,7 +11071,7 @@ breakpoint_re_set_one (void *bint)
       if (b->addr_string == NULL)
 	{
 	  /* Anything without a string can't be re-set.  */
-	  delete_breakpoint (b);
+	  delete_breakpoint (b, 1);
 	  return 0;
 	}
 
@@ -11127,7 +11125,7 @@ breakpoint_re_set_one (void *bint)
     case bp_longjmp_master:
     case bp_std_terminate_master:
     case bp_exception_master:
-      delete_breakpoint (b);
+      delete_breakpoint (b, 1);
       break;
 
       /* This breakpoint is special, it's set up when the inferior
@@ -12114,7 +12112,7 @@ delete_trace_command (char *arg, int from_tty)
 	  {
 	    if (is_tracepoint (b)
 		&& b->number >= 0)
-	      delete_breakpoint (b);
+	      delete_breakpoint (b, 1);
 	  }
 	}
     }
diff --git a/gdb/breakpoint.h b/gdb/breakpoint.h
index 7a9c2d4..bf827e5 100644
--- a/gdb/breakpoint.h
+++ b/gdb/breakpoint.h
@@ -953,7 +953,7 @@ extern void breakpoint_init_inferior (enum inf_context);
 
 extern struct cleanup *make_cleanup_delete_breakpoint (struct breakpoint *);
 
-extern void delete_breakpoint (struct breakpoint *);
+extern void delete_breakpoint (struct breakpoint *, int);
 
 extern void breakpoint_auto_delete (bpstat);
 
diff --git a/gdb/elfread.c b/gdb/elfread.c
index 2d589a4..277a093 100644
--- a/gdb/elfread.c
+++ b/gdb/elfread.c
@@ -1036,7 +1036,7 @@ elf_gnu_ifunc_resolver_return_stop (struct breakpoint *b)
 	case bp_gnu_ifunc_resolver:
 	  break;
 	case bp_gnu_ifunc_resolver_return:
-	  delete_breakpoint (b);
+	  delete_breakpoint (b, 1);
 	  break;
 	default:
 	  internal_error (__FILE__, __LINE__,
diff --git a/gdb/infcmd.c b/gdb/infcmd.c
index 3dc13e3..f0e9d96 100644
--- a/gdb/infcmd.c
+++ b/gdb/infcmd.c
@@ -1501,7 +1501,7 @@ finish_command_continuation (void *arg)
      that the *stopped notification includes the return value.  */
   if (bs != NULL && tp->control.proceed_to_finish)
     observer_notify_normal_stop (bs, 1 /* print frame */);
-  delete_breakpoint (a->breakpoint);
+  delete_breakpoint (a->breakpoint, 1);
   delete_longjmp_breakpoint (inferior_thread ()->num);
 }
 
diff --git a/gdb/python/py-breakpoint.c b/gdb/python/py-breakpoint.c
index 0c21bfc..4450e60 100644
--- a/gdb/python/py-breakpoint.c
+++ b/gdb/python/py-breakpoint.c
@@ -302,7 +302,7 @@ bppy_delete_breakpoint (PyObject *self, PyObject *args)
 
   BPPY_REQUIRE_VALID (self_bp);
 
-  delete_breakpoint (self_bp->bp);
+  delete_breakpoint (self_bp->bp, 1);
 
   Py_RETURN_NONE;
 }
diff --git a/gdb/thread.c b/gdb/thread.c
index 6ad1807..929c335 100644
--- a/gdb/thread.c
+++ b/gdb/thread.c
@@ -87,7 +87,7 @@ delete_step_resume_breakpoint (struct thread_info *tp)
 {
   if (tp && tp->control.step_resume_breakpoint)
     {
-      delete_breakpoint (tp->control.step_resume_breakpoint);
+      delete_breakpoint (tp->control.step_resume_breakpoint, 1);
       tp->control.step_resume_breakpoint = NULL;
     }
 }
@@ -97,7 +97,7 @@ delete_exception_resume_breakpoint (struct thread_info *tp)
 {
   if (tp && tp->control.exception_resume_breakpoint)
     {
-      delete_breakpoint (tp->control.exception_resume_breakpoint);
+      delete_breakpoint (tp->control.exception_resume_breakpoint, 1);
       tp->control.exception_resume_breakpoint = NULL;
     }
 }


^ permalink raw reply	[flat|nested] 38+ messages in thread

* [RFA 1/3] Change watchpoint's enable state in do_enable_breakpoint
  2011-02-17 15:10 ` Ulrich Weigand
  2011-04-18 21:22   ` [RFA 2/3] Demote to sw watchpoint only in update_watchpoint Thiago Jung Bauermann
@ 2011-04-18 21:22   ` Thiago Jung Bauermann
  2011-04-29 17:21     ` Ulrich Weigand
  2011-04-18 21:24   ` [RFA 3/3] Implement support for PowerPC BookE masked watchpoints Thiago Jung Bauermann
  2 siblings, 1 reply; 38+ messages in thread
From: Thiago Jung Bauermann @ 2011-04-18 21:22 UTC (permalink / raw)
  To: Ulrich Weigand; +Cc: gdb-patches ml

Hi,

This patch changes watchpoint's enable state in do_enable_breakpoint
before calling update_watchpoint. It fixes a bug in the current code
which makes GDB change disabled hardware watchpoints to software
watchpoints when the inferior is restarted:

(gdb) watch a
Hardware watchpoint 2: a
(gdb) disable 2
(gdb) watch c
Hardware watchpoint 3: c
(gdb) disable 3
(gdb) watch d
Hardware watchpoint 4: d
(gdb) i b
Num     Type           Disp Enb Address            What
2       hw watchpoint  keep n                      a
3       hw watchpoint  keep n                      c
4       hw watchpoint  keep y                      d
(gdb) r
The program being debugged has been started already.
Start it from the beginning? (y or n) y
Starting program: /home/bauermann/builds/examples/test-watch64 
a = 1
a = 2
Hardware watchpoint 4: d

Old value = 97 'a'
New value = 120 'x'
main (argc=1, argv=0xfffffd46a78) at ../../src/examples/test-watch.c:54
54        c = 31;
(gdb) i b
Num     Type           Disp Enb Address            What
2       watchpoint     keep n                      a
3       watchpoint     keep n                      c
4       hw watchpoint  keep y                      d

Notice that 2 and 3 are now software watchpoints.
This doesn't matter much today since watchpoints can change back and
forth between software and hardware watchpoints, but for masked
watchpoints it's important because they can't be changed to software
watchpoints. If you have a disabled masked watchpoint and there are not
enough debug registers for it, GDB will report an error when restarting
the inferior even though the watchpoint is disabled.

Tested without regressions on ppc-linux, ppc64-linux and i386-linux. Ok?
-- 
[]'s
Thiago Jung Bauermann
IBM Linux Technology Center


2011-04-18  Thiago Jung Bauermann  <bauerman@br.ibm.com>

	* breakpoint.c (update_watchpoint): Move code to change
	the enable state of breakpoint from here ...
	(do_enable_breakpoint): ... to here.

diff --git a/gdb/breakpoint.c b/gdb/breakpoint.c
index 8ea6cc9..744057a 100644
--- a/gdb/breakpoint.c
+++ b/gdb/breakpoint.c
@@ -1416,7 +1416,6 @@ update_watchpoint (struct breakpoint *b, int reparse)
 	  if (reg_cnt)
 	    {
 	      int i, target_resources_ok, other_type_used;
-	      enum enable_state orig_enable_state;
 
 	      /* We need to determine how many resources are already
 		 used for all other hardware watchpoints plus this one
@@ -1427,17 +1426,9 @@ update_watchpoint (struct breakpoint *b, int reparse)
 		 watchpoint.  */
 	      b->type = bp_hardware_watchpoint;
 
-	      /* hw_watchpoint_used_count ignores disabled watchpoints,
-		 and b might be disabled if we're being called from
-		 do_enable_breakpoint.  */
-	      orig_enable_state = b->enable_state;
-	      b->enable_state = bp_enabled;
-
 	      i = hw_watchpoint_used_count (bp_hardware_watchpoint,
 					    &other_type_used);
 
-	      b->enable_state = orig_enable_state;
-
 	      target_resources_ok = target_can_use_hardware_watchpoint
 		    (bp_hardware_watchpoint, i, other_type_used);
 	      if (target_resources_ok <= 0)
@@ -11490,14 +11481,18 @@ do_enable_breakpoint (struct breakpoint *bpt, enum bpdisp disposition)
 
   if (is_watchpoint (bpt))
     {
+      enum enable_state orig_enable_state;
       struct gdb_exception e;
 
       TRY_CATCH (e, RETURN_MASK_ALL)
 	{
+	  orig_enable_state = bpt->enable_state;
+	  bpt->enable_state = bp_enabled;
 	  update_watchpoint (bpt, 1 /* reparse */);
 	}
       if (e.reason < 0)
 	{
+	  bpt->enable_state = orig_enable_state;
 	  exception_fprintf (gdb_stderr, e, _("Cannot enable watchpoint %d: "),
 			     bpt->number);
 	  return;


^ permalink raw reply	[flat|nested] 38+ messages in thread

* [RFA 3/3] Implement support for PowerPC BookE masked watchpoints
  2011-02-17 15:10 ` Ulrich Weigand
  2011-04-18 21:22   ` [RFA 2/3] Demote to sw watchpoint only in update_watchpoint Thiago Jung Bauermann
  2011-04-18 21:22   ` [RFA 1/3] Change watchpoint's enable state in do_enable_breakpoint Thiago Jung Bauermann
@ 2011-04-18 21:24   ` Thiago Jung Bauermann
  2011-04-29 17:46     ` Ulrich Weigand
  2 siblings, 1 reply; 38+ messages in thread
From: Thiago Jung Bauermann @ 2011-04-18 21:24 UTC (permalink / raw)
  To: Ulrich Weigand; +Cc: gdb-patches ml

Hi Uli,

Thanks for your review and suggestions!

[ This patch depends on two patches that I'm posting as replies to your
message too so that they'll be grouped together. ]

On Thu, 2011-02-17 at 15:40 +0100, Ulrich Weigand wrote:
> Thiago Jung Bauermann wrote:
> The effect is that GDB will parse the expression, create the list of
> memory regions it needs to watch to implement its high-level semantics.
> Then, it will just add the mask to each of the addresses generated
> in that manner.  It seems to me that in general, the effects of what
> will actually happen now are hard to predict, and will generally not
> be what the user expects.
> 
> Of course, the feature *can* be used in ways the user understands,
> like in the example you show in the documentation:
>    watch *0xdeadbeef mask 0xffffff00
> 
> But if used in a more complex way, like
>    watch p->x mask 0xffffff00
> for some local variable p, this doesn't seem to have very useful
> (or even well-defined) semantics ...

This isn't a problem for PowerPC because there are only two hardware
watchpoint registers, and both will be needed to set up a masked
watchpoint (one for the address, the other for the mask). So the command
you mention above would fail since it would need more registers than
that. But I agree that in general it's a problem.

> Now, I'm not sure how exactly the GDB command line syntax ought to
> be modified to implement this.  But most fundamentally, we should
> go away from specifying "the value of an expression", and rather
> go to specifying a memory region via address and mask.
> 
> We've recently added the -location feature that already prevents
> GDB from fully tracking the expression, but rather just evaluate
> it one time for its address.   Maybe one simple fix could be to
> restrict the "mask" feature to watch -location (or have the 
> presence of "mask" automatically imply -location, or maybe have
> instead a new keyword -masked-location or so).

-location is indeed a good fit for this patch. I don't think we need a
separate -masked-location keyword, so in this patch I made the mask
parameter imply -location. Do you think this addresses your concerns
regarding the semantics of masked watchpoints?

> However, even so there are still differences: even with -location,
> GDB watchpoint code will still treat a watchpoint as refering to
> one value, and track it (e.g. remember the value we saw last time;
> re-evaluate it each time execution stops etc.).  This is really
> not appropriate for the masked watchpoint case, because we do not
> *have* any contiguous region that would define any single value.
> Therefore, it seems to me that all this code ought to be disabled
> for masked watchpoints.

Indeed. With this new patch, the only place that evaluates the
watchpoint expression is update_watchpoint. This is necessary because
the resulting value chain is then used to create the bp_locations and
also by can_use_hardware_watchpoint when deciding whether to set a
software or hardware watchpoint.

I could manually create a bp_location for masked watchpoints and
implement a version of can_use_hardware_watchpoint just for masked
watchpoints, but is it worth the extra special casing and complexity in
update_watchpoint?

> A couple of more specific comments on the patch:
> 
> > @@ -1518,10 +1522,26 @@ update_watchpoint (struct breakpoint *b, int reparse)
> >  	      target_resources_ok = target_can_use_hardware_watchpoint
> >  		    (bp_hardware_watchpoint, i, other_type_used);
> >  	      if (target_resources_ok <= 0)
> > -		b->type = bp_watchpoint;
> > +		{
> > +		  if (orig_type == bp_hardware_watchpoint
> > +		      && b->ops && b->ops->works_in_software_mode
> > +		      && !b->ops->works_in_software_mode (b))
> > +		    error (_("This watchpoint cannot be used "
> > +			     "in software mode."));
> > +		  else
> > +		    b->type = bp_watchpoint;
> > +		}
> >  	    }
> >  	  else
> > -	    b->type = bp_watchpoint;
> > +	    {
> > +	      if (b->type == bp_hardware_watchpoint
> > +		  && b->ops && b->ops->works_in_software_mode
> > +		  && !b->ops->works_in_software_mode (b))
> > +		error (_("This watchpoint cannot be used "
> > +			 "in software mode."));
> > +	      else
> > +		b->type = bp_watchpoint;
> > +	    }
> 
> What is the point of checking the original type?  If works_in_software_mode
> returns false, the original type couldn't have been a software watchpoint
> anyway, could it?

Right, removed.

> >  	   print_it_typical.  */
> >  	/* FIXME: how breakpoint can ever be NULL here?  */
> >  	if (b != NULL && b->ops != NULL && b->ops->print_it != NULL)
> > -	  return b->ops->print_it (b);
> > +	  return b->ops->print_it (b, bs->old_val);
> >  	else
> >  	  return print_it_typical (bs);
> >        }
> 
> I don't understand this change.  You add the "old_val" argument to the
> print_it routine, and the new instance of print_it for masked watchpoints
> then uses it (for what purpose?) ...  But for masked watchpoints, the
> whole concept of its "value", new or old, doesn't make sense to start
> with ...

I added it for two reasons. First, because I thought it made sense to
make available to print_it implementations the same information that
print_it_typical uses itself. Also, I wasn't sure how important is this
code in print_it_masked_watchpoint which I borrowed from
print_it_typical:

+    case bp_access_watchpoint:
+      if (old_val != NULL)
+       annotate_watchpoint (b->number);

So I decided to keep it. In this version I removed the old_val argument
and the call to annotate_watchpoint.

> > @@ -3761,6 +3796,11 @@ watchpoint_check (void *p)
> >  	  b->val_valid = 1;
> >  	  return WP_VALUE_CHANGED;
> >  	}
> > +      else if (is_masked_watchpoint (b))
> > +	/* Since we don't know the exact trigger address (from
> > +	   stopped_data_address), just tell the user we've triggered
> > +	   a mask watchpoint.  */
> > +	return WP_VALUE_CHANGED;
> 
> This goes back to the issue discussed above: this should not even
> attempt to "compute the old value" which doesn't make sense for a
> masked watchpoint.  Instead, it should simply report a stop to the
> user whenever the hardware reports a hit.

Right. This was solved simply by doing the is_masked_watchpoint check
before fetching the watchpoint value.

> > +static void
> > +print_one_detail_masked_watchpoint (const struct breakpoint *b,
> > +				    struct ui_out *uiout)
> > +{
> > +  ui_out_text (uiout, "\tmask ");
> > +
> > +  /* I don't know whether it's possible to get here without a b->loc,
> > +     but we can handle the situation.  */
> > +  if (b->loc)
> > +    ui_out_field_core_addr (uiout, "mask", b->loc->gdbarch, b->hw_wp_mask);
> > +  else
> > +    ui_out_field_string (uiout, "mask", core_addr_to_string (b->hw_wp_mask));
> 
> I think we should enforce that there is always exactly one location on
> masked watchpoints, just like we do e.g. for catchpoints.

Ok, with -location now we are guaranteed to have only one location.
Fixed.

> > +/* Implement the "print_recreate" breakpoint_ops method for
> > +   masked hardware watchpoints.  */
> > +
> > +static void
> > +print_recreate_masked_watchpoint (struct breakpoint *b, struct ui_file *fp)
> > +{
> > +  char tmp[40];
> > +
> > +  switch (b->type)
> > +    {
> > +    case bp_hardware_watchpoint:
> > +      fprintf_unfiltered (fp, "watch");
> > +      break;
> > +    case bp_read_watchpoint:
> > +      fprintf_unfiltered (fp, "rwatch");
> > +      break;
> > +    case bp_access_watchpoint:
> > +      fprintf_unfiltered (fp, "awatch");
> > +      break;
> > +    default:
> > +      internal_error (__FILE__, __LINE__,
> > +		      _("Invalid hardware watchpoint type."));
> > +    }
> > +
> > +  sprintf_vma (tmp, b->hw_wp_mask);
> > +  fprintf_unfiltered (fp, " %s mask 0x%s", b->exp_string, tmp);
> 
> Depending on the discussion on command syntax this may need to change anyway,
> but even with the current syntax, it ignores any -location flag that may have
> been given initially ...

Since mask now implies -location, no change is needed here anymore.

> > @@ -8540,7 +8832,14 @@ watch_command_1 (char *arg, int accessflag, int from_tty,
> >      b->exp_string = savestring (exp_start, exp_end - exp_start);
> >    b->val = val;
> >    b->val_valid = 1;
> > -  b->ops = &watchpoint_breakpoint_ops;
> > +
> > +  if (use_mask)
> > +    {
> > +      b->hw_wp_mask = hw_wp_mask;
> > +      b->ops = &masked_watchpoint_breakpoint_ops;
> > +    }
> > +  else
> > +    b->ops = &watchpoint_breakpoint_ops;
> 
> We shouldn't compute an intial value or set val_valid for masked watchpoints.

Fixed.

> > +/* Insert a new masked watchpoint at ADDR using the mask MASK.
> > +   RW may be hw_read for a read watchpoint, hw_write for a write watchpoint
> > +   or hw_access for an access watchpoint.  Returns 0 on success and throws
> > +   an error on failure.  */
> > +
> > +static int
> > +ppc_linux_insert_mask_watchpoint (struct target_ops *ops, CORE_ADDR addr,
> > +				  CORE_ADDR mask, int rw)
> > +{
> > +  ptid_t ptid;
> > +  struct lwp_info *lp;
> > +  struct ppc_hw_breakpoint p;
> > +
> > +  gdb_assert (have_ptrace_booke_interface ());
> > +
> > +  if ((mask & 0xC0000000) != 0xC0000000)
> > +    error (_("\
> > +The given mask covers kernel address space and cannot be used.\n\
> > +You have to delete the masked watchpoint to continue the debugging session."));
> 
> Huh, this interface seems a bit odd.  Shouldn't such watchpoints be rejected
> right from the start, using something like the region_ok_for_watchpoint
> callback?
>
> > +/* Return the number of registers needed for a masked hardware watchpoint.  */
> > +
> > +static int
> > +ppc_linux_masked_watch_num_registers (struct target_ops *target)
> > +{
> > +  return ((have_ptrace_booke_interface ()
> > +	   && booke_debug_info.features & PPC_DEBUG_FEATURE_DATA_BP_MASK)?
> > +	  2 : -1);
> > +}
> 
> So maybe this interface ought to get parameters to be able to check
> whether specific watchpoints are valid?

Ok, it now gets an addr and mask parameter, and returns -2 if the region
is rejected.

> >        INHERIT (to_insert_watchpoint, t);
> >        INHERIT (to_remove_watchpoint, t);
> > +      /* Do not inherit to_insert_mask_watchpoint.  */
> > +      /* Do not inherit to_remove_mask_watchpoint.  */
> 
> Why should this differ between regular and masked watchpoints?  Shouldn't
> they either both use inheritance or none?

This was discussed and settled in the ranged watchpoints patch, so I
didn't change it here.

Tested without regressions on ppc-linux, ppc64-linux and i386-linux. Ok?
-- 
[]'s
Thiago Jung Bauermann
IBM Linux Technology Center


2011-04-18  Sergio Durigan Junior  <sergiodj@linux.vnet.ibm.com>
	    Thiago Jung Bauermann  <bauerman@br.ibm.com>

	Implement support for PowerPC BookE masked watchpoints.

gdb/
	*NEWS: Mention masked watchpoint support.  Create "Changed commands"
	section.
	* breakpoint.h (struct breakpoint_ops) <works_in_software_mode>: New
	method.  Initialize to NULL in all existing breakpoint_ops instances.
	(struct breakpoint) <hw_wp_mask>: New field.
	* breakpoint.c (is_masked_watchpoint): Add prototype.
	(update_watchpoint): Don't set b->val for masked watchpoints.  Call
	breakpoint's breakpoint_ops.works_in_software_mode if available.
	(watchpoints_triggered): Handle the case of a hardware masked
	watchpoint trigger.
	(watchpoint_check): Likewise.
	(works_in_software_mode_watchpoint): New function.
	(insert_masked_watchpoint, remove_masked_watchpoint)
	(resources_needed_masked_watchpoint)
	(works_in_software_mode_masked_watchpoint, print_it_masked_watchpoint)
	(print_one_detail_masked_watchpoint, print_mention_masked_watchpoint)
	(print_recreate_masked_watchpoint, is_masked_watchpoint): New
	functions.
	(masked_watchpoint_breakpoint_ops): New structure.
	(watch_command_1): Check for the existence of the `mask' parameter.
	Set b->ops according to the type of hardware watchpoint being created.
	* ppc-linux-nat.c (ppc_linux_insert_mask_watchpoint)
	(ppc_linux_remove_mask_watchpoint)
	(ppc_linux_masked_watch_num_registers): New functions.
	(_initialize_ppc_linux_nat): Initialize to_insert_mask_watchpoint,
	to_remove_mask_watchpoint and to_masked_watch_num_registers.
	* target.c (update_current_target): Mention to_insert_mask_watchpoint,
	to_remove_mask_watchpoint, and to_masked_watch_num_registers.
	(target_insert_mask_watchpoint, target_remove_mask_watchpoint)
	(target_masked_watch_num_registers): New functions.
	* target.h (struct target_ops) <to_insert_mask_watchpoint>,
	<to_remove_mask_watchpoint>, <to_masked_watch_num_registers>: New
	methods.
	(target_insert_mask_watchpoint, target_remove_mask_watchpoint)
	(target_masked_watch_num_registers): Add prototypes.

gdb/doc/
	* gdb.texinfo (Set Watchpoints): Document mask parameter.
	(PowerPC Embedded): Document masked watchpoints.


diff --git a/gdb/NEWS b/gdb/NEWS
index a673d7a..5a68154 100644
--- a/gdb/NEWS
+++ b/gdb/NEWS
@@ -3,6 +3,20 @@
 
 *** Changes since GDB 7.3
 
+* When natively debugging programs on PowerPC BookE processors running
+  a Linux kernel version 2.6.34 or later, GDB supports masked hardware
+  watchpoints, which specify a mask in addition to an address to watch.
+  The mask specifies that some bits of an address (the bits which are
+  reset in the mask) should be ignored when matching the address accessed
+  by the inferior against the watchpoint address.  See the "PowerPC Embedded"
+  section in the user manual for more details.
+
+* Changed commands
+
+watch EXPRESSION mask MASK_VALUE
+  The watch command now supports the mask argument which allows creation
+  of masked watchpoints, if the current architecture supports this feature.
+
 *** Changes in GDB 7.3
 
 * GDB has a new command: "thread find [REGEXP]".
diff --git a/gdb/ada-lang.c b/gdb/ada-lang.c
index 0a0b09f..c91df6f 100644
--- a/gdb/ada-lang.c
+++ b/gdb/ada-lang.c
@@ -10951,6 +10951,7 @@ static struct breakpoint_ops catch_exception_breakpoint_ops =
   NULL, /* remove */
   NULL, /* breakpoint_hit */
   NULL, /* resources_needed */
+  NULL, /* works_in_software_mode */
   print_it_catch_exception,
   print_one_catch_exception,
   NULL, /* print_one_detail */
@@ -10991,6 +10992,7 @@ static struct breakpoint_ops catch_exception_unhandled_breakpoint_ops = {
   NULL, /* remove */
   NULL, /* breakpoint_hit */
   NULL, /* resources_needed */
+  NULL, /* works_in_software_mode */
   print_it_catch_exception_unhandled,
   print_one_catch_exception_unhandled,
   NULL, /* print_one_detail */
@@ -11029,6 +11031,7 @@ static struct breakpoint_ops catch_assert_breakpoint_ops = {
   NULL, /* remove */
   NULL, /* breakpoint_hit */
   NULL, /* resources_needed */
+  NULL, /* works_in_software_mode */
   print_it_catch_assert,
   print_one_catch_assert,
   NULL, /* print_one_detail */
diff --git a/gdb/breakpoint.c b/gdb/breakpoint.c
index 2bfdfb0..7d01737 100644
--- a/gdb/breakpoint.c
+++ b/gdb/breakpoint.c
@@ -224,6 +224,8 @@ static void disable_trace_command (char *, int);
 
 static void trace_pass_command (char *, int);
 
+static int is_masked_watchpoint (const struct breakpoint *b);
+
 /* Assuming we're creating a static tracepoint, does S look like a
    static tracepoint marker spec ("-m MARKER_ID")?  */
 #define is_marker_spec(s)						\
@@ -1345,8 +1347,10 @@ update_watchpoint (struct breakpoint *b, int reparse)
       /* Avoid setting b->val if it's already set.  The meaning of
 	 b->val is 'the last value' user saw, and we should update
 	 it only if we reported that last value to user.  As it
-	 happens, the code that reports it updates b->val directly.  */
-      if (!b->val_valid)
+	 happens, the code that reports it updates b->val directly.
+	 We don't keep track of the memory value for masked
+	 watchpoints.  */
+      if (!b->val_valid && !is_masked_watchpoint (b))
 	{
 	  b->val = v;
 	  b->val_valid = 1;
@@ -1437,19 +1441,23 @@ update_watchpoint (struct breakpoint *b, int reparse)
 		    (bp_hardware_watchpoint, i, other_type_used);
 	      if (target_resources_ok <= 0)
 		{
-		  if (target_resources_ok == 0
-		      && b->type != bp_hardware_watchpoint)
+		  /* If there's no works_in_software_mode method, we
+		     assume that the watchpoint works in software mode.  */
+		  int sw_mode = (!b->ops || !b->ops->works_in_software_mode
+				 || b->ops->works_in_software_mode (b));
+
+		  if (target_resources_ok == 0 && !sw_mode)
 		    error (_("Target does not support this type of "
 			     "hardware watchpoint."));
-		  else if (target_resources_ok < 0
-		      && b->type != bp_hardware_watchpoint)
-		    error (_("Target can only support one kind "
-			     "of HW watchpoint at a time."));
+		  else if (target_resources_ok < 0 && !sw_mode)
+		    error (_("There are not enough available hardware "
+			     "resources for this watchpoint."));
 		  else
 		    b->type = bp_watchpoint;
 		}
 	    }
-	  else if (b->type != bp_hardware_watchpoint)
+	  else if (b->ops && b->ops->works_in_software_mode
+		   && !b->ops->works_in_software_mode (b))
 	    error (_("Expression cannot be implemented with "
 		     "read/access watchpoint."));
 	  else
@@ -3695,15 +3703,30 @@ watchpoints_triggered (struct target_waitstatus *ws)
 
 	b->watchpoint_triggered = watch_triggered_no;
 	for (loc = b->loc; loc; loc = loc->next)
-	  /* Exact match not required.  Within range is
-	     sufficient.  */
-	  if (target_watchpoint_addr_within_range (&current_target,
-						   addr, loc->address,
-						   loc->length))
-	    {
-	      b->watchpoint_triggered = watch_triggered_yes;
-	      break;
-	    }
+	  {
+	    CORE_ADDR newaddr, start;
+
+	    if (is_masked_watchpoint (loc->owner))
+	      {
+		newaddr = addr & loc->owner->hw_wp_mask;
+		start = loc->address & loc->owner->hw_wp_mask;
+	      }
+	    else
+	      {
+		newaddr = addr;
+		start = loc->address;
+	      }
+
+	    /* Exact match not required.  Within range is
+	       sufficient.  */
+	    if (target_watchpoint_addr_within_range (&current_target,
+						     newaddr, start,
+						     loc->length))
+	      {
+		b->watchpoint_triggered = watch_triggered_yes;
+		break;
+	      }
+	  }
       }
 
   return 1;
@@ -3800,9 +3823,16 @@ watchpoint_check (void *p)
          might be in the middle of evaluating a function call.  */
 
       int pc = 0;
-      struct value *mark = value_mark ();
+      struct value *mark;
       struct value *new_val;
 
+      if (is_masked_watchpoint (b))
+	/* Since we don't know the exact trigger address (from
+	   stopped_data_address), just tell the user we've triggered
+	   a mask watchpoint.  */
+	return WP_VALUE_CHANGED;
+
+      mark = value_mark ();
       fetch_subexp_value (b->exp, &pc, &new_val, NULL, NULL);
 
       /* We use value_equal_contents instead of value_equal because
@@ -6306,6 +6336,7 @@ static struct breakpoint_ops catch_fork_breakpoint_ops =
   remove_catch_fork,
   breakpoint_hit_catch_fork,
   NULL, /* resources_needed */
+  NULL, /* works_in_software_mode */
   print_it_catch_fork,
   print_one_catch_fork,
   NULL, /* print_one_detail */
@@ -6404,6 +6435,7 @@ static struct breakpoint_ops catch_vfork_breakpoint_ops =
   remove_catch_vfork,
   breakpoint_hit_catch_vfork,
   NULL, /* resources_needed */
+  NULL, /* works_in_software_mode */
   print_it_catch_vfork,
   print_one_catch_vfork,
   NULL, /* print_one_detail */
@@ -6691,6 +6723,7 @@ static struct breakpoint_ops catch_syscall_breakpoint_ops =
   remove_catch_syscall,
   breakpoint_hit_catch_syscall,
   NULL, /* resources_needed */
+  NULL, /* works_in_software_mode */
   print_it_catch_syscall,
   print_one_catch_syscall,
   NULL, /* print_one_detail */
@@ -6847,6 +6880,7 @@ static struct breakpoint_ops catch_exec_breakpoint_ops =
   remove_catch_exec,
   breakpoint_hit_catch_exec,
   NULL, /* resources_needed */
+  NULL, /* works_in_software_mode */
   print_it_catch_exec,
   print_one_catch_exec,
   NULL, /* print_one_detail */
@@ -8479,6 +8513,7 @@ static struct breakpoint_ops ranged_breakpoint_ops =
   NULL, /* remove */
   breakpoint_hit_ranged_breakpoint,
   resources_needed_ranged_breakpoint,
+  NULL, /* works_in_software_mode */
   print_it_ranged_breakpoint,
   print_one_ranged_breakpoint,
   print_one_detail_ranged_breakpoint,
@@ -8785,6 +8820,15 @@ resources_needed_watchpoint (const struct bp_location *bl)
   return target_region_ok_for_hw_watchpoint (bl->address, length);
 }
 
+/* Implement the "works_in_software_mode" breakpoint_ops method for
+   hardware watchpoints.  */
+
+int
+works_in_software_mode_watchpoint (const struct breakpoint *b)
+{
+  return b->type == bp_hardware_watchpoint;
+}
+
 /* The breakpoint_ops structure to be used in hardware watchpoints.  */
 
 static struct breakpoint_ops watchpoint_breakpoint_ops =
@@ -8793,6 +8837,7 @@ static struct breakpoint_ops watchpoint_breakpoint_ops =
   remove_watchpoint,
   NULL, /* breakpoint_hit */
   resources_needed_watchpoint,
+  works_in_software_mode_watchpoint,
   NULL, /* print_it */
   NULL, /* print_one */
   NULL, /* print_one_detail */
@@ -8800,6 +8845,200 @@ static struct breakpoint_ops watchpoint_breakpoint_ops =
   NULL  /* print_recreate */
 };
 
+/* Implement the "insert" breakpoint_ops method for
+   masked hardware watchpoints.  */
+
+static int
+insert_masked_watchpoint (struct bp_location *bl)
+{
+  return target_insert_mask_watchpoint (bl->address, bl->owner->hw_wp_mask,
+					bl->watchpoint_type);
+}
+
+/* Implement the "remove" breakpoint_ops method for
+   masked hardware watchpoints.  */
+
+static int
+remove_masked_watchpoint (struct bp_location *bl)
+{
+  return target_remove_mask_watchpoint (bl->address, bl->owner->hw_wp_mask,
+				        bl->watchpoint_type);
+}
+
+/* Implement the "resources_needed" breakpoint_ops method for
+   masked hardware watchpoints.  */
+
+static int
+resources_needed_masked_watchpoint (const struct bp_location *bl)
+{
+  return target_masked_watch_num_registers (bl->address,
+					    bl->owner->hw_wp_mask);
+}
+
+/* Implement the "works_in_software_mode" breakpoint_ops method for
+   masked hardware watchpoints.  */
+
+static int
+works_in_software_mode_masked_watchpoint (const struct breakpoint *b)
+{
+  return 0;
+}
+
+/* Implement the "print_it" breakpoint_ops method for
+   masked hardware watchpoints.  */
+
+static enum print_stop_action
+print_it_masked_watchpoint (struct breakpoint *b)
+{
+  struct ui_stream *stb;
+  struct cleanup *old_chain;
+
+  /* Masked watchpoints have only one location.  */
+  gdb_assert (b->loc && b->loc->next == NULL);
+
+  stb = ui_out_stream_new (uiout);
+  old_chain = make_cleanup_ui_out_stream_delete (stb);
+
+  switch (b->type)
+    {
+    case bp_hardware_watchpoint:
+      annotate_watchpoint (b->number);
+      if (ui_out_is_mi_like_p (uiout))
+	ui_out_field_string
+	  (uiout, "reason",
+	   async_reason_lookup (EXEC_ASYNC_WATCHPOINT_TRIGGER));
+      break;
+
+    case bp_read_watchpoint:
+      if (ui_out_is_mi_like_p (uiout))
+	ui_out_field_string
+	  (uiout, "reason",
+	   async_reason_lookup (EXEC_ASYNC_READ_WATCHPOINT_TRIGGER));
+      break;
+
+    case bp_access_watchpoint:
+      if (ui_out_is_mi_like_p (uiout))
+	ui_out_field_string
+	  (uiout, "reason",
+	   async_reason_lookup (EXEC_ASYNC_ACCESS_WATCHPOINT_TRIGGER));
+      break;
+    default:
+      internal_error (__FILE__, __LINE__,
+		      _("Invalid hardware watchpoint type."));
+    }
+
+  mention (b);
+  ui_out_text (uiout, _("\n\
+Check the underlying instruction at PC for the memory\n\
+address and value which triggered this watchpoint.\n"));
+  ui_out_text (uiout, "\n");
+
+  do_cleanups (old_chain);
+
+  /* More than one watchpoint may have been triggered.  */
+  return PRINT_UNKNOWN;
+}
+
+/* Implement the "print_one_detail" breakpoint_ops method for
+   masked hardware watchpoints.  */
+
+static void
+print_one_detail_masked_watchpoint (const struct breakpoint *b,
+				    struct ui_out *uiout)
+{
+  /* Masked watchpoints have only one location.  */
+  gdb_assert (b->loc && b->loc->next == NULL);
+
+  ui_out_text (uiout, "\tmask ");
+  ui_out_field_core_addr (uiout, "mask", b->loc->gdbarch, b->hw_wp_mask);
+  ui_out_text (uiout, "\n");
+}
+
+/* Implement the "print_mention" breakpoint_ops method for
+   masked hardware watchpoints.  */
+
+static void
+print_mention_masked_watchpoint (struct breakpoint *b)
+{
+  struct cleanup *ui_out_chain;
+
+  switch (b->type)
+    {
+    case bp_hardware_watchpoint:
+      ui_out_text (uiout, "Masked hardware watchpoint ");
+      ui_out_chain = make_cleanup_ui_out_tuple_begin_end (uiout, "wpt");
+      break;
+    case bp_read_watchpoint:
+      ui_out_text (uiout, "Masked hardware read watchpoint ");
+      ui_out_chain = make_cleanup_ui_out_tuple_begin_end (uiout, "hw-rwpt");
+      break;
+    case bp_access_watchpoint:
+      ui_out_text (uiout, "Masked hardware access (read/write) watchpoint ");
+      ui_out_chain = make_cleanup_ui_out_tuple_begin_end (uiout, "hw-awpt");
+      break;
+    default:
+      internal_error (__FILE__, __LINE__,
+		      _("Invalid hardware watchpoint type."));
+    }
+
+  ui_out_field_int (uiout, "number", b->number);
+  ui_out_text (uiout, ": ");
+  ui_out_field_string (uiout, "exp", b->exp_string);
+  do_cleanups (ui_out_chain);
+}
+
+/* Implement the "print_recreate" breakpoint_ops method for
+   masked hardware watchpoints.  */
+
+static void
+print_recreate_masked_watchpoint (struct breakpoint *b, struct ui_file *fp)
+{
+  char tmp[40];
+
+  switch (b->type)
+    {
+    case bp_hardware_watchpoint:
+      fprintf_unfiltered (fp, "watch");
+      break;
+    case bp_read_watchpoint:
+      fprintf_unfiltered (fp, "rwatch");
+      break;
+    case bp_access_watchpoint:
+      fprintf_unfiltered (fp, "awatch");
+      break;
+    default:
+      internal_error (__FILE__, __LINE__,
+		      _("Invalid hardware watchpoint type."));
+    }
+
+  sprintf_vma (tmp, b->hw_wp_mask);
+  fprintf_unfiltered (fp, " %s mask 0x%s", b->exp_string, tmp);
+}
+
+/* The breakpoint_ops structure to be used in masked hardware watchpoints.  */
+
+static struct breakpoint_ops masked_watchpoint_breakpoint_ops =
+{
+  insert_masked_watchpoint,
+  remove_masked_watchpoint,
+  NULL, /* breakpoint_hit */
+  resources_needed_masked_watchpoint,
+  works_in_software_mode_masked_watchpoint,
+  print_it_masked_watchpoint,
+  NULL, /* print_one */
+  print_one_detail_masked_watchpoint,
+  print_mention_masked_watchpoint,
+  print_recreate_masked_watchpoint
+};
+
+/* Tell whether the given watchpoint is a masked hardware watchpoint.  */
+
+static int
+is_masked_watchpoint (const struct breakpoint *b)
+{
+  return b->ops == &masked_watchpoint_breakpoint_ops;
+}
+
 /* accessflag:  hw_write:  watch write, 
                 hw_read:   watch read, 
 		hw_access: watch access (read or write) */
@@ -8815,73 +9054,97 @@ watch_command_1 (char *arg, int accessflag, int from_tty,
   struct frame_info *frame;
   char *exp_start = NULL;
   char *exp_end = NULL;
-  char *tok, *id_tok_start, *end_tok;
-  int toklen;
+  char *tok, *end_tok;
+  int toklen = -1;
   char *cond_start = NULL;
   char *cond_end = NULL;
   enum bptype bp_type;
   int thread = -1;
   int pc = 0;
+  /* Flag to indicate whether we are going to use masks for
+     the hardware watchpoint.  */
+  int use_mask = 0;
+  CORE_ADDR mask = 0;
 
   /* Make sure that we actually have parameters to parse.  */
   if (arg != NULL && arg[0] != '\0')
     {
-      toklen = strlen (arg); /* Size of argument list.  */
+      char *value_start;
 
-      /* Points tok to the end of the argument list.  */
-      tok = arg + toklen - 1;
+      /* Look for "parameter value" pairs at the end
+	 of the arguments string.  */
+      for (tok = arg + strlen (arg) - 1; tok > arg; tok--)
+	{
+	  /* Skip whitespace at the end of the argument list.  */
+	  while (tok > arg && (*tok == ' ' || *tok == '\t'))
+	    tok--;
+
+	  /* Find the beginning of the last token.
+	     This is the value of the parameter.  */
+	  while (tok > arg && (*tok != ' ' && *tok != '\t'))
+	    tok--;
+	  value_start = tok + 1;
+
+	  /* Skip whitespace.  */
+	  while (tok > arg && (*tok == ' ' || *tok == '\t'))
+	    tok--;
+
+	  end_tok = tok;
+
+	  /* Find the beginning of the second to last token.
+	     This is the parameter itself.  */
+	  while (tok > arg && (*tok != ' ' && *tok != '\t'))
+	    tok--;
+	  tok++;
+	  toklen = end_tok - tok + 1;
+
+	  if (toklen == 6 && !strncmp (tok, "thread", 6))
+	    {
+	      /* At this point we've found a "thread" token, which means
+		 the user is trying to set a watchpoint that triggers
+		 only in a specific thread.  */
+	      char *endp;
 
-      /* Go backwards in the parameters list.  Skip the last
-         parameter.  If we're expecting a 'thread <thread_num>'
-         parameter, this should be the thread identifier.  */
-      while (tok > arg && (*tok == ' ' || *tok == '\t'))
-        tok--;
-      while (tok > arg && (*tok != ' ' && *tok != '\t'))
-        tok--;
+	      if (thread != -1)
+		error(_("You can specify only one thread."));
 
-      /* Points end_tok to the beginning of the last token.  */
-      id_tok_start = tok + 1;
+	      /* Extract the thread ID from the next token.  */
+	      thread = strtol (value_start, &endp, 0);
 
-      /* Go backwards in the parameters list.  Skip one more
-         parameter.  If we're expecting a 'thread <thread_num>'
-         parameter, we should reach a "thread" token.  */
-      while (tok > arg && (*tok == ' ' || *tok == '\t'))
-        tok--;
+	      /* Check if the user provided a valid numeric value for the
+		 thread ID.  */
+	      if (*endp != ' ' && *endp != '\t' && *endp != '\0')
+		error (_("Invalid thread ID specification %s."), value_start);
 
-      end_tok = tok;
+	      /* Check if the thread actually exists.  */
+	      if (!valid_thread_id (thread))
+		error (_("Unknown thread %d."), thread);
+	    }
+	  else if (toklen == 4 && !strncmp (tok, "mask", 4))
+	    {
+	      /* We've found a "mask" token, which means the user wants to
+		 create a hardware watchpoint that is going to have the mask
+		 facility.  */
+	      struct value *mask_value, *mark;
 
-      while (tok > arg && (*tok != ' ' && *tok != '\t'))
-        tok--;
+	      if (use_mask)
+		error(_("You can specify only one mask."));
 
-      /* Move the pointer forward to skip the whitespace and
-         calculate the length of the token.  */
-      tok++;
-      toklen = end_tok - tok;
+	      use_mask = just_location = 1;
 
-      if (toklen >= 1 && strncmp (tok, "thread", toklen) == 0)
-        {
-          /* At this point we've found a "thread" token, which means
-             the user is trying to set a watchpoint that triggers
-             only in a specific thread.  */
-          char *endp;
-
-          /* Extract the thread ID from the next token.  */
-          thread = strtol (id_tok_start, &endp, 0);
-
-          /* Check if the user provided a valid numeric value for the
-             thread ID.  */
-          if (*endp != ' ' && *endp != '\t' && *endp != '\0')
-            error (_("Invalid thread ID specification %s."), id_tok_start);
-
-          /* Check if the thread actually exists.  */
-          if (!valid_thread_id (thread))
-            error (_("Unknown thread %d."), thread);
-
-          /* Truncate the string and get rid of the thread <thread_num>
-             parameter before the parameter list is parsed by the
-             evaluate_expression() function.  */
-          *tok = '\0';
-        }
+	      mark = value_mark ();
+	      mask_value = parse_to_comma_and_eval (&value_start);
+	      mask = value_as_address (mask_value);
+	      value_free_to_mark (mark);
+	    }
+	  else
+	    /* We didn't recognize what we found.  We should stop here.  */
+	    break;
+
+	  /* Truncate the string and get rid of the "parameter value" pair before
+	     the arguments string is parsed by the parse_exp_1 function.  */
+	  *tok = '\0';
+	}
     }
 
   /* Parse the rest of the arguments.  */
@@ -8912,10 +9175,22 @@ watch_command_1 (char *arg, int accessflag, int from_tty,
 
   if (just_location)
     {
+      int ret;
+
       exp_valid_block = NULL;
       val = value_addr (result);
       release_value (val);
       value_free_to_mark (mark);
+
+      if (use_mask)
+	{
+	  ret = target_masked_watch_num_registers (value_as_address (val),
+						   mask);
+	  if (ret == -1)
+	    error (_("This target does not support masked watchpoints."));
+	  else if (ret == -2)
+	    error (_("Invalid mask or memory region."));
+	}
     }
   else if (val != NULL)
     release_value (val);
@@ -9013,9 +9288,18 @@ watch_command_1 (char *arg, int accessflag, int from_tty,
     }
   else
     b->exp_string = savestring (exp_start, exp_end - exp_start);
-  b->val = val;
-  b->val_valid = 1;
-  b->ops = &watchpoint_breakpoint_ops;
+
+  if (use_mask)
+    {
+      b->hw_wp_mask = mask;
+      b->ops = &masked_watchpoint_breakpoint_ops;
+    }
+  else
+    {
+      b->val = val;
+      b->val_valid = 1;
+      b->ops = &watchpoint_breakpoint_ops;
+    }
 
   if (cond_start)
     b->cond_string = savestring (cond_start, cond_end - cond_start);
@@ -9550,6 +9834,7 @@ static struct breakpoint_ops gnu_v3_exception_catchpoint_ops = {
   NULL, /* remove */
   NULL, /* breakpoint_hit */
   NULL, /* resources_needed */
+  NULL, /* works_in_software_mode */
   print_it_exception_catchpoint,
   print_one_exception_catchpoint,
   NULL, /* print_one_detail */
diff --git a/gdb/breakpoint.h b/gdb/breakpoint.h
index bf827e5..ccd7c3c 100644
--- a/gdb/breakpoint.h
+++ b/gdb/breakpoint.h
@@ -410,6 +410,11 @@ struct breakpoint_ops
      the breakpoint or watchpoint needs one debug register.  */
   int (*resources_needed) (const struct bp_location *);
 
+  /* Tell whether we can downgrade from a hardware watchpoint to a software
+     one.  If not, the user will not be able to enable the watchpoint when
+     there are not enough hardware resources available.  */
+  int (*works_in_software_mode) (const struct breakpoint *);
+
   /* The normal print routine for this breakpoint, called when we
      hit it.  */
   enum print_stop_action (*print_it) (struct breakpoint *);
@@ -651,6 +656,9 @@ struct breakpoint
 
     /* Whether this watchpoint is exact (see target_exact_watchpoints).  */
     int exact;
+
+    /* The mask address for a masked hardware watchpoint.  */
+    CORE_ADDR hw_wp_mask;
   };
 
 typedef struct breakpoint *breakpoint_p;
diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo
index c71d664..b1fb0ff 100644
--- a/gdb/doc/gdb.texinfo
+++ b/gdb/doc/gdb.texinfo
@@ -3727,7 +3727,7 @@ watchpoints, which do not slow down the running of your program.
 
 @table @code
 @kindex watch
-@item watch @r{[}-l@r{|}-location@r{]} @var{expr} @r{[}thread @var{threadnum}@r{]}
+@item watch @r{[}-l@r{|}-location@r{]} @var{expr} @r{[}thread @var{threadnum}@r{]} @r{[}mask @var{maskvalue}@r{]}
 Set a watchpoint for an expression.  @value{GDBN} will break when the
 expression @var{expr} is written into by the program and its value
 changes.  The simplest (and the most popular) use of this command is
@@ -3738,12 +3738,17 @@ to watch the value of a single variable:
 @end smallexample
 
 If the command includes a @code{@r{[}thread @var{threadnum}@r{]}}
-clause, @value{GDBN} breaks only when the thread identified by
+argument, @value{GDBN} breaks only when the thread identified by
 @var{threadnum} changes the value of @var{expr}.  If any other threads
 change the value of @var{expr}, @value{GDBN} will not break.  Note
 that watchpoints restricted to a single thread in this way only work
 with Hardware Watchpoints.
 
+The @code{@r{[}mask @var{maskvalue}@r{]}} argument allows creation
+of masked watchpoints, if the current architecture supports this
+feature.  (Currently, this is only available on PowerPC Embedded
+architecture, see @ref{PowerPC Embedded}.)
+
 Ordinarily a watchpoint respects the scope of variables in @var{expr}
 (see below).  The @code{-location} argument tells @value{GDBN} to
 instead watch the memory referred to by @var{expr}.  In this case,
@@ -3754,12 +3759,12 @@ result does not have an address, then @value{GDBN} will print an
 error.
 
 @kindex rwatch
-@item rwatch @r{[}-l@r{|}-location@r{]} @var{expr} @r{[}thread @var{threadnum}@r{]}
+@item rwatch @r{[}-l@r{|}-location@r{]} @var{expr} @r{[}thread @var{threadnum}@r{]} @r{[}mask @var{maskvalue}@r{]}
 Set a watchpoint that will break when the value of @var{expr} is read
 by the program.
 
 @kindex awatch
-@item awatch @r{[}-l@r{|}-location@r{]} @var{expr} @r{[}thread @var{threadnum}@r{]}
+@item awatch @r{[}-l@r{|}-location@r{]} @var{expr} @r{[}thread @var{threadnum}@r{]} @r{[}mask @var{maskvalue}@r{]}
 Set a watchpoint that will break when @var{expr} is either read from
 or written into by the program.
 
@@ -18742,6 +18747,23 @@ region using one of the following commands (@pxref{Expressions}):
 (@value{GDBP}) watch @{char[@var{length}]@} @var{address}
 @end smallexample
 
+PowerPC embedded processors support masked watchpoints.
+
+A @dfn{masked watchpoint} specifies a mask in addition to an address
+to watch.  The mask specifies that some bits of an address (the bits
+which are reset in the mask) should be ignored when matching the
+address accessed by the inferior against the watchpoint address.
+Thus, a masked watchpoint watches many addresses
+simultaneously---those addresses whose unmasked bits are identical
+to the unmasked bits in the watchpoint address.
+
+To set a masked watchpoint in @value{GDBN}, use the @code{mask} argument in
+the @code{watch} command (@pxref{Set Watchpoints}), as in:
+
+@smallexample
+(@value{GDBP}) watch *0xdeadbeef mask 0xffffff00
+@end smallexample
+
 @cindex ranged breakpoint
 PowerPC embedded processors support hardware accelerated
 @dfn{ranged breakpoints}.  A ranged breakpoint stops execution of
diff --git a/gdb/ppc-linux-nat.c b/gdb/ppc-linux-nat.c
index 6f11715..d20a288 100644
--- a/gdb/ppc-linux-nat.c
+++ b/gdb/ppc-linux-nat.c
@@ -1739,6 +1739,64 @@ get_trigger_type (int rw)
   return t;
 }
 
+/* Insert a new masked watchpoint at ADDR using the mask MASK.
+   RW may be hw_read for a read watchpoint, hw_write for a write watchpoint
+   or hw_access for an access watchpoint.  Returns 0 on success and throws
+   an error on failure.  */
+
+static int
+ppc_linux_insert_mask_watchpoint (struct target_ops *ops, CORE_ADDR addr,
+				  CORE_ADDR mask, int rw)
+{
+  ptid_t ptid;
+  struct lwp_info *lp;
+  struct ppc_hw_breakpoint p;
+
+  gdb_assert (have_ptrace_booke_interface ());
+
+  p.version = PPC_DEBUG_CURRENT_VERSION;
+  p.trigger_type = get_trigger_type (rw);
+  p.addr_mode = PPC_BREAKPOINT_MODE_MASK;
+  p.condition_mode = PPC_BREAKPOINT_CONDITION_NONE;
+  p.addr = addr;
+  p.addr2 = mask;
+  p.condition_value = 0;
+
+  ALL_LWPS (lp, ptid)
+    booke_insert_point (&p, TIDGET (ptid));
+
+  return 0;
+}
+
+/* Remove a masked watchpoint at ADDR with the mask MASK.
+   RW may be hw_read for a read watchpoint, hw_write for a write watchpoint
+   or hw_access for an access watchpoint.  Returns 0 on success and throws
+   an error on failure.  */
+
+static int
+ppc_linux_remove_mask_watchpoint (struct target_ops *ops, CORE_ADDR addr,
+				  CORE_ADDR mask, int rw)
+{
+  ptid_t ptid;
+  struct lwp_info *lp;
+  struct ppc_hw_breakpoint p;
+
+  gdb_assert (have_ptrace_booke_interface ());
+
+  p.version = PPC_DEBUG_CURRENT_VERSION;
+  p.trigger_type = get_trigger_type (rw);
+  p.addr_mode = PPC_BREAKPOINT_MODE_MASK;
+  p.condition_mode = PPC_BREAKPOINT_CONDITION_NONE;
+  p.addr = addr;
+  p.addr2 = mask;
+  p.condition_value = 0;
+
+  ALL_LWPS (lp, ptid)
+    booke_remove_point (&p, TIDGET (ptid));
+
+  return 0;
+}
+
 /* Check whether we have at least one free DVC register.  */
 static int
 can_use_watchpoint_cond_accel (void)
@@ -2224,6 +2282,27 @@ ppc_linux_watchpoint_addr_within_range (struct target_ops *target,
   return start <= addr + mask && start + length - 1 >= addr;
 }
 
+/* Return the number of registers needed for a masked hardware watchpoint.  */
+
+static int
+ppc_linux_masked_watch_num_registers (struct target_ops *target,
+				      CORE_ADDR addr, CORE_ADDR mask)
+{
+  if (!have_ptrace_booke_interface ()
+	   || (booke_debug_info.features & PPC_DEBUG_FEATURE_DATA_BP_MASK) == 0)
+    return -1;
+  else if ((mask & 0xC0000000) != 0xC0000000)
+    {
+      warning (_("\
+The given mask covers kernel address space and cannot be used.\n\
+You have to delete the masked watchpoint to continue the debugging session."));
+
+      return -2;
+    }
+  else
+    return 2;
+}
+
 static void
 ppc_linux_store_inferior_registers (struct target_ops *ops,
 				    struct regcache *regcache, int regno)
@@ -2438,11 +2517,14 @@ _initialize_ppc_linux_nat (void)
   t->to_region_ok_for_hw_watchpoint = ppc_linux_region_ok_for_hw_watchpoint;
   t->to_insert_watchpoint = ppc_linux_insert_watchpoint;
   t->to_remove_watchpoint = ppc_linux_remove_watchpoint;
+  t->to_insert_mask_watchpoint = ppc_linux_insert_mask_watchpoint;
+  t->to_remove_mask_watchpoint = ppc_linux_remove_mask_watchpoint;
   t->to_stopped_by_watchpoint = ppc_linux_stopped_by_watchpoint;
   t->to_stopped_data_address = ppc_linux_stopped_data_address;
   t->to_watchpoint_addr_within_range = ppc_linux_watchpoint_addr_within_range;
   t->to_can_accel_watchpoint_condition
     = ppc_linux_can_accel_watchpoint_condition;
+  t->to_masked_watch_num_registers = ppc_linux_masked_watch_num_registers;
   t->to_ranged_break_num_registers = ppc_linux_ranged_break_num_registers;
 
   t->to_read_description = ppc_linux_read_description;
diff --git a/gdb/target.c b/gdb/target.c
index a032052..5028247 100644
--- a/gdb/target.c
+++ b/gdb/target.c
@@ -597,6 +597,8 @@ update_current_target (void)
       /* Do not inherit to_ranged_break_num_registers.  */
       INHERIT (to_insert_watchpoint, t);
       INHERIT (to_remove_watchpoint, t);
+      /* Do not inherit to_insert_mask_watchpoint.  */
+      /* Do not inherit to_remove_mask_watchpoint.  */
       INHERIT (to_stopped_data_address, t);
       INHERIT (to_have_steppable_watchpoint, t);
       INHERIT (to_have_continuable_watchpoint, t);
@@ -604,6 +606,7 @@ update_current_target (void)
       INHERIT (to_watchpoint_addr_within_range, t);
       INHERIT (to_region_ok_for_hw_watchpoint, t);
       INHERIT (to_can_accel_watchpoint_condition, t);
+      /* Do not inherit to_masked_watch_num_registers.  */
       INHERIT (to_terminal_init, t);
       INHERIT (to_terminal_inferior, t);
       INHERIT (to_terminal_ours_for_output, t);
@@ -3492,6 +3495,75 @@ target_verify_memory (const gdb_byte *data, CORE_ADDR memaddr, ULONGEST size)
   tcomplain ();
 }
 
+/* The documentation for this function is in its prototype declaration in
+   target.h.  */
+
+int
+target_insert_mask_watchpoint (CORE_ADDR addr, CORE_ADDR mask, int rw)
+{
+  struct target_ops *t;
+
+  for (t = current_target.beneath; t != NULL; t = t->beneath)
+    if (t->to_insert_mask_watchpoint != NULL)
+      {
+	int ret;
+
+	ret = t->to_insert_mask_watchpoint (t, addr, mask, rw);
+
+	if (targetdebug)
+	  fprintf_unfiltered (gdb_stdlog, "\
+target_insert_mask_watchpoint (%s, %s, %d) = %d\n",
+			      core_addr_to_string (addr),
+			      core_addr_to_string (mask), rw, ret);
+
+	return ret;
+      }
+
+  return 1;
+}
+
+/* The documentation for this function is in its prototype declaration in
+   target.h.  */
+
+int
+target_remove_mask_watchpoint (CORE_ADDR addr, CORE_ADDR mask, int rw)
+{
+  struct target_ops *t;
+
+  for (t = current_target.beneath; t != NULL; t = t->beneath)
+    if (t->to_remove_mask_watchpoint != NULL)
+      {
+	int ret;
+
+	ret = t->to_remove_mask_watchpoint (t, addr, mask, rw);
+
+	if (targetdebug)
+	  fprintf_unfiltered (gdb_stdlog, "\
+target_remove_mask_watchpoint (%s, %s, %d) = %d\n",
+			      core_addr_to_string (addr),
+			      core_addr_to_string (mask), rw, ret);
+
+	return ret;
+      }
+
+  return 1;
+}
+
+/* The documentation for this function is in its prototype declaration
+   in target.h.  */
+
+int
+target_masked_watch_num_registers (CORE_ADDR addr, CORE_ADDR mask)
+{
+  struct target_ops *t;
+
+  for (t = current_target.beneath; t != NULL; t = t->beneath)
+    if (t->to_masked_watch_num_registers != NULL)
+      return t->to_masked_watch_num_registers (t, addr, mask);
+
+  return -1;
+}
+
 /* The documentation for this function is in its prototype declaration
    in target.h.  */
 
diff --git a/gdb/target.h b/gdb/target.h
index f0b2e43..ef15022 100644
--- a/gdb/target.h
+++ b/gdb/target.h
@@ -459,6 +459,10 @@ struct target_ops
     int (*to_remove_watchpoint) (CORE_ADDR, int, int, struct expression *);
     int (*to_insert_watchpoint) (CORE_ADDR, int, int, struct expression *);
 
+    int (*to_insert_mask_watchpoint) (struct target_ops *,
+				      CORE_ADDR, CORE_ADDR, int);
+    int (*to_remove_mask_watchpoint) (struct target_ops *,
+				      CORE_ADDR, CORE_ADDR, int);
     int (*to_stopped_by_watchpoint) (void);
     int to_have_steppable_watchpoint;
     int to_have_continuable_watchpoint;
@@ -472,6 +476,8 @@ struct target_ops
 
     int (*to_can_accel_watchpoint_condition) (CORE_ADDR, int, int,
 					      struct expression *);
+    int (*to_masked_watch_num_registers) (struct target_ops *,
+					  CORE_ADDR, CORE_ADDR);
     void (*to_terminal_init) (void);
     void (*to_terminal_inferior) (void);
     void (*to_terminal_ours_for_output) (void);
@@ -1349,6 +1355,20 @@ extern char *target_thread_name (struct thread_info *);
 #define	target_remove_watchpoint(addr, len, type, cond) \
      (*current_target.to_remove_watchpoint) (addr, len, type, cond)
 
+/* Insert a new masked watchpoint at ADDR using the mask MASK.
+   RW may be hw_read for a read watchpoint, hw_write for a write watchpoint
+   or hw_access for an access watchpoint.  Returns 0 for success, 1 if
+   masked watchpoints are not supported, -1 for failure.  */
+
+extern int target_insert_mask_watchpoint (CORE_ADDR, CORE_ADDR, int);
+
+/* Remove a masked watchpoint at ADDR with the mask MASK.
+   RW may be hw_read for a read watchpoint, hw_write for a write watchpoint
+   or hw_access for an access watchpoint.  Returns 0 for success, non-zero
+   for failure.  */
+
+extern int target_remove_mask_watchpoint (CORE_ADDR, CORE_ADDR, int);
+
 #define target_insert_hw_breakpoint(gdbarch, bp_tgt) \
      (*current_target.to_insert_hw_breakpoint) (gdbarch, bp_tgt)
 
@@ -1382,6 +1402,12 @@ extern int target_ranged_break_num_registers (void);
 #define target_can_accel_watchpoint_condition(addr, len, type, cond) \
   (*current_target.to_can_accel_watchpoint_condition) (addr, len, type, cond)
 
+/* Return number of debug registers needed for a masked watchpoint,
+   -1 if masked watchpoints are not supported or -2 if the given address
+   and mask combination cannot be used.  */
+
+extern int target_masked_watch_num_registers (CORE_ADDR addr, CORE_ADDR mask);
+
 /* Target can execute in reverse?  */
 #define target_can_execute_reverse \
      (current_target.to_can_execute_reverse ? \


^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [RFA 1/3] Change watchpoint's enable state in do_enable_breakpoint
  2011-04-18 21:22   ` [RFA 1/3] Change watchpoint's enable state in do_enable_breakpoint Thiago Jung Bauermann
@ 2011-04-29 17:21     ` Ulrich Weigand
  2011-05-04  0:11       ` Thiago Jung Bauermann
  0 siblings, 1 reply; 38+ messages in thread
From: Ulrich Weigand @ 2011-04-29 17:21 UTC (permalink / raw)
  To: Thiago Jung Bauermann; +Cc: gdb-patches ml

Thiago Jung Bauermann wrote:

> 2011-04-18  Thiago Jung Bauermann  <bauerman@br.ibm.com>
> 
> 	* breakpoint.c (update_watchpoint): Move code to change
> 	the enable state of breakpoint from here ...
> 	(do_enable_breakpoint): ... to here.

Yes, I think this makes sense.  OK.

Thanks,
Ulrich

-- 
  Dr. Ulrich Weigand
  GNU Toolchain for Linux on System z and Cell BE
  Ulrich.Weigand@de.ibm.com

^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [RFA 2/3] Demote to sw watchpoint only in update_watchpoint
  2011-04-18 21:22   ` [RFA 2/3] Demote to sw watchpoint only in update_watchpoint Thiago Jung Bauermann
@ 2011-04-29 17:26     ` Ulrich Weigand
  2011-05-03  4:56       ` Thiago Jung Bauermann
  0 siblings, 1 reply; 38+ messages in thread
From: Ulrich Weigand @ 2011-04-29 17:26 UTC (permalink / raw)
  To: Thiago Jung Bauermann; +Cc: gdb-patches ml

Thiago Jung Bauermann wrote:

> I was trying to adapt the logic in both places for masked watchpoints,
> but it's hard to anticipate in watch_command_1 what update_watchpoint
> will ultimately do without duplicating a good portion of the latter. The
> code in watch_command_1 was getting complicated and hard to get right in
> all situations for something which would be done again later anyway.

Agreed, that's a good idea.

> I decided that it was cleaner if watch_command_1 just delegated
> everything to update_watchpoint. This patch makes it create a
> watchpoint, call update_watchpoint and then delete it if some error is
> hit. The only drawback I can think of is that the aborted watchpoint
> will "consume" one breakpoint number, and thus GDB will skip one number
> when creating the next breakpoint/watchpoint. This doesn't seem
> important to me.

Hmm, I don't really like that change.  However, it should be easy to
fix by just moving the set_breakpoint_number call to down below where
update_watchpoint has succeeded, shouldn't it?

> 	(delete_breakpoint): Add announce argument to control whether
> 	observers are notified of the deletion.  Update all callers.

Ugh.  Adding an extra argument that everybody must be aware of just
to take care of this special case isn't really nice ...  I'd prefer
if you'd either split off the parts of delete_breakpoint that are
needed to undo partial creation into a separate function, or else,
if you use the set_breakpoint_number trick, identify partial
breakpoints by the fact that their b->number is still zero.

> @@ -1432,8 +1436,22 @@ update_watchpoint (struct breakpoint *b, int reparse)
>  	      target_resources_ok = target_can_use_hardware_watchpoint
>  		    (bp_hardware_watchpoint, i, other_type_used);
This should now use b->type instead of hardcoding bp_hardware_watchpoint,
shouldn't it?

Otherwise looks good to me.

Thanks,
Ulrich

-- 
  Dr. Ulrich Weigand
  GNU Toolchain for Linux on System z and Cell BE
  Ulrich.Weigand@de.ibm.com

^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [RFA 3/3] Implement support for PowerPC BookE masked watchpoints
  2011-04-18 21:24   ` [RFA 3/3] Implement support for PowerPC BookE masked watchpoints Thiago Jung Bauermann
@ 2011-04-29 17:46     ` Ulrich Weigand
  2011-05-03  4:56       ` [needs doc review] " Thiago Jung Bauermann
  0 siblings, 1 reply; 38+ messages in thread
From: Ulrich Weigand @ 2011-04-29 17:46 UTC (permalink / raw)
  To: Thiago Jung Bauermann; +Cc: gdb-patches ml

Thiago Jung Bauermann wrote:

> > We've recently added the -location feature that already prevents
> > GDB from fully tracking the expression, but rather just evaluate
> > it one time for its address.   Maybe one simple fix could be to
> > restrict the "mask" feature to watch -location (or have the 
> > presence of "mask" automatically imply -location, or maybe have
> > instead a new keyword -masked-location or so).
> 
> -location is indeed a good fit for this patch. I don't think we need a
> separate -masked-location keyword, so in this patch I made the mask
> parameter imply -location. Do you think this addresses your concerns
> regarding the semantics of masked watchpoints?

OK, that's fine with me.  I guess that ought to mentioned in the
documentation somewhere ...

> > However, even so there are still differences: even with -location,
> > GDB watchpoint code will still treat a watchpoint as refering to
> > one value, and track it (e.g. remember the value we saw last time;
> > re-evaluate it each time execution stops etc.).  This is really
> > not appropriate for the masked watchpoint case, because we do not
> > *have* any contiguous region that would define any single value.
> > Therefore, it seems to me that all this code ought to be disabled
> > for masked watchpoints.
> 
> Indeed. With this new patch, the only place that evaluates the
> watchpoint expression is update_watchpoint. This is necessary because
> the resulting value chain is then used to create the bp_locations and
> also by can_use_hardware_watchpoint when deciding whether to set a
> software or hardware watchpoint.
> 
> I could manually create a bp_location for masked watchpoints and
> implement a version of can_use_hardware_watchpoint just for masked
> watchpoints, but is it worth the extra special casing and complexity in
> update_watchpoint?

No, this is good.  Evaluating the expression just for it's value's
location(s) is fine ...

> +	  {
> +	    CORE_ADDR newaddr, start;
> +
> +	    if (is_masked_watchpoint (loc->owner))
> +	      {
> +		newaddr = addr & loc->owner->hw_wp_mask;
> +		start = loc->address & loc->owner->hw_wp_mask;
> +	      }
> +	    else
> +	      {
> +		newaddr = addr;
> +		start = loc->address;
> +	      }
> +
> +	    /* Exact match not required.  Within range is
> +	       sufficient.  */
> +	    if (target_watchpoint_addr_within_range (&current_target,
> +						     newaddr, start,
> +						     loc->length))
> +	      {
> +		b->watchpoint_triggered = watch_triggered_yes;
> +		break;
> +	      }
> +	  }

Hmmm, so for masked watchpoints we implement the masking operation
directly here, and then also call the target callback (which may use
the length, and do some additional masking on powerpc)?  That seems
a bit odd to me ...

Shouldn't we either:
 - just compare masked addresses for equality, directly (which
   implements that stated semantics)
 - or else pass the mask into target_watchpoint_addr_within_range
   and allow the target to implement whatever matching is appropriate


> +static enum print_stop_action
> +print_it_masked_watchpoint (struct breakpoint *b)
> +{
> +  struct ui_stream *stb;
> +  struct cleanup *old_chain;
> +
> +  /* Masked watchpoints have only one location.  */
> +  gdb_assert (b->loc && b->loc->next == NULL);
> +
> +  stb = ui_out_stream_new (uiout);
> +  old_chain = make_cleanup_ui_out_stream_delete (stb);

These aren't used anywhere, are they?

> +ppc_linux_masked_watch_num_registers (struct target_ops *target,
> +				      CORE_ADDR addr, CORE_ADDR mask)
> +{
> +  if (!have_ptrace_booke_interface ()
> +	   || (booke_debug_info.features & PPC_DEBUG_FEATURE_DATA_BP_MASK) == 0)
> +    return -1;
> +  else if ((mask & 0xC0000000) != 0xC0000000)
> +    {
> +      warning (_("\
> +The given mask covers kernel address space and cannot be used.\n\
> +You have to delete the masked watchpoint to continue the debugging session."));

This second sentence shouldn't be neccessary now: the watchpoint with the
invalid mask will never be successfully created, right?

Otherwise this looks all good to me now.

Thanks,
Ulrich

-- 
  Dr. Ulrich Weigand
  GNU Toolchain for Linux on System z and Cell BE
  Ulrich.Weigand@de.ibm.com

^ permalink raw reply	[flat|nested] 38+ messages in thread

* [needs doc review] Re: [RFA 3/3] Implement support for PowerPC BookE masked watchpoints
  2011-04-29 17:46     ` Ulrich Weigand
@ 2011-05-03  4:56       ` Thiago Jung Bauermann
  2011-05-03  6:24         ` Eli Zaretskii
  2011-05-05 11:07         ` Ulrich Weigand
  0 siblings, 2 replies; 38+ messages in thread
From: Thiago Jung Bauermann @ 2011-05-03  4:56 UTC (permalink / raw)
  To: Ulrich Weigand; +Cc: gdb-patches ml

On Fri, 2011-04-29 at 19:45 +0200, Ulrich Weigand wrote:
> Thiago Jung Bauermann wrote:
> 
> > > We've recently added the -location feature that already prevents
> > > GDB from fully tracking the expression, but rather just evaluate
> > > it one time for its address.   Maybe one simple fix could be to
> > > restrict the "mask" feature to watch -location (or have the 
> > > presence of "mask" automatically imply -location, or maybe have
> > > instead a new keyword -masked-location or so).
> > 
> > -location is indeed a good fit for this patch. I don't think we need a
> > separate -masked-location keyword, so in this patch I made the mask
> > parameter imply -location. Do you think this addresses your concerns
> > regarding the semantics of masked watchpoints?
> 
> OK, that's fine with me.  I guess that ought to mentioned in the
> documentation somewhere ...

I updated the documentation. The following paragraphs were changing
relative to the previously approved text in the manual:

1. The last sentence was added to the paragraph below:

  The @code{@r{[}mask @var{maskvalue}@r{]}} argument allows creation
  of masked watchpoints, if the current architecture supports this
  feature.  (Currently, this is only available on PowerPC Embedded
  architecture, see @ref{PowerPC Embedded}.)  Specifying a mask argument
  implies the @code{-location} argument.

2. The paragraph

  A @dfn{masked watchpoint} specifies a mask in addition to an address
  to watch.  The mask specifies that some bits of an address (the bits
  which are reset in the mask) should be ignored when matching the
  address accessed by the inferior against the watchpoint address.
  Thus, a masked watchpoint watches many addresses
  simultaneously---those addresses whose unmasked bits are identical
  to the unmasked bits in the watchpoint address.

became

  A @dfn{masked watchpoint} specifies a mask in addition to an address
  to watch.  The @code{mask} argument implies the @code{-location}
  argument, which means that the expression will be resolved to a memory
  address at watchpoint creation time (@pxref{Set Watchpoints}.)  The mask
  specifies that some bits of an address (the bits which are reset in the
  mask) should be ignored when matching the address accessed by the inferior
  against the watchpoint address.  Thus, a masked watchpoint watches many
  addresses simultaneously---those addresses whose unmasked bits are
  identical to the unmasked bits in the watchpoint address.

> > +	  {
> > +	    CORE_ADDR newaddr, start;
> > +
> > +	    if (is_masked_watchpoint (loc->owner))
> > +	      {
> > +		newaddr = addr & loc->owner->hw_wp_mask;
> > +		start = loc->address & loc->owner->hw_wp_mask;
> > +	      }
> > +	    else
> > +	      {
> > +		newaddr = addr;
> > +		start = loc->address;
> > +	      }
> > +
> > +	    /* Exact match not required.  Within range is
> > +	       sufficient.  */
> > +	    if (target_watchpoint_addr_within_range (&current_target,
> > +						     newaddr, start,
> > +						     loc->length))
> > +	      {
> > +		b->watchpoint_triggered = watch_triggered_yes;
> > +		break;
> > +	      }
> > +	  }
> 
> Hmmm, so for masked watchpoints we implement the masking operation
> directly here, and then also call the target callback (which may use
> the length, and do some additional masking on powerpc)?  That seems
> a bit odd to me ...
> 
> Shouldn't we either:
>  - just compare masked addresses for equality, directly (which
>    implements that stated semantics)
>  - or else pass the mask into target_watchpoint_addr_within_range
>    and allow the target to implement whatever matching is appropriate

This version implements the first option.

> > +static enum print_stop_action
> > +print_it_masked_watchpoint (struct breakpoint *b)
> > +{
> > +  struct ui_stream *stb;
> > +  struct cleanup *old_chain;
> > +
> > +  /* Masked watchpoints have only one location.  */
> > +  gdb_assert (b->loc && b->loc->next == NULL);
> > +
> > +  stb = ui_out_stream_new (uiout);
> > +  old_chain = make_cleanup_ui_out_stream_delete (stb);
> 
> These aren't used anywhere, are they?

Right. Dropped.

> > +ppc_linux_masked_watch_num_registers (struct target_ops *target,
> > +				      CORE_ADDR addr, CORE_ADDR mask)
> > +{
> > +  if (!have_ptrace_booke_interface ()
> > +	   || (booke_debug_info.features & PPC_DEBUG_FEATURE_DATA_BP_MASK) == 0)
> > +    return -1;
> > +  else if ((mask & 0xC0000000) != 0xC0000000)
> > +    {
> > +      warning (_("\
> > +The given mask covers kernel address space and cannot be used.\n\
> > +You have to delete the masked watchpoint to continue the debugging session."));
> 
> This second sentence shouldn't be neccessary now: the watchpoint with the
> invalid mask will never be successfully created, right?

Indeed. Removed the second sentence.

> Otherwise this looks all good to me now.

Great. What about this version?
-- 
[]'s
Thiago Jung Bauermann
IBM Linux Technology Center


2011-05-03  Sergio Durigan Junior  <sergiodj@linux.vnet.ibm.com>
	    Thiago Jung Bauermann  <bauerman@br.ibm.com>

	Implement support for PowerPC BookE masked watchpoints.

gdb/
	*NEWS: Mention masked watchpoint support.  Create "Changed commands"
	section.
	* breakpoint.h (struct breakpoint_ops) <works_in_software_mode>: New
	method.  Initialize to NULL in all existing breakpoint_ops instances.
	(struct breakpoint) <hw_wp_mask>: New field.
	* breakpoint.c (is_masked_watchpoint): Add prototype.
	(update_watchpoint): Don't set b->val for masked watchpoints.  Call
	breakpoint's breakpoint_ops.works_in_software_mode if available.
	(watchpoints_triggered): Handle the case of a hardware masked
	watchpoint trigger.
	(watchpoint_check): Likewise.
	(works_in_software_mode_watchpoint): New function.
	(insert_masked_watchpoint, remove_masked_watchpoint)
	(resources_needed_masked_watchpoint)
	(works_in_software_mode_masked_watchpoint, print_it_masked_watchpoint)
	(print_one_detail_masked_watchpoint, print_mention_masked_watchpoint)
	(print_recreate_masked_watchpoint, is_masked_watchpoint): New
	functions.
	(masked_watchpoint_breakpoint_ops): New structure.
	(watch_command_1): Check for the existence of the `mask' parameter.
	Set b->ops according to the type of hardware watchpoint being created.
	* ppc-linux-nat.c (ppc_linux_insert_mask_watchpoint)
	(ppc_linux_remove_mask_watchpoint)
	(ppc_linux_masked_watch_num_registers): New functions.
	(_initialize_ppc_linux_nat): Initialize to_insert_mask_watchpoint,
	to_remove_mask_watchpoint and to_masked_watch_num_registers.
	* target.c (update_current_target): Mention to_insert_mask_watchpoint,
	to_remove_mask_watchpoint, and to_masked_watch_num_registers.
	(target_insert_mask_watchpoint, target_remove_mask_watchpoint)
	(target_masked_watch_num_registers): New functions.
	* target.h (struct target_ops) <to_insert_mask_watchpoint>,
	<to_remove_mask_watchpoint>, <to_masked_watch_num_registers>: New
	methods.
	(target_insert_mask_watchpoint, target_remove_mask_watchpoint)
	(target_masked_watch_num_registers): Add prototypes.

gdb/doc/
	* gdb.texinfo (Set Watchpoints): Document mask parameter.
	(PowerPC Embedded): Document masked watchpoints.


diff --git a/gdb/NEWS b/gdb/NEWS
index 1a22c66..9b59419 100644
--- a/gdb/NEWS
+++ b/gdb/NEWS
@@ -3,10 +3,24 @@
 
 *** Changes since GDB 7.3
 
+* When natively debugging programs on PowerPC BookE processors running
+  a Linux kernel version 2.6.34 or later, GDB supports masked hardware
+  watchpoints, which specify a mask in addition to an address to watch.
+  The mask specifies that some bits of an address (the bits which are
+  reset in the mask) should be ignored when matching the address accessed
+  by the inferior against the watchpoint address.  See the "PowerPC Embedded"
+  section in the user manual for more details.
+
 * The new option --once causes GDBserver to stop listening for connections once
   the first connection is made.  The listening port used by GDBserver will
   become available after that.
 
+* Changed commands
+
+watch EXPRESSION mask MASK_VALUE
+  The watch command now supports the mask argument which allows creation
+  of masked watchpoints, if the current architecture supports this feature.
+
 *** Changes in GDB 7.3
 
 * GDB has a new command: "thread find [REGEXP]".
diff --git a/gdb/ada-lang.c b/gdb/ada-lang.c
index d434521..ebd5fd2 100644
--- a/gdb/ada-lang.c
+++ b/gdb/ada-lang.c
@@ -10950,6 +10950,7 @@ static struct breakpoint_ops catch_exception_breakpoint_ops =
   NULL, /* remove */
   NULL, /* breakpoint_hit */
   NULL, /* resources_needed */
+  NULL, /* works_in_software_mode */
   print_it_catch_exception,
   print_one_catch_exception,
   NULL, /* print_one_detail */
@@ -10990,6 +10991,7 @@ static struct breakpoint_ops catch_exception_unhandled_breakpoint_ops = {
   NULL, /* remove */
   NULL, /* breakpoint_hit */
   NULL, /* resources_needed */
+  NULL, /* works_in_software_mode */
   print_it_catch_exception_unhandled,
   print_one_catch_exception_unhandled,
   NULL, /* print_one_detail */
@@ -11028,6 +11030,7 @@ static struct breakpoint_ops catch_assert_breakpoint_ops = {
   NULL, /* remove */
   NULL, /* breakpoint_hit */
   NULL, /* resources_needed */
+  NULL, /* works_in_software_mode */
   print_it_catch_assert,
   print_one_catch_assert,
   NULL, /* print_one_detail */
diff --git a/gdb/breakpoint.c b/gdb/breakpoint.c
index 604d5ab..fc62971 100644
--- a/gdb/breakpoint.c
+++ b/gdb/breakpoint.c
@@ -224,6 +224,8 @@ static void disable_trace_command (char *, int);
 
 static void trace_pass_command (char *, int);
 
+static int is_masked_watchpoint (const struct breakpoint *b);
+
 /* Assuming we're creating a static tracepoint, does S look like a
    static tracepoint marker spec ("-m MARKER_ID")?  */
 #define is_marker_spec(s)						\
@@ -1345,8 +1347,10 @@ update_watchpoint (struct breakpoint *b, int reparse)
       /* Avoid setting b->val if it's already set.  The meaning of
 	 b->val is 'the last value' user saw, and we should update
 	 it only if we reported that last value to user.  As it
-	 happens, the code that reports it updates b->val directly.  */
-      if (!b->val_valid)
+	 happens, the code that reports it updates b->val directly.
+	 We don't keep track of the memory value for masked
+	 watchpoints.  */
+      if (!b->val_valid && !is_masked_watchpoint (b))
 	{
 	  b->val = v;
 	  b->val_valid = 1;
@@ -1440,19 +1444,23 @@ update_watchpoint (struct breakpoint *b, int reparse)
 		    (bp_hardware_watchpoint, i, other_type_used);
 	      if (target_resources_ok <= 0)
 		{
-		  if (target_resources_ok == 0
-		      && b->type != bp_hardware_watchpoint)
+		  /* If there's no works_in_software_mode method, we
+		     assume that the watchpoint works in software mode.  */
+		  int sw_mode = (!b->ops || !b->ops->works_in_software_mode
+				 || b->ops->works_in_software_mode (b));
+
+		  if (target_resources_ok == 0 && !sw_mode)
 		    error (_("Target does not support this type of "
 			     "hardware watchpoint."));
-		  else if (target_resources_ok < 0
-		      && b->type != bp_hardware_watchpoint)
-		    error (_("Target can only support one kind "
-			     "of HW watchpoint at a time."));
+		  else if (target_resources_ok < 0 && !sw_mode)
+		    error (_("There are not enough available hardware "
+			     "resources for this watchpoint."));
 		  else
 		    b->type = bp_watchpoint;
 		}
 	    }
-	  else if (b->type != bp_hardware_watchpoint)
+	  else if (b->ops && b->ops->works_in_software_mode
+		   && !b->ops->works_in_software_mode (b))
 	    error (_("Expression cannot be implemented with "
 		     "read/access watchpoint."));
 	  else
@@ -3699,15 +3707,27 @@ watchpoints_triggered (struct target_waitstatus *ws)
 
 	b->watchpoint_triggered = watch_triggered_no;
 	for (loc = b->loc; loc; loc = loc->next)
-	  /* Exact match not required.  Within range is
-	     sufficient.  */
-	  if (target_watchpoint_addr_within_range (&current_target,
-						   addr, loc->address,
-						   loc->length))
-	    {
-	      b->watchpoint_triggered = watch_triggered_yes;
-	      break;
-	    }
+	  {
+	    if (is_masked_watchpoint (loc->owner))
+	      {
+		CORE_ADDR newaddr = addr & loc->owner->hw_wp_mask;
+		CORE_ADDR start = loc->address & loc->owner->hw_wp_mask;
+
+		if (newaddr == start)
+		  {
+		    b->watchpoint_triggered = watch_triggered_yes;
+		    break;
+		  }
+	      }
+	    /* Exact match not required.  Within range is sufficient.  */
+	    else if (target_watchpoint_addr_within_range (&current_target,
+							 addr, loc->address,
+							 loc->length))
+	      {
+		b->watchpoint_triggered = watch_triggered_yes;
+		break;
+	      }
+	  }
       }
 
   return 1;
@@ -3804,9 +3824,16 @@ watchpoint_check (void *p)
          might be in the middle of evaluating a function call.  */
 
       int pc = 0;
-      struct value *mark = value_mark ();
+      struct value *mark;
       struct value *new_val;
 
+      if (is_masked_watchpoint (b))
+	/* Since we don't know the exact trigger address (from
+	   stopped_data_address), just tell the user we've triggered
+	   a mask watchpoint.  */
+	return WP_VALUE_CHANGED;
+
+      mark = value_mark ();
       fetch_subexp_value (b->exp, &pc, &new_val, NULL, NULL);
 
       /* We use value_equal_contents instead of value_equal because
@@ -6308,6 +6335,7 @@ static struct breakpoint_ops catch_fork_breakpoint_ops =
   remove_catch_fork,
   breakpoint_hit_catch_fork,
   NULL, /* resources_needed */
+  NULL, /* works_in_software_mode */
   print_it_catch_fork,
   print_one_catch_fork,
   NULL, /* print_one_detail */
@@ -6406,6 +6434,7 @@ static struct breakpoint_ops catch_vfork_breakpoint_ops =
   remove_catch_vfork,
   breakpoint_hit_catch_vfork,
   NULL, /* resources_needed */
+  NULL, /* works_in_software_mode */
   print_it_catch_vfork,
   print_one_catch_vfork,
   NULL, /* print_one_detail */
@@ -6693,6 +6722,7 @@ static struct breakpoint_ops catch_syscall_breakpoint_ops =
   remove_catch_syscall,
   breakpoint_hit_catch_syscall,
   NULL, /* resources_needed */
+  NULL, /* works_in_software_mode */
   print_it_catch_syscall,
   print_one_catch_syscall,
   NULL, /* print_one_detail */
@@ -6850,6 +6880,7 @@ static struct breakpoint_ops catch_exec_breakpoint_ops =
   remove_catch_exec,
   breakpoint_hit_catch_exec,
   NULL, /* resources_needed */
+  NULL, /* works_in_software_mode */
   print_it_catch_exec,
   print_one_catch_exec,
   NULL, /* print_one_detail */
@@ -8475,6 +8506,7 @@ static struct breakpoint_ops ranged_breakpoint_ops =
   NULL, /* remove */
   breakpoint_hit_ranged_breakpoint,
   resources_needed_ranged_breakpoint,
+  NULL, /* works_in_software_mode */
   print_it_ranged_breakpoint,
   print_one_ranged_breakpoint,
   print_one_detail_ranged_breakpoint,
@@ -8782,6 +8814,15 @@ resources_needed_watchpoint (const struct bp_location *bl)
   return target_region_ok_for_hw_watchpoint (bl->address, length);
 }
 
+/* Implement the "works_in_software_mode" breakpoint_ops method for
+   hardware watchpoints.  */
+
+int
+works_in_software_mode_watchpoint (const struct breakpoint *b)
+{
+  return b->type == bp_hardware_watchpoint;
+}
+
 /* The breakpoint_ops structure to be used in hardware watchpoints.  */
 
 static struct breakpoint_ops watchpoint_breakpoint_ops =
@@ -8790,6 +8831,7 @@ static struct breakpoint_ops watchpoint_breakpoint_ops =
   remove_watchpoint,
   NULL, /* breakpoint_hit */
   resources_needed_watchpoint,
+  works_in_software_mode_watchpoint,
   NULL, /* print_it */
   NULL, /* print_one */
   NULL, /* print_one_detail */
@@ -8797,6 +8839,192 @@ static struct breakpoint_ops watchpoint_breakpoint_ops =
   NULL  /* print_recreate */
 };
 
+/* Implement the "insert" breakpoint_ops method for
+   masked hardware watchpoints.  */
+
+static int
+insert_masked_watchpoint (struct bp_location *bl)
+{
+  return target_insert_mask_watchpoint (bl->address, bl->owner->hw_wp_mask,
+					bl->watchpoint_type);
+}
+
+/* Implement the "remove" breakpoint_ops method for
+   masked hardware watchpoints.  */
+
+static int
+remove_masked_watchpoint (struct bp_location *bl)
+{
+  return target_remove_mask_watchpoint (bl->address, bl->owner->hw_wp_mask,
+				        bl->watchpoint_type);
+}
+
+/* Implement the "resources_needed" breakpoint_ops method for
+   masked hardware watchpoints.  */
+
+static int
+resources_needed_masked_watchpoint (const struct bp_location *bl)
+{
+  return target_masked_watch_num_registers (bl->address,
+					    bl->owner->hw_wp_mask);
+}
+
+/* Implement the "works_in_software_mode" breakpoint_ops method for
+   masked hardware watchpoints.  */
+
+static int
+works_in_software_mode_masked_watchpoint (const struct breakpoint *b)
+{
+  return 0;
+}
+
+/* Implement the "print_it" breakpoint_ops method for
+   masked hardware watchpoints.  */
+
+static enum print_stop_action
+print_it_masked_watchpoint (struct breakpoint *b)
+{
+  /* Masked watchpoints have only one location.  */
+  gdb_assert (b->loc && b->loc->next == NULL);
+
+  switch (b->type)
+    {
+    case bp_hardware_watchpoint:
+      annotate_watchpoint (b->number);
+      if (ui_out_is_mi_like_p (uiout))
+	ui_out_field_string
+	  (uiout, "reason",
+	   async_reason_lookup (EXEC_ASYNC_WATCHPOINT_TRIGGER));
+      break;
+
+    case bp_read_watchpoint:
+      if (ui_out_is_mi_like_p (uiout))
+	ui_out_field_string
+	  (uiout, "reason",
+	   async_reason_lookup (EXEC_ASYNC_READ_WATCHPOINT_TRIGGER));
+      break;
+
+    case bp_access_watchpoint:
+      if (ui_out_is_mi_like_p (uiout))
+	ui_out_field_string
+	  (uiout, "reason",
+	   async_reason_lookup (EXEC_ASYNC_ACCESS_WATCHPOINT_TRIGGER));
+      break;
+    default:
+      internal_error (__FILE__, __LINE__,
+		      _("Invalid hardware watchpoint type."));
+    }
+
+  mention (b);
+  ui_out_text (uiout, _("\n\
+Check the underlying instruction at PC for the memory\n\
+address and value which triggered this watchpoint.\n"));
+  ui_out_text (uiout, "\n");
+
+  /* More than one watchpoint may have been triggered.  */
+  return PRINT_UNKNOWN;
+}
+
+/* Implement the "print_one_detail" breakpoint_ops method for
+   masked hardware watchpoints.  */
+
+static void
+print_one_detail_masked_watchpoint (const struct breakpoint *b,
+				    struct ui_out *uiout)
+{
+  /* Masked watchpoints have only one location.  */
+  gdb_assert (b->loc && b->loc->next == NULL);
+
+  ui_out_text (uiout, "\tmask ");
+  ui_out_field_core_addr (uiout, "mask", b->loc->gdbarch, b->hw_wp_mask);
+  ui_out_text (uiout, "\n");
+}
+
+/* Implement the "print_mention" breakpoint_ops method for
+   masked hardware watchpoints.  */
+
+static void
+print_mention_masked_watchpoint (struct breakpoint *b)
+{
+  struct cleanup *ui_out_chain;
+
+  switch (b->type)
+    {
+    case bp_hardware_watchpoint:
+      ui_out_text (uiout, "Masked hardware watchpoint ");
+      ui_out_chain = make_cleanup_ui_out_tuple_begin_end (uiout, "wpt");
+      break;
+    case bp_read_watchpoint:
+      ui_out_text (uiout, "Masked hardware read watchpoint ");
+      ui_out_chain = make_cleanup_ui_out_tuple_begin_end (uiout, "hw-rwpt");
+      break;
+    case bp_access_watchpoint:
+      ui_out_text (uiout, "Masked hardware access (read/write) watchpoint ");
+      ui_out_chain = make_cleanup_ui_out_tuple_begin_end (uiout, "hw-awpt");
+      break;
+    default:
+      internal_error (__FILE__, __LINE__,
+		      _("Invalid hardware watchpoint type."));
+    }
+
+  ui_out_field_int (uiout, "number", b->number);
+  ui_out_text (uiout, ": ");
+  ui_out_field_string (uiout, "exp", b->exp_string);
+  do_cleanups (ui_out_chain);
+}
+
+/* Implement the "print_recreate" breakpoint_ops method for
+   masked hardware watchpoints.  */
+
+static void
+print_recreate_masked_watchpoint (struct breakpoint *b, struct ui_file *fp)
+{
+  char tmp[40];
+
+  switch (b->type)
+    {
+    case bp_hardware_watchpoint:
+      fprintf_unfiltered (fp, "watch");
+      break;
+    case bp_read_watchpoint:
+      fprintf_unfiltered (fp, "rwatch");
+      break;
+    case bp_access_watchpoint:
+      fprintf_unfiltered (fp, "awatch");
+      break;
+    default:
+      internal_error (__FILE__, __LINE__,
+		      _("Invalid hardware watchpoint type."));
+    }
+
+  sprintf_vma (tmp, b->hw_wp_mask);
+  fprintf_unfiltered (fp, " %s mask 0x%s", b->exp_string, tmp);
+}
+
+/* The breakpoint_ops structure to be used in masked hardware watchpoints.  */
+
+static struct breakpoint_ops masked_watchpoint_breakpoint_ops =
+{
+  insert_masked_watchpoint,
+  remove_masked_watchpoint,
+  NULL, /* breakpoint_hit */
+  resources_needed_masked_watchpoint,
+  works_in_software_mode_masked_watchpoint,
+  print_it_masked_watchpoint,
+  NULL, /* print_one */
+  print_one_detail_masked_watchpoint,
+  print_mention_masked_watchpoint,
+  print_recreate_masked_watchpoint
+};
+
+/* Tell whether the given watchpoint is a masked hardware watchpoint.  */
+
+static int
+is_masked_watchpoint (const struct breakpoint *b)
+{
+  return b->ops == &masked_watchpoint_breakpoint_ops;
+}
+
 /* accessflag:  hw_write:  watch write, 
                 hw_read:   watch read, 
 		hw_access: watch access (read or write) */
@@ -8812,73 +9040,97 @@ watch_command_1 (char *arg, int accessflag, int from_tty,
   struct frame_info *frame;
   char *exp_start = NULL;
   char *exp_end = NULL;
-  char *tok, *id_tok_start, *end_tok;
-  int toklen;
+  char *tok, *end_tok;
+  int toklen = -1;
   char *cond_start = NULL;
   char *cond_end = NULL;
   enum bptype bp_type;
   int thread = -1;
   int pc = 0;
+  /* Flag to indicate whether we are going to use masks for
+     the hardware watchpoint.  */
+  int use_mask = 0;
+  CORE_ADDR mask = 0;
 
   /* Make sure that we actually have parameters to parse.  */
   if (arg != NULL && arg[0] != '\0')
     {
-      toklen = strlen (arg); /* Size of argument list.  */
+      char *value_start;
 
-      /* Points tok to the end of the argument list.  */
-      tok = arg + toklen - 1;
+      /* Look for "parameter value" pairs at the end
+	 of the arguments string.  */
+      for (tok = arg + strlen (arg) - 1; tok > arg; tok--)
+	{
+	  /* Skip whitespace at the end of the argument list.  */
+	  while (tok > arg && (*tok == ' ' || *tok == '\t'))
+	    tok--;
+
+	  /* Find the beginning of the last token.
+	     This is the value of the parameter.  */
+	  while (tok > arg && (*tok != ' ' && *tok != '\t'))
+	    tok--;
+	  value_start = tok + 1;
+
+	  /* Skip whitespace.  */
+	  while (tok > arg && (*tok == ' ' || *tok == '\t'))
+	    tok--;
+
+	  end_tok = tok;
+
+	  /* Find the beginning of the second to last token.
+	     This is the parameter itself.  */
+	  while (tok > arg && (*tok != ' ' && *tok != '\t'))
+	    tok--;
+	  tok++;
+	  toklen = end_tok - tok + 1;
+
+	  if (toklen == 6 && !strncmp (tok, "thread", 6))
+	    {
+	      /* At this point we've found a "thread" token, which means
+		 the user is trying to set a watchpoint that triggers
+		 only in a specific thread.  */
+	      char *endp;
 
-      /* Go backwards in the parameters list.  Skip the last
-         parameter.  If we're expecting a 'thread <thread_num>'
-         parameter, this should be the thread identifier.  */
-      while (tok > arg && (*tok == ' ' || *tok == '\t'))
-        tok--;
-      while (tok > arg && (*tok != ' ' && *tok != '\t'))
-        tok--;
+	      if (thread != -1)
+		error(_("You can specify only one thread."));
 
-      /* Points end_tok to the beginning of the last token.  */
-      id_tok_start = tok + 1;
+	      /* Extract the thread ID from the next token.  */
+	      thread = strtol (value_start, &endp, 0);
 
-      /* Go backwards in the parameters list.  Skip one more
-         parameter.  If we're expecting a 'thread <thread_num>'
-         parameter, we should reach a "thread" token.  */
-      while (tok > arg && (*tok == ' ' || *tok == '\t'))
-        tok--;
+	      /* Check if the user provided a valid numeric value for the
+		 thread ID.  */
+	      if (*endp != ' ' && *endp != '\t' && *endp != '\0')
+		error (_("Invalid thread ID specification %s."), value_start);
 
-      end_tok = tok;
+	      /* Check if the thread actually exists.  */
+	      if (!valid_thread_id (thread))
+		error (_("Unknown thread %d."), thread);
+	    }
+	  else if (toklen == 4 && !strncmp (tok, "mask", 4))
+	    {
+	      /* We've found a "mask" token, which means the user wants to
+		 create a hardware watchpoint that is going to have the mask
+		 facility.  */
+	      struct value *mask_value, *mark;
 
-      while (tok > arg && (*tok != ' ' && *tok != '\t'))
-        tok--;
+	      if (use_mask)
+		error(_("You can specify only one mask."));
 
-      /* Move the pointer forward to skip the whitespace and
-         calculate the length of the token.  */
-      tok++;
-      toklen = end_tok - tok;
+	      use_mask = just_location = 1;
 
-      if (toklen >= 1 && strncmp (tok, "thread", toklen) == 0)
-        {
-          /* At this point we've found a "thread" token, which means
-             the user is trying to set a watchpoint that triggers
-             only in a specific thread.  */
-          char *endp;
-
-          /* Extract the thread ID from the next token.  */
-          thread = strtol (id_tok_start, &endp, 0);
-
-          /* Check if the user provided a valid numeric value for the
-             thread ID.  */
-          if (*endp != ' ' && *endp != '\t' && *endp != '\0')
-            error (_("Invalid thread ID specification %s."), id_tok_start);
-
-          /* Check if the thread actually exists.  */
-          if (!valid_thread_id (thread))
-            error (_("Unknown thread %d."), thread);
-
-          /* Truncate the string and get rid of the thread <thread_num>
-             parameter before the parameter list is parsed by the
-             evaluate_expression() function.  */
-          *tok = '\0';
-        }
+	      mark = value_mark ();
+	      mask_value = parse_to_comma_and_eval (&value_start);
+	      mask = value_as_address (mask_value);
+	      value_free_to_mark (mark);
+	    }
+	  else
+	    /* We didn't recognize what we found.  We should stop here.  */
+	    break;
+
+	  /* Truncate the string and get rid of the "parameter value" pair before
+	     the arguments string is parsed by the parse_exp_1 function.  */
+	  *tok = '\0';
+	}
     }
 
   /* Parse the rest of the arguments.  */
@@ -8909,10 +9161,22 @@ watch_command_1 (char *arg, int accessflag, int from_tty,
 
   if (just_location)
     {
+      int ret;
+
       exp_valid_block = NULL;
       val = value_addr (result);
       release_value (val);
       value_free_to_mark (mark);
+
+      if (use_mask)
+	{
+	  ret = target_masked_watch_num_registers (value_as_address (val),
+						   mask);
+	  if (ret == -1)
+	    error (_("This target does not support masked watchpoints."));
+	  else if (ret == -2)
+	    error (_("Invalid mask or memory region."));
+	}
     }
   else if (val != NULL)
     release_value (val);
@@ -9009,9 +9273,18 @@ watch_command_1 (char *arg, int accessflag, int from_tty,
     }
   else
     b->exp_string = savestring (exp_start, exp_end - exp_start);
-  b->val = val;
-  b->val_valid = 1;
-  b->ops = &watchpoint_breakpoint_ops;
+
+  if (use_mask)
+    {
+      b->hw_wp_mask = mask;
+      b->ops = &masked_watchpoint_breakpoint_ops;
+    }
+  else
+    {
+      b->val = val;
+      b->val_valid = 1;
+      b->ops = &watchpoint_breakpoint_ops;
+    }
 
   if (cond_start)
     b->cond_string = savestring (cond_start, cond_end - cond_start);
@@ -9548,6 +9821,7 @@ static struct breakpoint_ops gnu_v3_exception_catchpoint_ops = {
   NULL, /* remove */
   NULL, /* breakpoint_hit */
   NULL, /* resources_needed */
+  NULL, /* works_in_software_mode */
   print_it_exception_catchpoint,
   print_one_exception_catchpoint,
   NULL, /* print_one_detail */
diff --git a/gdb/breakpoint.h b/gdb/breakpoint.h
index 7a9c2d4..7fa705f 100644
--- a/gdb/breakpoint.h
+++ b/gdb/breakpoint.h
@@ -410,6 +410,11 @@ struct breakpoint_ops
      the breakpoint or watchpoint needs one debug register.  */
   int (*resources_needed) (const struct bp_location *);
 
+  /* Tell whether we can downgrade from a hardware watchpoint to a software
+     one.  If not, the user will not be able to enable the watchpoint when
+     there are not enough hardware resources available.  */
+  int (*works_in_software_mode) (const struct breakpoint *);
+
   /* The normal print routine for this breakpoint, called when we
      hit it.  */
   enum print_stop_action (*print_it) (struct breakpoint *);
@@ -651,6 +656,9 @@ struct breakpoint
 
     /* Whether this watchpoint is exact (see target_exact_watchpoints).  */
     int exact;
+
+    /* The mask address for a masked hardware watchpoint.  */
+    CORE_ADDR hw_wp_mask;
   };
 
 typedef struct breakpoint *breakpoint_p;
diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo
index ff5b7cb..19104ad 100644
--- a/gdb/doc/gdb.texinfo
+++ b/gdb/doc/gdb.texinfo
@@ -3728,7 +3728,7 @@ watchpoints, which do not slow down the running of your program.
 
 @table @code
 @kindex watch
-@item watch @r{[}-l@r{|}-location@r{]} @var{expr} @r{[}thread @var{threadnum}@r{]}
+@item watch @r{[}-l@r{|}-location@r{]} @var{expr} @r{[}thread @var{threadnum}@r{]} @r{[}mask @var{maskvalue}@r{]}
 Set a watchpoint for an expression.  @value{GDBN} will break when the
 expression @var{expr} is written into by the program and its value
 changes.  The simplest (and the most popular) use of this command is
@@ -3739,12 +3739,18 @@ to watch the value of a single variable:
 @end smallexample
 
 If the command includes a @code{@r{[}thread @var{threadnum}@r{]}}
-clause, @value{GDBN} breaks only when the thread identified by
+argument, @value{GDBN} breaks only when the thread identified by
 @var{threadnum} changes the value of @var{expr}.  If any other threads
 change the value of @var{expr}, @value{GDBN} will not break.  Note
 that watchpoints restricted to a single thread in this way only work
 with Hardware Watchpoints.
 
+The @code{@r{[}mask @var{maskvalue}@r{]}} argument allows creation
+of masked watchpoints, if the current architecture supports this
+feature.  (Currently, this is only available on PowerPC Embedded
+architecture, see @ref{PowerPC Embedded}.)  Specifying a mask argument
+implies the @code{-location} argument.
+
 Ordinarily a watchpoint respects the scope of variables in @var{expr}
 (see below).  The @code{-location} argument tells @value{GDBN} to
 instead watch the memory referred to by @var{expr}.  In this case,
@@ -3755,12 +3761,12 @@ result does not have an address, then @value{GDBN} will print an
 error.
 
 @kindex rwatch
-@item rwatch @r{[}-l@r{|}-location@r{]} @var{expr} @r{[}thread @var{threadnum}@r{]}
+@item rwatch @r{[}-l@r{|}-location@r{]} @var{expr} @r{[}thread @var{threadnum}@r{]} @r{[}mask @var{maskvalue}@r{]}
 Set a watchpoint that will break when the value of @var{expr} is read
 by the program.
 
 @kindex awatch
-@item awatch @r{[}-l@r{|}-location@r{]} @var{expr} @r{[}thread @var{threadnum}@r{]}
+@item awatch @r{[}-l@r{|}-location@r{]} @var{expr} @r{[}thread @var{threadnum}@r{]} @r{[}mask @var{maskvalue}@r{]}
 Set a watchpoint that will break when @var{expr} is either read from
 or written into by the program.
 
@@ -18783,6 +18789,25 @@ region using one of the following commands (@pxref{Expressions}):
 (@value{GDBP}) watch @{char[@var{length}]@} @var{address}
 @end smallexample
 
+PowerPC embedded processors support masked watchpoints.
+
+A @dfn{masked watchpoint} specifies a mask in addition to an address
+to watch.  The @code{mask} argument implies the @code{-location}
+argument, which means that the expression will be resolved to a memory
+address at watchpoint creation time (@pxref{Set Watchpoints}.)  The mask
+specifies that some bits of an address (the bits which are reset in the
+mask) should be ignored when matching the address accessed by the inferior
+against the watchpoint address.  Thus, a masked watchpoint watches many
+addresses simultaneously---those addresses whose unmasked bits are
+identical to the unmasked bits in the watchpoint address.
+
+To set a masked watchpoint in @value{GDBN}, use the @code{mask} argument in
+the @code{watch} command (@pxref{Set Watchpoints}), as in:
+
+@smallexample
+(@value{GDBP}) watch *0xdeadbeef mask 0xffffff00
+@end smallexample
+
 @cindex ranged breakpoint
 PowerPC embedded processors support hardware accelerated
 @dfn{ranged breakpoints}.  A ranged breakpoint stops execution of
diff --git a/gdb/ppc-linux-nat.c b/gdb/ppc-linux-nat.c
index 6f11715..275de78 100644
--- a/gdb/ppc-linux-nat.c
+++ b/gdb/ppc-linux-nat.c
@@ -1739,6 +1739,64 @@ get_trigger_type (int rw)
   return t;
 }
 
+/* Insert a new masked watchpoint at ADDR using the mask MASK.
+   RW may be hw_read for a read watchpoint, hw_write for a write watchpoint
+   or hw_access for an access watchpoint.  Returns 0 on success and throws
+   an error on failure.  */
+
+static int
+ppc_linux_insert_mask_watchpoint (struct target_ops *ops, CORE_ADDR addr,
+				  CORE_ADDR mask, int rw)
+{
+  ptid_t ptid;
+  struct lwp_info *lp;
+  struct ppc_hw_breakpoint p;
+
+  gdb_assert (have_ptrace_booke_interface ());
+
+  p.version = PPC_DEBUG_CURRENT_VERSION;
+  p.trigger_type = get_trigger_type (rw);
+  p.addr_mode = PPC_BREAKPOINT_MODE_MASK;
+  p.condition_mode = PPC_BREAKPOINT_CONDITION_NONE;
+  p.addr = addr;
+  p.addr2 = mask;
+  p.condition_value = 0;
+
+  ALL_LWPS (lp, ptid)
+    booke_insert_point (&p, TIDGET (ptid));
+
+  return 0;
+}
+
+/* Remove a masked watchpoint at ADDR with the mask MASK.
+   RW may be hw_read for a read watchpoint, hw_write for a write watchpoint
+   or hw_access for an access watchpoint.  Returns 0 on success and throws
+   an error on failure.  */
+
+static int
+ppc_linux_remove_mask_watchpoint (struct target_ops *ops, CORE_ADDR addr,
+				  CORE_ADDR mask, int rw)
+{
+  ptid_t ptid;
+  struct lwp_info *lp;
+  struct ppc_hw_breakpoint p;
+
+  gdb_assert (have_ptrace_booke_interface ());
+
+  p.version = PPC_DEBUG_CURRENT_VERSION;
+  p.trigger_type = get_trigger_type (rw);
+  p.addr_mode = PPC_BREAKPOINT_MODE_MASK;
+  p.condition_mode = PPC_BREAKPOINT_CONDITION_NONE;
+  p.addr = addr;
+  p.addr2 = mask;
+  p.condition_value = 0;
+
+  ALL_LWPS (lp, ptid)
+    booke_remove_point (&p, TIDGET (ptid));
+
+  return 0;
+}
+
 /* Check whether we have at least one free DVC register.  */
 static int
 can_use_watchpoint_cond_accel (void)
@@ -2224,6 +2282,26 @@ ppc_linux_watchpoint_addr_within_range (struct target_ops *target,
   return start <= addr + mask && start + length - 1 >= addr;
 }
 
+/* Return the number of registers needed for a masked hardware watchpoint.  */
+
+static int
+ppc_linux_masked_watch_num_registers (struct target_ops *target,
+				      CORE_ADDR addr, CORE_ADDR mask)
+{
+  if (!have_ptrace_booke_interface ()
+	   || (booke_debug_info.features & PPC_DEBUG_FEATURE_DATA_BP_MASK) == 0)
+    return -1;
+  else if ((mask & 0xC0000000) != 0xC0000000)
+    {
+      warning (_("The given mask covers kernel address space "
+		 "and cannot be used.\n"));
+
+      return -2;
+    }
+  else
+    return 2;
+}
+
 static void
 ppc_linux_store_inferior_registers (struct target_ops *ops,
 				    struct regcache *regcache, int regno)
@@ -2438,11 +2516,14 @@ _initialize_ppc_linux_nat (void)
   t->to_region_ok_for_hw_watchpoint = ppc_linux_region_ok_for_hw_watchpoint;
   t->to_insert_watchpoint = ppc_linux_insert_watchpoint;
   t->to_remove_watchpoint = ppc_linux_remove_watchpoint;
+  t->to_insert_mask_watchpoint = ppc_linux_insert_mask_watchpoint;
+  t->to_remove_mask_watchpoint = ppc_linux_remove_mask_watchpoint;
   t->to_stopped_by_watchpoint = ppc_linux_stopped_by_watchpoint;
   t->to_stopped_data_address = ppc_linux_stopped_data_address;
   t->to_watchpoint_addr_within_range = ppc_linux_watchpoint_addr_within_range;
   t->to_can_accel_watchpoint_condition
     = ppc_linux_can_accel_watchpoint_condition;
+  t->to_masked_watch_num_registers = ppc_linux_masked_watch_num_registers;
   t->to_ranged_break_num_registers = ppc_linux_ranged_break_num_registers;
 
   t->to_read_description = ppc_linux_read_description;
diff --git a/gdb/target.c b/gdb/target.c
index 1e1c38e..9c522cb 100644
--- a/gdb/target.c
+++ b/gdb/target.c
@@ -595,6 +595,8 @@ update_current_target (void)
       /* Do not inherit to_ranged_break_num_registers.  */
       INHERIT (to_insert_watchpoint, t);
       INHERIT (to_remove_watchpoint, t);
+      /* Do not inherit to_insert_mask_watchpoint.  */
+      /* Do not inherit to_remove_mask_watchpoint.  */
       INHERIT (to_stopped_data_address, t);
       INHERIT (to_have_steppable_watchpoint, t);
       INHERIT (to_have_continuable_watchpoint, t);
@@ -602,6 +604,7 @@ update_current_target (void)
       INHERIT (to_watchpoint_addr_within_range, t);
       INHERIT (to_region_ok_for_hw_watchpoint, t);
       INHERIT (to_can_accel_watchpoint_condition, t);
+      /* Do not inherit to_masked_watch_num_registers.  */
       INHERIT (to_terminal_init, t);
       INHERIT (to_terminal_inferior, t);
       INHERIT (to_terminal_ours_for_output, t);
@@ -3518,6 +3521,75 @@ target_verify_memory (const gdb_byte *data, CORE_ADDR memaddr, ULONGEST size)
   tcomplain ();
 }
 
+/* The documentation for this function is in its prototype declaration in
+   target.h.  */
+
+int
+target_insert_mask_watchpoint (CORE_ADDR addr, CORE_ADDR mask, int rw)
+{
+  struct target_ops *t;
+
+  for (t = current_target.beneath; t != NULL; t = t->beneath)
+    if (t->to_insert_mask_watchpoint != NULL)
+      {
+	int ret;
+
+	ret = t->to_insert_mask_watchpoint (t, addr, mask, rw);
+
+	if (targetdebug)
+	  fprintf_unfiltered (gdb_stdlog, "\
+target_insert_mask_watchpoint (%s, %s, %d) = %d\n",
+			      core_addr_to_string (addr),
+			      core_addr_to_string (mask), rw, ret);
+
+	return ret;
+      }
+
+  return 1;
+}
+
+/* The documentation for this function is in its prototype declaration in
+   target.h.  */
+
+int
+target_remove_mask_watchpoint (CORE_ADDR addr, CORE_ADDR mask, int rw)
+{
+  struct target_ops *t;
+
+  for (t = current_target.beneath; t != NULL; t = t->beneath)
+    if (t->to_remove_mask_watchpoint != NULL)
+      {
+	int ret;
+
+	ret = t->to_remove_mask_watchpoint (t, addr, mask, rw);
+
+	if (targetdebug)
+	  fprintf_unfiltered (gdb_stdlog, "\
+target_remove_mask_watchpoint (%s, %s, %d) = %d\n",
+			      core_addr_to_string (addr),
+			      core_addr_to_string (mask), rw, ret);
+
+	return ret;
+      }
+
+  return 1;
+}
+
+/* The documentation for this function is in its prototype declaration
+   in target.h.  */
+
+int
+target_masked_watch_num_registers (CORE_ADDR addr, CORE_ADDR mask)
+{
+  struct target_ops *t;
+
+  for (t = current_target.beneath; t != NULL; t = t->beneath)
+    if (t->to_masked_watch_num_registers != NULL)
+      return t->to_masked_watch_num_registers (t, addr, mask);
+
+  return -1;
+}
+
 /* The documentation for this function is in its prototype declaration
    in target.h.  */
 
diff --git a/gdb/target.h b/gdb/target.h
index 11380ed..52e0276 100644
--- a/gdb/target.h
+++ b/gdb/target.h
@@ -459,6 +459,10 @@ struct target_ops
     int (*to_remove_watchpoint) (CORE_ADDR, int, int, struct expression *);
     int (*to_insert_watchpoint) (CORE_ADDR, int, int, struct expression *);
 
+    int (*to_insert_mask_watchpoint) (struct target_ops *,
+				      CORE_ADDR, CORE_ADDR, int);
+    int (*to_remove_mask_watchpoint) (struct target_ops *,
+				      CORE_ADDR, CORE_ADDR, int);
     int (*to_stopped_by_watchpoint) (void);
     int to_have_steppable_watchpoint;
     int to_have_continuable_watchpoint;
@@ -472,6 +476,8 @@ struct target_ops
 
     int (*to_can_accel_watchpoint_condition) (CORE_ADDR, int, int,
 					      struct expression *);
+    int (*to_masked_watch_num_registers) (struct target_ops *,
+					  CORE_ADDR, CORE_ADDR);
     void (*to_terminal_init) (void);
     void (*to_terminal_inferior) (void);
     void (*to_terminal_ours_for_output) (void);
@@ -1362,6 +1368,20 @@ extern char *target_thread_name (struct thread_info *);
 #define	target_remove_watchpoint(addr, len, type, cond) \
      (*current_target.to_remove_watchpoint) (addr, len, type, cond)
 
+/* Insert a new masked watchpoint at ADDR using the mask MASK.
+   RW may be hw_read for a read watchpoint, hw_write for a write watchpoint
+   or hw_access for an access watchpoint.  Returns 0 for success, 1 if
+   masked watchpoints are not supported, -1 for failure.  */
+
+extern int target_insert_mask_watchpoint (CORE_ADDR, CORE_ADDR, int);
+
+/* Remove a masked watchpoint at ADDR with the mask MASK.
+   RW may be hw_read for a read watchpoint, hw_write for a write watchpoint
+   or hw_access for an access watchpoint.  Returns 0 for success, non-zero
+   for failure.  */
+
+extern int target_remove_mask_watchpoint (CORE_ADDR, CORE_ADDR, int);
+
 #define target_insert_hw_breakpoint(gdbarch, bp_tgt) \
      (*current_target.to_insert_hw_breakpoint) (gdbarch, bp_tgt)
 
@@ -1395,6 +1415,12 @@ extern int target_ranged_break_num_registers (void);
 #define target_can_accel_watchpoint_condition(addr, len, type, cond) \
   (*current_target.to_can_accel_watchpoint_condition) (addr, len, type, cond)
 
+/* Return number of debug registers needed for a masked watchpoint,
+   -1 if masked watchpoints are not supported or -2 if the given address
+   and mask combination cannot be used.  */
+
+extern int target_masked_watch_num_registers (CORE_ADDR addr, CORE_ADDR mask);
+
 /* Target can execute in reverse?  */
 #define target_can_execute_reverse \
      (current_target.to_can_execute_reverse ? \


^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [RFA 2/3] Demote to sw watchpoint only in update_watchpoint
  2011-04-29 17:26     ` Ulrich Weigand
@ 2011-05-03  4:56       ` Thiago Jung Bauermann
  2011-05-03  6:05         ` Eli Zaretskii
  2011-05-05 11:04         ` Ulrich Weigand
  0 siblings, 2 replies; 38+ messages in thread
From: Thiago Jung Bauermann @ 2011-05-03  4:56 UTC (permalink / raw)
  To: Ulrich Weigand; +Cc: gdb-patches ml

On Fri, 2011-04-29 at 19:26 +0200, Ulrich Weigand wrote: 
> Thiago Jung Bauermann wrote:
> > I decided that it was cleaner if watch_command_1 just delegated
> > everything to update_watchpoint. This patch makes it create a
> > watchpoint, call update_watchpoint and then delete it if some error is
> > hit. The only drawback I can think of is that the aborted watchpoint
> > will "consume" one breakpoint number, and thus GDB will skip one number
> > when creating the next breakpoint/watchpoint. This doesn't seem
> > important to me.
> 
> Hmm, I don't really like that change.  However, it should be easy to
> fix by just moving the set_breakpoint_number call to down below where
> update_watchpoint has succeeded, shouldn't it?

Indeed, it's quite simple. I wish I had thought of that. :-) This
version does what you say.

> > 	(delete_breakpoint): Add announce argument to control whether
> > 	observers are notified of the deletion.  Update all callers.
> 
> Ugh.  Adding an extra argument that everybody must be aware of just
> to take care of this special case isn't really nice ...  I'd prefer
> if you'd either split off the parts of delete_breakpoint that are
> needed to undo partial creation into a separate function, or else,
> if you use the set_breakpoint_number trick, identify partial
> breakpoints by the fact that their b->number is still zero.

Right. This version checks whether b->number is zero.

> > @@ -1432,8 +1436,22 @@ update_watchpoint (struct breakpoint *b, int reparse)
> >  	      target_resources_ok = target_can_use_hardware_watchpoint
> >  		    (bp_hardware_watchpoint, i, other_type_used);
> 
> This should now use b->type instead of hardcoding bp_hardware_watchpoint,
> shouldn't it?

No, because the line above it (on which the one you mention depends
because of the i variable) hardcodes bp_hardware_watchpoint:

              i = hw_watchpoint_used_count (bp_hardware_watchpoint,
                                            &other_type_used);

I hardcoded bp_hardware_watchpoint in an attempt to make read and access
watchpoints also count as hardware watchpoints when determining the
number of used and available debug resources (otherwise only watchpoints
of the same type as the one being created are taken into account when
counting how many debug resources are used).

I just realised it doesn't work, and to fix it I'd have to slightly
change the meaning of the other_type_used argument to be the number of
other types of watchpoints, instead of just one or zero indicated
whether there is any watchpoint of another type being used.

I didn't make the change because I don't know if there's any target
which would break. I couldn't find anywhere what other_type_used
actually means...

On the other hand, the current code is already broken in that regard,
and creating several read and access watchpoints on today's GDB will
confuse it and allow creating more hardware watchpoints (read, access or
regular) than possible. Thus, this patch doesn't make the situation any
worse. So now I just use b->type.

The real fix IMHO would be to make the -tdep code manage the creation
and deletion of bp_locations, so that it could always make an informed
decision about what can and cannot be done with the available hardware
debug resources. But that's out of the scope of this patch series.

> Otherwise looks good to me.

Nice! What about this version?
-- 
[]'s
Thiago Jung Bauermann
IBM Linux Technology Center


Demote to sw watchpoint only in update_watchpoint.

2011-05-03  Thiago Jung Bauermann  <bauerman@br.ibm.com>

	* breakpoint.c (update_watchpoint): Change between software and
	hardware watchpoint for all kinds of watchpoints, not just
	read/write ones.  Determine b->exact value here instead of
	in watch_command_1.  Error out if there are not enough resources
	for a read or access hardware watchpoint.
	(watch_command_1): Remove logic of checking whether there are
	enough resources available, since update_watchpoint will do that
	work now.  Don't set b->exact here.  Catch exceptions thrown by
	update_watchpoint and delete the watchpoint.
	(can_use_hardware_watchpoint): Remove exact_watchpoints argument.
	Use target_exact_watchpoints instead.
	(delete_breakpoint): Notify observers only if deleted watchpoint
	has a breakpoint number assigned to it.

diff --git a/gdb/breakpoint.c b/gdb/breakpoint.c
index e265135..8358dac 100644
--- a/gdb/breakpoint.c
+++ b/gdb/breakpoint.c
@@ -101,7 +101,7 @@ static void clear_command (char *, int);
 
 static void catch_command (char *, int);
 
-static int can_use_hardware_watchpoint (struct value *, int);
+static int can_use_hardware_watchpoint (struct value *);
 
 static void break_command_1 (char *, int, int);
 
@@ -1404,19 +1404,22 @@ update_watchpoint (struct breakpoint *b, int reparse)
 	 an ordinary watchpoint depending on the hardware support
 	 and free hardware slots.  REPARSE is set when the inferior
 	 is started.  */
-      if ((b->type == bp_watchpoint || b->type == bp_hardware_watchpoint)
-	  && reparse)
+      if (reparse)
 	{
 	  int reg_cnt;
 	  enum bp_loc_type loc_type;
 	  struct bp_location *bl;
 
-	  reg_cnt = can_use_hardware_watchpoint (val_chain, b->exact);
+	  reg_cnt = can_use_hardware_watchpoint (val_chain);
 
 	  if (reg_cnt)
 	    {
 	      int i, target_resources_ok, other_type_used;
 
+	      /* Use an exact watchpoint when there's only one memory region to be
+		 watched, and only one debug register is needed to watch it.  */
+	      b->exact = target_exact_watchpoints && reg_cnt == 1;
+
 	      /* We need to determine how many resources are already
 		 used for all other hardware watchpoints plus this one
 		 to see if we still have enough resources to also fit
@@ -1424,16 +1427,29 @@ update_watchpoint (struct breakpoint *b, int reparse)
 		 hw_watchpoint_used_count call below counts this
 		 watchpoint, make sure that it is marked as a hardware
 		 watchpoint.  */
-	      b->type = bp_hardware_watchpoint;
-
-	      i = hw_watchpoint_used_count (bp_hardware_watchpoint,
-					    &other_type_used);
+	      if (b->type == bp_watchpoint)
+		b->type = bp_hardware_watchpoint;
 
+	      i = hw_watchpoint_used_count (b->type, &other_type_used);
 	      target_resources_ok = target_can_use_hardware_watchpoint
-		    (bp_hardware_watchpoint, i, other_type_used);
+		    (b->type, i, other_type_used);
 	      if (target_resources_ok <= 0)
-		b->type = bp_watchpoint;
+		{
+		  if (target_resources_ok == 0
+		      && b->type != bp_hardware_watchpoint)
+		    error (_("Target does not support this type of "
+			     "hardware watchpoint."));
+		  else if (target_resources_ok < 0
+		      && b->type != bp_hardware_watchpoint)
+		    error (_("Target can only support one kind "
+			     "of HW watchpoint at a time."));
+		  else
+		    b->type = bp_watchpoint;
+		}
 	    }
+	  else if (b->type != bp_hardware_watchpoint)
+	    error (_("Expression cannot be implemented with "
+		     "read/access watchpoint."));
 	  else
 	    b->type = bp_watchpoint;
 
@@ -8783,6 +8799,7 @@ static void
 watch_command_1 (char *arg, int accessflag, int from_tty,
 		 int just_location, int internal)
 {
+  volatile struct gdb_exception e;
   struct breakpoint *b, *scope_breakpoint = NULL;
   struct expression *exp;
   struct block *exp_valid_block = NULL, *cond_exp_valid_block = NULL;
@@ -8794,9 +8811,7 @@ watch_command_1 (char *arg, int accessflag, int from_tty,
   int toklen;
   char *cond_start = NULL;
   char *cond_end = NULL;
-  int i, other_type_used, target_resources_ok = 0;
   enum bptype bp_type;
-  int reg_cnt = 0;
   int thread = -1;
   int pc = 0;
 
@@ -8926,28 +8941,6 @@ watch_command_1 (char *arg, int accessflag, int from_tty,
   else
     bp_type = bp_hardware_watchpoint;
 
-  reg_cnt = can_use_hardware_watchpoint (val, target_exact_watchpoints);
-  if (reg_cnt == 0 && bp_type != bp_hardware_watchpoint)
-    error (_("Expression cannot be implemented with read/access watchpoint."));
-  if (reg_cnt != 0)
-    {
-      i = hw_watchpoint_used_count (bp_type, &other_type_used);
-      target_resources_ok = 
-	target_can_use_hardware_watchpoint (bp_type, i + reg_cnt,
-					    other_type_used);
-      if (target_resources_ok == 0 && bp_type != bp_hardware_watchpoint)
-	error (_("Target does not support this type of hardware watchpoint."));
-
-      if (target_resources_ok < 0 && bp_type != bp_hardware_watchpoint)
-	error (_("Target can only support one kind "
-		 "of HW watchpoint at a time."));
-    }
-
-  /* Change the type of breakpoint to an ordinary watchpoint if a
-     hardware watchpoint could not be set.  */
-  if (!reg_cnt || target_resources_ok <= 0)
-    bp_type = bp_watchpoint;
-
   frame = block_innermost_frame (exp_valid_block);
 
   /* If the expression is "local", then set up a "watchpoint scope"
@@ -8985,7 +8978,6 @@ watch_command_1 (char *arg, int accessflag, int from_tty,
 
   /* Now set up the breakpoint.  */
   b = set_raw_breakpoint_without_location (NULL, bp_type);
-  set_breakpoint_number (internal, b);
   b->thread = thread;
   b->disposition = disp_donttouch;
   b->exp = exp;
@@ -9016,10 +9008,6 @@ watch_command_1 (char *arg, int accessflag, int from_tty,
   b->val_valid = 1;
   b->ops = &watchpoint_breakpoint_ops;
 
-  /* Use an exact watchpoint when there's only one memory region to be
-     watched, and only one debug register is needed to watch it.  */
-  b->exact = target_exact_watchpoints && reg_cnt == 1;
-
   if (cond_start)
     b->cond_string = savestring (cond_start, cond_end - cond_start);
   else
@@ -9047,12 +9035,22 @@ watch_command_1 (char *arg, int accessflag, int from_tty,
   if (!just_location)
     value_free_to_mark (mark);
 
-  /* Finally update the new watchpoint.  This creates the locations
-     that should be inserted.  */
-  update_watchpoint (b, 1);
+  TRY_CATCH (e, RETURN_MASK_ALL)
+    {
+      /* Finally update the new watchpoint.  This creates the locations
+	 that should be inserted.  */
+      update_watchpoint (b, 1);
+    }
+  if (e.reason < 0)
+    {
+      delete_breakpoint (b);
+      throw_exception (e);
+    }
+
+  set_breakpoint_number (internal, b);
 
   /* Do not mention breakpoints with a negative number, but do
-       notify observers.  */
+     notify observers.  */
   if (!internal)
     mention (b);
   observer_notify_breakpoint_created (b);
@@ -9061,14 +9059,10 @@ watch_command_1 (char *arg, int accessflag, int from_tty,
 }
 
 /* Return count of debug registers needed to watch the given expression.
-   If EXACT_WATCHPOINTS is 1, then consider that only the address of
-   the start of the watched region will be monitored (i.e., all accesses
-   will be aligned).  This uses less debug registers on some targets.
-
    If the watchpoint cannot be handled in hardware return zero.  */
 
 static int
-can_use_hardware_watchpoint (struct value *v, int exact_watchpoints)
+can_use_hardware_watchpoint (struct value *v)
 {
   int found_memory_cnt = 0;
   struct value *head = v;
@@ -9124,7 +9118,7 @@ can_use_hardware_watchpoint (struct value *v, int exact_watchpoints)
 		  int len;
 		  int num_regs;
 
-		  len = (exact_watchpoints
+		  len = (target_exact_watchpoints
 			 && is_scalar_type_recursive (vtype))?
 		    1 : TYPE_LENGTH (value_type (v));
 
@@ -10483,7 +10477,12 @@ delete_breakpoint (struct breakpoint *bpt)
       bpt->related_breakpoint = bpt;
     }
 
-  observer_notify_breakpoint_deleted (bpt);
+  /* watch_command_1 creates a watchpoint but only sets its number if
+     update_watchpoint succeeds in creating its bp_locations.  If there's
+     a problem in that process, we'll be asked to delete the half-created
+     watchpoint.  In that case, don't announce the deletion.  */
+  if (bpt->number)
+    observer_notify_breakpoint_deleted (bpt);
 
   if (breakpoint_chain == bpt)
     breakpoint_chain = bpt->next;



^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [RFA 2/3] Demote to sw watchpoint only in update_watchpoint
  2011-05-03  4:56       ` Thiago Jung Bauermann
@ 2011-05-03  6:05         ` Eli Zaretskii
  2011-05-03  9:58           ` Pedro Alves
  2011-05-04 19:12           ` Thiago Jung Bauermann
  2011-05-05 11:04         ` Ulrich Weigand
  1 sibling, 2 replies; 38+ messages in thread
From: Eli Zaretskii @ 2011-05-03  6:05 UTC (permalink / raw)
  To: Thiago Jung Bauermann; +Cc: uweigand, gdb-patches

> From: Thiago Jung Bauermann <bauerman@br.ibm.com>
> Cc: gdb-patches ml <gdb-patches@sourceware.org>
> Date: Tue, 03 May 2011 01:55:46 -0300
> 
> I hardcoded bp_hardware_watchpoint in an attempt to make read and access
> watchpoints also count as hardware watchpoints when determining the
> number of used and available debug resources (otherwise only watchpoints
> of the same type as the one being created are taken into account when
> counting how many debug resources are used).
> 
> I just realised it doesn't work, and to fix it I'd have to slightly
> change the meaning of the other_type_used argument to be the number of
> other types of watchpoints, instead of just one or zero indicated
> whether there is any watchpoint of another type being used.
> 
> I didn't make the change because I don't know if there's any target
> which would break. I couldn't find anywhere what other_type_used
> actually means...
> 
> On the other hand, the current code is already broken in that regard,
> and creating several read and access watchpoints on today's GDB will
> confuse it and allow creating more hardware watchpoints (read, access or
> regular) than possible. Thus, this patch doesn't make the situation any
> worse. So now I just use b->type.

Sorry, but I object.  This kind of changes just adds kludges upon
kludges on what is a fundamentally broken design to begin with.  It
was originally designed and implemented for a single platform (which
we no longer support, btw), and doesn't scale well, or not at all, to
other platforms, not even to x86.

The problem with the meaning of the other_type_used argument is the
telltale sign: it only made sense for that single platform for which
hardware watchpoints were originally implemented in GDB.  It no longer
makes any sense with today's platforms, and actually cannot be used at
all with most of them (at least those I'm familiar with), for a very
simple reason: a single `int' parameter doesn't provide a way to
report enough information about the consumption of related resources.
It doesn't matter if that parameter is a boolean or not; it simply
isn't up to this job.  Much more information is needed about the
related resources to decide whether another watchpoint can or cannot
be set.

The fundamental design problem here is this: there's no way GDB
application level can know whether the target can accommodate an
additional hardware watchpoint of a given type and attributes.  Only
the target itself can tell that accurately, because the information
needed to answer that question is extremely target-dependent.  OTOH,
it is bad UI design to let the user set a hardware watchpoint, then
demote it to a software watchpoint (or even refuse to insert a
watchpoint at all) at "resume" time.  So on the one hand, we _want_
the GDB application level to know if a hardware watchpoint is
possible, to tell the user it cannot, and OTOH there's a problem
knowing this at that level.

We should resolve this conflict in the most direct way: introduce a
method, to be implemented by each target, that will answer these
questions.  It should accept the exact spec of the new watchpoint, and
it should have access to the watchpoints and breakpoints already set,
including their full specs.  With that information in hand, a target
can reliably produce a definitive response, at least in the vast
majority of cases, when the corresponding resources are under GDB
control.

To avoid breaking too many targets, the default implementation should
be what we do now.  This will make the result no worse than the
current code.

Let's solve this problem once and for all.  Any other way of treating
this problem will only sweep it under the carpet for a few more months
or years, until some other advanced platform comes out that needs more
kludgeying.  The result will be (already is) code that is hard to
maintain and that is in real danger of breaking platforms other than
the one which needs the patch.  When will it stop?

> The real fix IMHO would be to make the -tdep code manage the creation
> and deletion of bp_locations, so that it could always make an informed
> decision about what can and cannot be done with the available hardware
> debug resources.

Exactly!

> But that's out of the scope of this patch series.

I say, let's stop postponing this to some other patch series.  I've
been to that movie enough to know that it's a polite form of saying
"never".

Sorry for being so blunt, but I think this problem is well past the
time we should have solved it for good.

^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [needs doc review] Re: [RFA 3/3] Implement support for PowerPC BookE masked watchpoints
  2011-05-03  4:56       ` [needs doc review] " Thiago Jung Bauermann
@ 2011-05-03  6:24         ` Eli Zaretskii
  2011-05-05 21:57           ` Thiago Jung Bauermann
  2011-05-05 11:07         ` Ulrich Weigand
  1 sibling, 1 reply; 38+ messages in thread
From: Eli Zaretskii @ 2011-05-03  6:24 UTC (permalink / raw)
  To: Thiago Jung Bauermann; +Cc: uweigand, gdb-patches

> From: Thiago Jung Bauermann <bauerman@br.ibm.com>
> Cc: gdb-patches ml <gdb-patches@sourceware.org>
> Date: Tue, 03 May 2011 01:55:54 -0300
> 
>   The @code{@r{[}mask @var{maskvalue}@r{]}} argument allows creation
>   of masked watchpoints, if the current architecture supports this
>   feature.  (Currently, this is only available on PowerPC Embedded
>   architecture, see @ref{PowerPC Embedded}.)  Specifying a mask argument
>   implies the @code{-location} argument.

I would prefer to avoid text in the manual that could easily become
obsolete tomorrow: we don't have any efficient mechanism in place to
tell us to revise such text.  So instead of

  (Currently, this is only available on PowerPC Embedded architecture,
  see @ref{PowerPC Embedded}.)

I would prefer either to say nothing, or use a more vague phrase,
without the too-decisive "currently, available only on...".  Like
this, for example:

  The @code{@r{[}mask @var{maskvalue}@r{]}} argument allows creation
  of masked watchpoints, if the current architecture supports this
  feature (e.g., PowerPC Embedded architecture, see @ref{PowerPC
  Embedded}.)

>   A @dfn{masked watchpoint} specifies a mask in addition to an address
>   to watch.  The mask specifies that some bits of an address (the bits
>   which are reset in the mask) should be ignored when matching the
>   address accessed by the inferior against the watchpoint address.
>   Thus, a masked watchpoint watches many addresses
>   simultaneously---those addresses whose unmasked bits are identical
>   to the unmasked bits in the watchpoint address.
> 
> became
> 
>   A @dfn{masked watchpoint} specifies a mask in addition to an address
>   to watch.  The @code{mask} argument implies the @code{-location}
>   argument, which means that the expression will be resolved to a memory
>   address at watchpoint creation time (@pxref{Set Watchpoints}.)

What do you mean by "implies"?  Do you mean that -location must be
specified if "mask" is specified?  If so, "implies" is not a good
word.

I also don't really understand the part about "resolving to a memory
address at watchpoint creation time".  What were you trying to say?

Thanks.

^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [RFA 2/3] Demote to sw watchpoint only in update_watchpoint
  2011-05-03  6:05         ` Eli Zaretskii
@ 2011-05-03  9:58           ` Pedro Alves
  2011-05-03 16:57             ` Eli Zaretskii
  2011-05-04 19:12           ` Thiago Jung Bauermann
  1 sibling, 1 reply; 38+ messages in thread
From: Pedro Alves @ 2011-05-03  9:58 UTC (permalink / raw)
  To: gdb-patches, Eli Zaretskii; +Cc: Thiago Jung Bauermann, uweigand

On Tuesday 03 May 2011 07:05:35, Eli Zaretskii wrote:
> We should resolve this conflict in the most direct way: introduce a
> method, to be implemented by each target, that will answer these
> questions.  It should accept the exact spec of the new watchpoint, and
> it should have access to the watchpoints and breakpoints already set,
> including their full specs.  With that information in hand, a target
> can reliably produce a definitive response, at least in the vast
> majority of cases, when the corresponding resources are under GDB
> control.

Consider:

 gdb core -> target_ops -> remote -> remote stub -> debug API (something that actually inserts/remove watchpoints, and hides resource accounting details)

Currently, the accounting is done between gdb core and the target_ops
implementation, using target methods.

Many debug support libraries (that abstract access to jtag,
for example), and debug APIs (like ptrace) don't expose programatic methods
to do resource accounting to be able to implement such new method either.
They may even do watchpoint merging themselves (e.g., overlapping watchpoints
consume only one registers, instead of two), making it impossibly to
implement the new method other than always returning "it fits".
With such targets, the only reliable way to know whether the watchpoint
resources haven't been exausted, is to actually try to insert the watchpoint.
But this should work for the simplest APIs, like those where the backend
manages a finite set of debug registers (like most i386 backends).

What if we tried to make GDB do that instead? (try inserting
watchpoint immediately, instead of trying to do any sort of
accounting.)

-- 
Pedro Alves

^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [RFA 2/3] Demote to sw watchpoint only in update_watchpoint
  2011-05-03  9:58           ` Pedro Alves
@ 2011-05-03 16:57             ` Eli Zaretskii
  2011-05-03 17:41               ` Pedro Alves
  0 siblings, 1 reply; 38+ messages in thread
From: Eli Zaretskii @ 2011-05-03 16:57 UTC (permalink / raw)
  To: Pedro Alves; +Cc: gdb-patches, bauerman, uweigand

> From: Pedro Alves <pedro@codesourcery.com>
> Date: Tue, 3 May 2011 10:58:44 +0100
> Cc: Thiago Jung Bauermann <bauerman@br.ibm.com>,
>  uweigand@de.ibm.com
> 
> What if we tried to make GDB do that instead? (try inserting
> watchpoint immediately, instead of trying to do any sort of
> accounting.)

That could work, but won't it get us in trouble, e.g., when there are
other threads running?  They could inadvertently hit those watchpoints
while we are trying to insert them, no?

Or we could let targets which needs that (e.g., those using jtag as
you described) try inserting the watchpoints to respond to GDB's
request in target_can_use_hardware_watchpoint.  Other targets, which
can decide that without inserting, would not need to do that.

WDYT?

^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [RFA 2/3] Demote to sw watchpoint only in update_watchpoint
  2011-05-03 16:57             ` Eli Zaretskii
@ 2011-05-03 17:41               ` Pedro Alves
  2011-05-03 18:03                 ` Eli Zaretskii
  0 siblings, 1 reply; 38+ messages in thread
From: Pedro Alves @ 2011-05-03 17:41 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: gdb-patches, bauerman, uweigand

On Tuesday 03 May 2011 17:55:53, Eli Zaretskii wrote:
> > From: Pedro Alves <pedro@codesourcery.com>
> > Date: Tue, 3 May 2011 10:58:44 +0100
> > Cc: Thiago Jung Bauermann <bauerman@br.ibm.com>,
> >  uweigand@de.ibm.com
> > 
> > What if we tried to make GDB do that instead? (try inserting
> > watchpoint immediately, instead of trying to do any sort of
> > accounting.)
> 
> That could work, but won't it get us in trouble, e.g., when there are
> other threads running?  They could inadvertently hit those watchpoints
> while we are trying to insert them, no?

That would be no trouble, I think.  If we're midway trying to insert
them, it should be okay to hit them.  The problem case I can think of
is if we're installing e.g., 3 (low-level) watchpoints locations for a
single watchpoint, say, and we fail on the third.  When that
happens, we need to delete the first two watchpoints locations.  A thread
may meanwhile hit one of those watchpoints, and gdb would only see the
event _after_ the watchpoint location being long deleted.  But, GDB already
has to handle this situation situation anyway, because it's
what happens when you simply delete a watchpoint in non-stop
mode -- GDB will simply ignore such watchpoint events it can't explain.

> 
> Or we could let targets which needs that (e.g., those using jtag as
> you described) try inserting the watchpoints to respond to GDB's
> request in target_can_use_hardware_watchpoint.  Other targets, which
> can decide that without inserting, would not need to do that.
> 
> WDYT?

The main point/win of the suggestion was avoiding the whole
resource accounting infrastructure, getting away without adding
a bunch of (what looks to me at this point, unnecessary) target
methods/packets/logic.

-- 
Pedro Alves

^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [RFA 2/3] Demote to sw watchpoint only in update_watchpoint
  2011-05-03 17:41               ` Pedro Alves
@ 2011-05-03 18:03                 ` Eli Zaretskii
  2011-05-03 18:12                   ` Pedro Alves
  0 siblings, 1 reply; 38+ messages in thread
From: Eli Zaretskii @ 2011-05-03 18:03 UTC (permalink / raw)
  To: Pedro Alves; +Cc: gdb-patches, bauerman, uweigand

> From: Pedro Alves <pedro@codesourcery.com>
> Date: Tue, 3 May 2011 18:41:46 +0100
> Cc: gdb-patches@sourceware.org,
>  bauerman@br.ibm.com,
>  uweigand@de.ibm.com
> 
> > Or we could let targets which needs that (e.g., those using jtag as
> > you described) try inserting the watchpoints to respond to GDB's
> > request in target_can_use_hardware_watchpoint.  Other targets, which
> > can decide that without inserting, would not need to do that.
> > 
> > WDYT?
> 
> The main point/win of the suggestion was avoiding the whole
> resource accounting infrastructure, getting away without adding
> a bunch of (what looks to me at this point, unnecessary) target
> methods/packets/logic.

At least for x86, the resource accounting is necessary, because that
is what allows us to have several watchpoints sharing the same debug
register.  Targets that already have this resource accounting may well
use it to return accurate results to target_can_use_hardware_watchpoint
without actually going to the metal or the kernel.

^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [RFA 2/3] Demote to sw watchpoint only in update_watchpoint
  2011-05-03 18:03                 ` Eli Zaretskii
@ 2011-05-03 18:12                   ` Pedro Alves
  2011-05-03 20:30                     ` Eli Zaretskii
  0 siblings, 1 reply; 38+ messages in thread
From: Pedro Alves @ 2011-05-03 18:12 UTC (permalink / raw)
  To: gdb-patches, Eli Zaretskii; +Cc: bauerman, uweigand

On Tuesday 03 May 2011 19:02:39, Eli Zaretskii wrote:
> > The main point/win of the suggestion was avoiding the whole
> > resource accounting infrastructure, getting away without adding
> > a bunch of (what looks to me at this point, unnecessary) target
> > methods/packets/logic.
> 
> At least for x86, the resource accounting is necessary, because that
> is what allows us to have several watchpoints sharing the same debug
> register.  

Right, I meant the accounting instructure on the core side.  For
x86, i386-nat.c would stay as is.  The merging is done at insert
time currently, and it would stay the same.  The difference would
be that gdb would insert the watchpoint as soon as the user wanted
it, instead of calling some "may I create this?" mechanism.

> Targets that already have this resource accounting may well
> use it to return accurate results to target_can_use_hardware_watchpoint
> without actually going to the metal or the kernel.

I'm proposing getting rid of target_can_use_hardware_watchpoint
as being part of the core accounting infrastructure.
I'm trying to think of a use case that makes it necessary to know
if the watchpoints will fit before creating them, but I'm not
coming up with any.

-- 
Pedro Alves

^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [RFA 2/3] Demote to sw watchpoint only in update_watchpoint
  2011-05-03 18:12                   ` Pedro Alves
@ 2011-05-03 20:30                     ` Eli Zaretskii
  2011-05-04  0:03                       ` Thiago Jung Bauermann
  0 siblings, 1 reply; 38+ messages in thread
From: Eli Zaretskii @ 2011-05-03 20:30 UTC (permalink / raw)
  To: Pedro Alves; +Cc: gdb-patches, bauerman, uweigand

> From: Pedro Alves <pedro@codesourcery.com>
> Date: Tue, 3 May 2011 19:12:42 +0100
> Cc: bauerman@br.ibm.com,
>  uweigand@de.ibm.com
> 
> I'm proposing getting rid of target_can_use_hardware_watchpoint
> as being part of the core accounting infrastructure.

I'm fine with heading that way.  It will certainly be cleaner than the
current mess, which needs a face-lift every few months.

^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [RFA 2/3] Demote to sw watchpoint only in update_watchpoint
  2011-05-03 20:30                     ` Eli Zaretskii
@ 2011-05-04  0:03                       ` Thiago Jung Bauermann
  2011-05-04  3:07                         ` Eli Zaretskii
  0 siblings, 1 reply; 38+ messages in thread
From: Thiago Jung Bauermann @ 2011-05-04  0:03 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: Pedro Alves, gdb-patches, uweigand

On Tue, 2011-05-03 at 23:29 +0300, Eli Zaretskii wrote:
> > From: Pedro Alves <pedro@codesourcery.com>
> > Date: Tue, 3 May 2011 19:12:42 +0100
> > Cc: bauerman@br.ibm.com,
> >  uweigand@de.ibm.com
> > 
> > I'm proposing getting rid of target_can_use_hardware_watchpoint
> > as being part of the core accounting infrastructure.
> 
> I'm fine with heading that way.  It will certainly be cleaner than the
> current mess, which needs a face-lift every few months.

For this scheme to work, GDB will have to be changed to use
always-inserted mode exclusively, right? Or at least insert all
breakpoints and watchpoints when probing whether a new
breakpoint/watchpoint can be created.
-- 
[]'s
Thiago Jung Bauermann
IBM Linux Technology Center

^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [RFA 1/3] Change watchpoint's enable state in do_enable_breakpoint
  2011-04-29 17:21     ` Ulrich Weigand
@ 2011-05-04  0:11       ` Thiago Jung Bauermann
  0 siblings, 0 replies; 38+ messages in thread
From: Thiago Jung Bauermann @ 2011-05-04  0:11 UTC (permalink / raw)
  To: gdb-patches ml

On Fri, 2011-04-29 at 19:21 +0200, Ulrich Weigand wrote:
> Thiago Jung Bauermann wrote:
> 
> > 2011-04-18  Thiago Jung Bauermann  <bauerman@br.ibm.com>
> > 
> > 	* breakpoint.c (update_watchpoint): Move code to change
> > 	the enable state of breakpoint from here ...
> > 	(do_enable_breakpoint): ... to here.
> 
> Yes, I think this makes sense.  OK.

I committed this patch yesterday night. I sent an e-mail stating so, but
I just noticed that I sent it only to Ulrich. D'oh.
-- 
[]'s
Thiago Jung Bauermann
IBM Linux Technology Center

^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [RFA 2/3] Demote to sw watchpoint only in update_watchpoint
  2011-05-04  0:03                       ` Thiago Jung Bauermann
@ 2011-05-04  3:07                         ` Eli Zaretskii
  2011-05-04 22:21                           ` Thiago Jung Bauermann
  0 siblings, 1 reply; 38+ messages in thread
From: Eli Zaretskii @ 2011-05-04  3:07 UTC (permalink / raw)
  To: Thiago Jung Bauermann; +Cc: pedro, gdb-patches, uweigand

> From: Thiago Jung Bauermann <bauerman@br.ibm.com>
> Cc: Pedro Alves <pedro@codesourcery.com>, gdb-patches@sourceware.org,
>         uweigand@de.ibm.com
> Date: Tue, 03 May 2011 21:03:06 -0300
> 
> On Tue, 2011-05-03 at 23:29 +0300, Eli Zaretskii wrote:
> > > From: Pedro Alves <pedro@codesourcery.com>
> > > Date: Tue, 3 May 2011 19:12:42 +0100
> > > Cc: bauerman@br.ibm.com,
> > >  uweigand@de.ibm.com
> > > 
> > > I'm proposing getting rid of target_can_use_hardware_watchpoint
> > > as being part of the core accounting infrastructure.
> > 
> > I'm fine with heading that way.  It will certainly be cleaner than the
> > current mess, which needs a face-lift every few months.
> 
> For this scheme to work, GDB will have to be changed to use
> always-inserted mode exclusively, right? Or at least insert all
> breakpoints and watchpoints when probing whether a new
> breakpoint/watchpoint can be created.

I think what Pedro suggests can (and should) work only for hardware
watchpoints and breakpoints.  Normal breakpoints and watchpoints
cannot work that way, they must be inserted at "resume" time.

So I think always-inserted mode is not the right way here, unless I'm
missing something.

^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [RFA 2/3] Demote to sw watchpoint only in update_watchpoint
  2011-05-03  6:05         ` Eli Zaretskii
  2011-05-03  9:58           ` Pedro Alves
@ 2011-05-04 19:12           ` Thiago Jung Bauermann
  2011-05-04 20:31             ` Eli Zaretskii
  1 sibling, 1 reply; 38+ messages in thread
From: Thiago Jung Bauermann @ 2011-05-04 19:12 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: uweigand, gdb-patches

Hi Eli,

On Tue, 2011-05-03 at 02:05 -0400, Eli Zaretskii wrote:
> It was originally designed and implemented for a single platform (which
> we no longer support, btw), and doesn't scale well, or not at all, to
> other platforms, not even to x86.
> 
> The problem with the meaning of the other_type_used argument is the
> telltale sign: it only made sense for that single platform for which
> hardware watchpoints were originally implemented in GDB.  It no longer
> makes any sense with today's platforms, and actually cannot be used at
> all with most of them (at least those I'm familiar with), for a very
> simple reason: a single `int' parameter doesn't provide a way to
> report enough information about the consumption of related resources.
> It doesn't matter if that parameter is a boolean or not; it simply
> isn't up to this job.  Much more information is needed about the
> related resources to decide whether another watchpoint can or cannot
> be set.

This was hard for me to evaluate as I didn't find anywhere what
other_type_used was ever meant to be. Not even in the patch submission
that introduced it. Thanks for the insight.

> The fundamental design problem here is this: there's no way GDB
> application level can know whether the target can accommodate an
> additional hardware watchpoint of a given type and attributes.  Only
> the target itself can tell that accurately, because the information
> needed to answer that question is extremely target-dependent.  OTOH,
> it is bad UI design to let the user set a hardware watchpoint, then
> demote it to a software watchpoint (or even refuse to insert a
> watchpoint at all) at "resume" time.  So on the one hand, we _want_
> the GDB application level to know if a hardware watchpoint is
> possible, to tell the user it cannot, and OTOH there's a problem
> knowing this at that level.

GDB doesn't have a command to create a hardware watchpoint or a software
watchpoint. It will decide which will be created based on what it thinks
can be done. Do you think this should be changed and there should be an
hwatch command which would fail if an hw watchpoint is not possible? Or
just that a watchpoint should never be converted between sw and hw after
they are created?

> > But that's out of the scope of this patch series.
> 
> I say, let's stop postponing this to some other patch series.  I've
> been to that movie enough to know that it's a polite form of saying
> "never".

In the particular case of this patch, I think this reasoning is
misplaced. It may not have been clear in my previous message, but what I
was saying was that I tried to attack the problem in a minimally
intrusive way (i.e., a kludge :-) ) but gave up and left the code
basically untouched.

I said that fixing the problem was out of the scope of this patch series
meaning "I was developing the feature and I noticed this problem. I
tried to solve it while I was at it but things got involved". So I don't
think it's fair to say "You tried to address that problem and even
mentioned in your patch submission, now you have to fix it!"

This is GDB's behaviour without this patch:

(gdb) awatch a
Hardware access (read/write) watchpoint 6: a
(gdb) rwatch c
Hardware read watchpoint 7: c
(gdb) watch d
Hardware watchpoint 8: d
(gdb) i b
Num     Type            Disp Enb Address    What
6       acc watchpoint  keep y              a
7       read watchpoint keep y              c
8       hw watchpoint   keep y              d
(gdb) c
Continuing.
Unexpected error setting breakpoint or watchpoint: No space left on device.
(gdb)

and this is the behaviour with the patch:

(gdb) awatch a
Hardware access (read/write) watchpoint 2: a
(gdb) rwatch c
Hardware read watchpoint 3: c
(gdb) watch d
Hardware watchpoint 4: d
(gdb) i b
Num     Type            Disp Enb Address    What
2       acc watchpoint  keep y              a
3       read watchpoint keep y              c
4       hw watchpoint   keep y              d
(gdb) c
Continuing.
Warning:
Could not insert hardware watchpoint 3.
Could not insert hardware watchpoint 4.
Could not insert hardware breakpoints:
You may have requested too many hardware breakpoints/watchpoints.

(gdb)

So the problem is still there. It's not better, but not worse either.
The output is slightly different because of the better error handling
this patch introduces. Thus, IMHO overhauling resources handling is not
a prerequisite or even directly related to this patch (or the next one
in the series). The acceptance or rejection of this patch is orthogonal
to that.

Having said that, I agree that it's a shame that GDB can't keep track of
debug hardware availability, something that one would expect to be among
the basic tasks of a debugger. So if we can agree on how GDB should deal
with the problem, I'm willing to work on it on a best effort basis
(meaning that I wouldn't have much time to dedicate to this, but would
eventually make progress).

> Sorry for being so blunt, but I think this problem is well past the
> time we should have solved it for good.

No need to apologize. I understand your frustration, especially since I
read the discussion you and Cagney had in 2002 about this very topic,
and nothing actually changed since then...
-- 
[]'s
Thiago Jung Bauermann
IBM Linux Technology Center

^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [RFA 2/3] Demote to sw watchpoint only in update_watchpoint
  2011-05-04 19:12           ` Thiago Jung Bauermann
@ 2011-05-04 20:31             ` Eli Zaretskii
  2011-05-04 22:22               ` Thiago Jung Bauermann
  0 siblings, 1 reply; 38+ messages in thread
From: Eli Zaretskii @ 2011-05-04 20:31 UTC (permalink / raw)
  To: Thiago Jung Bauermann; +Cc: uweigand, gdb-patches

> From: Thiago Jung Bauermann <bauerman@br.ibm.com>
> Cc: uweigand@de.ibm.coma, gdb-patches@sourceware.org
> Date: Wed, 04 May 2011 16:12:24 -0300
> 
> GDB doesn't have a command to create a hardware watchpoint or a software
> watchpoint. It will decide which will be created based on what it thinks
> can be done. Do you think this should be changed and there should be an
> hwatch command which would fail if an hw watchpoint is not possible? Or
> just that a watchpoint should never be converted between sw and hw after
> they are created?

It certainly is bad to have the demotion happen when you resume the
inferior.  Pedro's suggestion resolves this as well, because the
problem will be revealed at "watch foo" time.  If and when we
implement that, there will be no need for "hwatch", I think, as the
user will see the problem on the spot and can take corrective actions
in time.

> So the problem is still there. It's not better, but not worse either.
> The output is slightly different because of the better error handling
> this patch introduces. Thus, IMHO overhauling resources handling is not
> a prerequisite or even directly related to this patch (or the next one
> in the series). The acceptance or rejection of this patch is orthogonal
> to that.

Fair enough.  I withdraw my objections to the patch.

> Having said that, I agree that it's a shame that GDB can't keep track of
> debug hardware availability, something that one would expect to be among
> the basic tasks of a debugger. So if we can agree on how GDB should deal
> with the problem, I'm willing to work on it on a best effort basis
> (meaning that I wouldn't have much time to dedicate to this, but would
> eventually make progress).

Thank you.  I think Pedro's idea is already on the table, and no one
objected to it.  If it is feasible, I'd say let's do it that way.

^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [RFA 2/3] Demote to sw watchpoint only in update_watchpoint
  2011-05-04  3:07                         ` Eli Zaretskii
@ 2011-05-04 22:21                           ` Thiago Jung Bauermann
  2011-05-05  3:09                             ` Eli Zaretskii
  2011-05-05  8:15                             ` Pedro Alves
  0 siblings, 2 replies; 38+ messages in thread
From: Thiago Jung Bauermann @ 2011-05-04 22:21 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: pedro, gdb-patches, uweigand

On Wed, 2011-05-04 at 06:06 +0300, Eli Zaretskii wrote:
> > From: Thiago Jung Bauermann <bauerman@br.ibm.com>
> > Cc: Pedro Alves <pedro@codesourcery.com>, gdb-patches@sourceware.org,
> >         uweigand@de.ibm.com
> > Date: Tue, 03 May 2011 21:03:06 -0300
> > 
> > On Tue, 2011-05-03 at 23:29 +0300, Eli Zaretskii wrote:
> > > > From: Pedro Alves <pedro@codesourcery.com>
> > > > Date: Tue, 3 May 2011 19:12:42 +0100
> > > > Cc: bauerman@br.ibm.com,
> > > >  uweigand@de.ibm.com
> > > > 
> > > > I'm proposing getting rid of target_can_use_hardware_watchpoint
> > > > as being part of the core accounting infrastructure.
> > > 
> > > I'm fine with heading that way.  It will certainly be cleaner than the
> > > current mess, which needs a face-lift every few months.
> > 
> > For this scheme to work, GDB will have to be changed to use
> > always-inserted mode exclusively, right? Or at least insert all
> > breakpoints and watchpoints when probing whether a new
> > breakpoint/watchpoint can be created.
> 
> I think what Pedro suggests can (and should) work only for hardware
> watchpoints and breakpoints.  Normal breakpoints and watchpoints
> cannot work that way, they must be inserted at "resume" time.
> 
> So I think always-inserted mode is not the right way here, unless I'm
> missing something.

Ok, I think I'm a bit slow today. Is the following description correct?

Current scheme:

1. The inferior is stopped and all bp_locations are removed.
2. The user asks for a new watchpoint.
3. GDB evaluates the expression and creates the bp_locations.
4. GDB counts all existing watchpoint bp_locations and asks the target 
   whether there's room for one more. Depending on the answer, decides 
   for a hw or sw watch.
5. GDB registers the new watchpoint for insertion.
6. The user asks the inferior to be continued.
7. GDB inserts all breakpoints and watchpoints and resumes the inferior.

Pedro's suggestion:

1. The inferior is stopped and software bp_locations (both breakpoints 
   and watchpoints) are removed. Hardware ones stay in place.
2. The user asks for a new watchpoint.
3. GDB evaluates the expression and creates the bp_locations.
4. GDB tries to insert the bp_locations as hw watches. If that fails, 
   then converts to sw and registers the watchpoint for insertion.
5. The user asks the inferior to be continued.
6. GDB inserts sw breakpoints and watchpoints and resumes the inferior.
-- 
[]'s
Thiago Jung Bauermann
IBM Linux Technology Center

^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [RFA 2/3] Demote to sw watchpoint only in update_watchpoint
  2011-05-04 20:31             ` Eli Zaretskii
@ 2011-05-04 22:22               ` Thiago Jung Bauermann
  0 siblings, 0 replies; 38+ messages in thread
From: Thiago Jung Bauermann @ 2011-05-04 22:22 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: uweigand, gdb-patches

On Wed, 2011-05-04 at 23:30 +0300, Eli Zaretskii wrote:
> > From: Thiago Jung Bauermann <bauerman@br.ibm.com>
> > Cc: uweigand@de.ibm.coma, gdb-patches@sourceware.org
> > Date: Wed, 04 May 2011 16:12:24 -0300
> > 
> > So the problem is still there. It's not better, but not worse either.
> > The output is slightly different because of the better error handling
> > this patch introduces. Thus, IMHO overhauling resources handling is not
> > a prerequisite or even directly related to this patch (or the next one
> > in the series). The acceptance or rejection of this patch is orthogonal
> > to that.
> 
> Fair enough.  I withdraw my objections to the patch.

Thanks!

> > Having said that, I agree that it's a shame that GDB can't keep track of
> > debug hardware availability, something that one would expect to be among
> > the basic tasks of a debugger. So if we can agree on how GDB should deal
> > with the problem, I'm willing to work on it on a best effort basis
> > (meaning that I wouldn't have much time to dedicate to this, but would
> > eventually make progress).
> 
> Thank you.  I think Pedro's idea is already on the table, and no one
> objected to it.  If it is feasible, I'd say let's do it that way.

Great. I'll implement it as soon as I make sure I understood it
correctly. :-)
-- 
[]'s
Thiago Jung Bauermann
IBM Linux Technology Center

^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [RFA 2/3] Demote to sw watchpoint only in update_watchpoint
  2011-05-04 22:21                           ` Thiago Jung Bauermann
@ 2011-05-05  3:09                             ` Eli Zaretskii
  2011-05-05  8:15                             ` Pedro Alves
  1 sibling, 0 replies; 38+ messages in thread
From: Eli Zaretskii @ 2011-05-05  3:09 UTC (permalink / raw)
  To: Thiago Jung Bauermann; +Cc: pedro, gdb-patches, uweigand

> From: Thiago Jung Bauermann <bauerman@br.ibm.com>
> Cc: pedro@codesourcery.com, gdb-patches@sourceware.org, uweigand@de.ibm.com
> Date: Wed, 04 May 2011 19:20:48 -0300
> 
> Current scheme:
> 
> 1. The inferior is stopped and all bp_locations are removed.
> 2. The user asks for a new watchpoint.
> 3. GDB evaluates the expression and creates the bp_locations.
> 4. GDB counts all existing watchpoint bp_locations and asks the target 
>    whether there's room for one more. Depending on the answer, decides 
>    for a hw or sw watch.
> 5. GDB registers the new watchpoint for insertion.
> 6. The user asks the inferior to be continued.
> 7. GDB inserts all breakpoints and watchpoints and resumes the inferior.

Yes.

> Pedro's suggestion:
> 
> 1. The inferior is stopped and software bp_locations (both breakpoints 
>    and watchpoints) are removed. Hardware ones stay in place.
> 2. The user asks for a new watchpoint.
> 3. GDB evaluates the expression and creates the bp_locations.
> 4. GDB tries to insert the bp_locations as hw watches. If that fails, 
>    then converts to sw and registers the watchpoint for insertion.
> 5. The user asks the inferior to be continued.
> 6. GDB inserts sw breakpoints and watchpoints and resumes the inferior.

That's my understanding, yes.

^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [RFA 2/3] Demote to sw watchpoint only in update_watchpoint
  2011-05-04 22:21                           ` Thiago Jung Bauermann
  2011-05-05  3:09                             ` Eli Zaretskii
@ 2011-05-05  8:15                             ` Pedro Alves
  2011-05-05 10:28                               ` Eli Zaretskii
  2011-05-05 11:10                               ` Ulrich Weigand
  1 sibling, 2 replies; 38+ messages in thread
From: Pedro Alves @ 2011-05-05  8:15 UTC (permalink / raw)
  To: Thiago Jung Bauermann; +Cc: Eli Zaretskii, gdb-patches, uweigand

On Wednesday 04 May 2011 23:20:48, Thiago Jung Bauermann wrote:
> Pedro's suggestion:
> 
> 1. The inferior is stopped and software bp_locations (both breakpoints 
>    and watchpoints) are removed. Hardware ones stay in place.
> 2. The user asks for a new watchpoint.
> 3. GDB evaluates the expression and creates the bp_locations.
> 4. GDB tries to insert the bp_locations as hw watches. If that fails, 
>    then converts to sw and registers the watchpoint for insertion.
> 5. The user asks the inferior to be continued.
> 6. GDB inserts sw breakpoints and watchpoints and resumes the inferior.

Either that or try keep hardware breakpoints and watchpoints uninserted,
and insert them just before 4.  This variant is a bit safer in case GDB crashes,
but is a bit less efficient in case there are many watchpoints.  But then
again we already remove/insert them all at each step, so that is kind of moot.
I've no real preference on which.  This is a minor detail in the grand scheme
from my perspective.

-- 
Pedro Alves

^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [RFA 2/3] Demote to sw watchpoint only in update_watchpoint
  2011-05-05  8:15                             ` Pedro Alves
@ 2011-05-05 10:28                               ` Eli Zaretskii
  2011-05-05 15:27                                 ` Pedro Alves
  2011-05-05 11:10                               ` Ulrich Weigand
  1 sibling, 1 reply; 38+ messages in thread
From: Eli Zaretskii @ 2011-05-05 10:28 UTC (permalink / raw)
  To: Pedro Alves; +Cc: bauerman, gdb-patches, uweigand

> From: Pedro Alves <pedro@codesourcery.com>
> Date: Thu, 5 May 2011 09:15:18 +0100
> Cc: Eli Zaretskii <eliz@gnu.org>,
>  gdb-patches@sourceware.org,
>  uweigand@de.ibm.com
> 
> On Wednesday 04 May 2011 23:20:48, Thiago Jung Bauermann wrote:
> > Pedro's suggestion:
> > 
> > 1. The inferior is stopped and software bp_locations (both breakpoints 
> >    and watchpoints) are removed. Hardware ones stay in place.
> > 2. The user asks for a new watchpoint.
> > 3. GDB evaluates the expression and creates the bp_locations.
> > 4. GDB tries to insert the bp_locations as hw watches. If that fails, 
> >    then converts to sw and registers the watchpoint for insertion.
> > 5. The user asks the inferior to be continued.
> > 6. GDB inserts sw breakpoints and watchpoints and resumes the inferior.
> 
> Either that or try keep hardware breakpoints and watchpoints uninserted,
> and insert them just before 4.

If you really meant "before 4", then I must say I don't understand
what are the 2 alternative suggestions.

^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [RFA 2/3] Demote to sw watchpoint only in update_watchpoint
  2011-05-03  4:56       ` Thiago Jung Bauermann
  2011-05-03  6:05         ` Eli Zaretskii
@ 2011-05-05 11:04         ` Ulrich Weigand
  1 sibling, 0 replies; 38+ messages in thread
From: Ulrich Weigand @ 2011-05-05 11:04 UTC (permalink / raw)
  To: Thiago Jung Bauermann; +Cc: gdb-patches ml

Thiago Jung Bauermann wrote:

> On the other hand, the current code is already broken in that regard,
> and creating several read and access watchpoints on today's GDB will
> confuse it and allow creating more hardware watchpoints (read, access or
> regular) than possible. Thus, this patch doesn't make the situation any
> worse. So now I just use b->type.
> 
> The real fix IMHO would be to make the -tdep code manage the creation
> and deletion of bp_locations, so that it could always make an informed
> decision about what can and cannot be done with the available hardware
> debug resources. But that's out of the scope of this patch series.

Yes, I'd agree with Eli and Pedro that this really ought to be fixed.
I also agree that this is independent of this patch (and in fact I'd
consider the patch a (small) step in the right direction anyway,
since it reduced the number of locations in the code where resource
accounting is done) ...

> 2011-05-03  Thiago Jung Bauermann  <bauerman@br.ibm.com>
> 
> 	* breakpoint.c (update_watchpoint): Change between software and
> 	hardware watchpoint for all kinds of watchpoints, not just
> 	read/write ones.  Determine b->exact value here instead of
> 	in watch_command_1.  Error out if there are not enough resources
> 	for a read or access hardware watchpoint.
> 	(watch_command_1): Remove logic of checking whether there are
> 	enough resources available, since update_watchpoint will do that
> 	work now.  Don't set b->exact here.  Catch exceptions thrown by
> 	update_watchpoint and delete the watchpoint.
> 	(can_use_hardware_watchpoint): Remove exact_watchpoints argument.
> 	Use target_exact_watchpoints instead.
> 	(delete_breakpoint): Notify observers only if deleted watchpoint
> 	has a breakpoint number assigned to it.

As Eli has withdrawn objections to the patch, this is OK.

Thanks,
Ulrich

-- 
  Dr. Ulrich Weigand
  GNU Toolchain for Linux on System z and Cell BE
  Ulrich.Weigand@de.ibm.com

^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [needs doc review] Re: [RFA 3/3] Implement support for PowerPC BookE masked watchpoints
  2011-05-03  4:56       ` [needs doc review] " Thiago Jung Bauermann
  2011-05-03  6:24         ` Eli Zaretskii
@ 2011-05-05 11:07         ` Ulrich Weigand
  1 sibling, 0 replies; 38+ messages in thread
From: Ulrich Weigand @ 2011-05-05 11:07 UTC (permalink / raw)
  To: Thiago Jung Bauermann; +Cc: gdb-patches ml

Thiago Jung Bauermann wrote:

> 2011-05-03  Sergio Durigan Junior  <sergiodj@linux.vnet.ibm.com>
> 	    Thiago Jung Bauermann  <bauerman@br.ibm.com>
> 
> 	Implement support for PowerPC BookE masked watchpoints.
> 
> gdb/
> 	*NEWS: Mention masked watchpoint support.  Create "Changed commands"
> 	section.

Missing space.

> 	* breakpoint.h (struct breakpoint_ops) <works_in_software_mode>: New
> 	method.  Initialize to NULL in all existing breakpoint_ops instances.
> 	(struct breakpoint) <hw_wp_mask>: New field.
> 	* breakpoint.c (is_masked_watchpoint): Add prototype.
> 	(update_watchpoint): Don't set b->val for masked watchpoints.  Call
> 	breakpoint's breakpoint_ops.works_in_software_mode if available.
> 	(watchpoints_triggered): Handle the case of a hardware masked
> 	watchpoint trigger.
> 	(watchpoint_check): Likewise.
> 	(works_in_software_mode_watchpoint): New function.
> 	(insert_masked_watchpoint, remove_masked_watchpoint)
> 	(resources_needed_masked_watchpoint)
> 	(works_in_software_mode_masked_watchpoint, print_it_masked_watchpoint)
> 	(print_one_detail_masked_watchpoint, print_mention_masked_watchpoint)
> 	(print_recreate_masked_watchpoint, is_masked_watchpoint): New
> 	functions.
> 	(masked_watchpoint_breakpoint_ops): New structure.
> 	(watch_command_1): Check for the existence of the `mask' parameter.
> 	Set b->ops according to the type of hardware watchpoint being created.
> 	* ppc-linux-nat.c (ppc_linux_insert_mask_watchpoint)
> 	(ppc_linux_remove_mask_watchpoint)
> 	(ppc_linux_masked_watch_num_registers): New functions.
> 	(_initialize_ppc_linux_nat): Initialize to_insert_mask_watchpoint,
> 	to_remove_mask_watchpoint and to_masked_watch_num_registers.
> 	* target.c (update_current_target): Mention to_insert_mask_watchpoint,
> 	to_remove_mask_watchpoint, and to_masked_watch_num_registers.
> 	(target_insert_mask_watchpoint, target_remove_mask_watchpoint)
> 	(target_masked_watch_num_registers): New functions.
> 	* target.h (struct target_ops) <to_insert_mask_watchpoint>,
> 	<to_remove_mask_watchpoint>, <to_masked_watch_num_registers>: New
> 	methods.
> 	(target_insert_mask_watchpoint, target_remove_mask_watchpoint)
> 	(target_masked_watch_num_registers): Add prototypes.
> 
> gdb/doc/
> 	* gdb.texinfo (Set Watchpoints): Document mask parameter.
> 	(PowerPC Embedded): Document masked watchpoints.

When Eli is happy with the doc parts, the rest is OK.

Thanks,
Ulrich

-- 
  Dr. Ulrich Weigand
  GNU Toolchain for Linux on System z and Cell BE
  Ulrich.Weigand@de.ibm.com

^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [RFA 2/3] Demote to sw watchpoint only in update_watchpoint
  2011-05-05  8:15                             ` Pedro Alves
  2011-05-05 10:28                               ` Eli Zaretskii
@ 2011-05-05 11:10                               ` Ulrich Weigand
  2011-05-05 15:21                                 ` Pedro Alves
  1 sibling, 1 reply; 38+ messages in thread
From: Ulrich Weigand @ 2011-05-05 11:10 UTC (permalink / raw)
  To: Pedro Alves; +Cc: Thiago Jung Bauermann, Eli Zaretskii, gdb-patches

Pedro Alves wrote:
> On Wednesday 04 May 2011 23:20:48, Thiago Jung Bauermann wrote:
> > Pedro's suggestion:
> > 
> > 1. The inferior is stopped and software bp_locations (both breakpoints 
> >    and watchpoints) are removed. Hardware ones stay in place.
> > 2. The user asks for a new watchpoint.
> > 3. GDB evaluates the expression and creates the bp_locations.
> > 4. GDB tries to insert the bp_locations as hw watches. If that fails, 
> >    then converts to sw and registers the watchpoint for insertion.
> > 5. The user asks the inferior to be continued.
> > 6. GDB inserts sw breakpoints and watchpoints and resumes the inferior.
> 
> Either that or try keep hardware breakpoints and watchpoints uninserted,
> and insert them just before 4.  This variant is a bit safer in case GDB crashes,
> but is a bit less efficient in case there are many watchpoints.  But then
> again we already remove/insert them all at each step, so that is kind of moot.
> I've no real preference on which.  This is a minor detail in the grand scheme
> from my perspective.

One thing I'm wondering about is the comment before update_watchpoints:

   Even with `set breakpoint always-inserted on' the watchpoints are
   removed + inserted on each stop here.  Normal breakpoints must
   never be removed because they might be missed by a running thread
   when debugging in non-stop mode.  On the other hand, hardware
   watchpoints (is_hardware_watchpoint; processed here) are specific
   to each LWP since they are stored in each LWP's hardware debug
   registers.  Therefore, such LWP must be stopped first in order to
   be able to modify its hardware watchpoints.
[etc.]

Is this still valid, and would it affect this current discussion if so?

Bye,
Ulrich

-- 
  Dr. Ulrich Weigand
  GNU Toolchain for Linux on System z and Cell BE
  Ulrich.Weigand@de.ibm.com

^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [RFA 2/3] Demote to sw watchpoint only in update_watchpoint
  2011-05-05 11:10                               ` Ulrich Weigand
@ 2011-05-05 15:21                                 ` Pedro Alves
  0 siblings, 0 replies; 38+ messages in thread
From: Pedro Alves @ 2011-05-05 15:21 UTC (permalink / raw)
  To: Ulrich Weigand; +Cc: Thiago Jung Bauermann, Eli Zaretskii, gdb-patches

On Thursday 05 May 2011 12:10:05, Ulrich Weigand wrote:
> Pedro Alves wrote:
> > On Wednesday 04 May 2011 23:20:48, Thiago Jung Bauermann wrote:
> > > Pedro's suggestion:
> > > 
> > > 1. The inferior is stopped and software bp_locations (both breakpoints 
> > >    and watchpoints) are removed. Hardware ones stay in place.
> > > 2. The user asks for a new watchpoint.
> > > 3. GDB evaluates the expression and creates the bp_locations.
> > > 4. GDB tries to insert the bp_locations as hw watches. If that fails, 
> > >    then converts to sw and registers the watchpoint for insertion.
> > > 5. The user asks the inferior to be continued.
> > > 6. GDB inserts sw breakpoints and watchpoints and resumes the inferior.
> > 
> > Either that or try keep hardware breakpoints and watchpoints uninserted,
> > and insert them just before 4.  This variant is a bit safer in case GDB crashes,
> > but is a bit less efficient in case there are many watchpoints.  But then
> > again we already remove/insert them all at each step, so that is kind of moot.
> > I've no real preference on which.  This is a minor detail in the grand scheme
> > from my perspective.
> 
> One thing I'm wondering about is the comment before update_watchpoints:
> 
>    Even with `set breakpoint always-inserted on' the watchpoints are
>    removed + inserted on each stop here    Normal breakpoints must
>    never be removed because they might be missed by a running thread
>    when debugging in non-stop mode.  On the other hand, hardware
>    watchpoints (is_hardware_watchpoint; processed here) are specific
>    to each LWP since they are stored in each LWP's hardware debug
>    registers.  Therefore, such LWP must be stopped first in order to
>    be able to modify its hardware watchpoints.
> [etc.]
> 
> Is this still valid, and would it affect this current discussion if so?

This is stale.  Watchpoints are no longer removed/inserted
on each stop with always-inserted on.  It needed fixing for watchpoints+non-stop.
linux gdbserver copes with inserting breakpoints/watchpoints when
threads are running.  Native linux doesn't, but that just it doesn't really
fully support watchpoints in non-stop mode currently.

-- 
Pedro Alves

^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [RFA 2/3] Demote to sw watchpoint only in update_watchpoint
  2011-05-05 10:28                               ` Eli Zaretskii
@ 2011-05-05 15:27                                 ` Pedro Alves
  2011-05-05 16:27                                   ` Eli Zaretskii
  0 siblings, 1 reply; 38+ messages in thread
From: Pedro Alves @ 2011-05-05 15:27 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: bauerman, gdb-patches, uweigand

On Thursday 05 May 2011 11:28:06, Eli Zaretskii wrote:
> > From: Pedro Alves <pedro@codesourcery.com>
> > Date: Thu, 5 May 2011 09:15:18 +0100
> > Cc: Eli Zaretskii <eliz@gnu.org>,
> >  gdb-patches@sourceware.org,
> >  uweigand@de.ibm.com
> > 
> > On Wednesday 04 May 2011 23:20:48, Thiago Jung Bauermann wrote:
> > > Pedro's suggestion:
> > > 
> > > 1. The inferior is stopped and software bp_locations (both breakpoints 
> > >    and watchpoints) are removed. Hardware ones stay in place.
> > > 2. The user asks for a new watchpoint.
> > > 3. GDB evaluates the expression and creates the bp_locations.
> > > 4. GDB tries to insert the bp_locations as hw watches. If that fails, 
> > >    then converts to sw and registers the watchpoint for insertion.
> > > 5. The user asks the inferior to be continued.
> > > 6. GDB inserts sw breakpoints and watchpoints and resumes the inferior.
> > 
> > Either that or try keep hardware breakpoints and watchpoints uninserted,
> > and insert them just before 4.
> 
> If you really meant "before 4", then I must say I don't understand
> what are the 2 alternative suggestions.

 1. The inferior is stopped and software bp_locations (both breakpoints 
    and watchpoints) are removed. Hardware ones stay in place.
                                  ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
 2. The user asks for a new watchpoint.
 3. GDB evaluates the expression and creates the bp_locations.
 4. GDB tries to insert the bp_locations as hw watches. If that fails, 
    then converts to sw and registers the watchpoint for insertion.
 5. The user asks the inferior to be continued.
 6. GDB inserts sw breakpoints and watchpoints and resumes the inferior.

vs

 1. The inferior is stopped and all sw/hw breakpoints/watchpoints are removed,
                                ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
    as currently.
 2. The user asks for a new watchpoint.
 3. GDB evaluates the expression and creates the bp_locations.
 4. GDB inserts the hw bp_locations of already existing
    hardware watchpoints/breakpoints.  This shouldn't fail,
    unless there's a bug, because otherwise, they wouldn't have
    been created in the first place.  This is a nop if 
    "breakpoint always-inserted" is on.
 5. GDB tries to insert the new bp_locations as hw watches. If that fails,
    remove any leftovers, and convert to sw.
 6. If "breakpoint always-inserted" is off, remove all breakpoints.
 7. The user asks the inferior to be continued.
 8. GDB inserts all breakpoints/watchpoints as usualy.

-- 
Pedro Alves

^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [RFA 2/3] Demote to sw watchpoint only in update_watchpoint
  2011-05-05 15:27                                 ` Pedro Alves
@ 2011-05-05 16:27                                   ` Eli Zaretskii
  0 siblings, 0 replies; 38+ messages in thread
From: Eli Zaretskii @ 2011-05-05 16:27 UTC (permalink / raw)
  To: Pedro Alves; +Cc: bauerman, gdb-patches, uweigand

> From: Pedro Alves <pedro@codesourcery.com>
> Date: Thu, 5 May 2011 16:27:40 +0100
> Cc: bauerman@br.ibm.com,
>  gdb-patches@sourceware.org,
>  uweigand@de.ibm.com
> 
>  1. The inferior is stopped and software bp_locations (both breakpoints 
>     and watchpoints) are removed. Hardware ones stay in place.
>                                   ^^^^^^^^^^^^^^^^^^^^^^^^^^^^
>  2. The user asks for a new watchpoint.

Ah, okay.  I thought you were talking about that "new watchpoint" in
item 2.  Thanks for setting me straight.

Yes, I agree that the difference doesn't really matter, and that your
second variant is slightly better.

^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [needs doc review] Re: [RFA 3/3] Implement support for PowerPC BookE masked watchpoints
  2011-05-03  6:24         ` Eli Zaretskii
@ 2011-05-05 21:57           ` Thiago Jung Bauermann
  2011-05-06 10:28             ` Eli Zaretskii
  0 siblings, 1 reply; 38+ messages in thread
From: Thiago Jung Bauermann @ 2011-05-05 21:57 UTC (permalink / raw)
  To: Eli Zaretskii; +Cc: uweigand, gdb-patches ml

Hi Eli,

Thanks for your review.

On Tue, 2011-05-03 at 02:23 -0400, Eli Zaretskii wrote:
> > From: Thiago Jung Bauermann <bauerman@br.ibm.com>
> > Cc: gdb-patches ml <gdb-patches@sourceware.org>
> > Date: Tue, 03 May 2011 01:55:54 -0300
> > 
> >   The @code{@r{[}mask @var{maskvalue}@r{]}} argument allows creation
> >   of masked watchpoints, if the current architecture supports this
> >   feature.  (Currently, this is only available on PowerPC Embedded
> >   architecture, see @ref{PowerPC Embedded}.)  Specifying a mask argument
> >   implies the @code{-location} argument.
> 
> I would prefer to avoid text in the manual that could easily become
> obsolete tomorrow: we don't have any efficient mechanism in place to
> tell us to revise such text.  So instead of
> 
>   (Currently, this is only available on PowerPC Embedded architecture,
>   see @ref{PowerPC Embedded}.)
> 
> I would prefer either to say nothing, or use a more vague phrase,
> without the too-decisive "currently, available only on...".  Like
> this, for example:
> 
>   The @code{@r{[}mask @var{maskvalue}@r{]}} argument allows creation
>   of masked watchpoints, if the current architecture supports this
>   feature (e.g., PowerPC Embedded architecture, see @ref{PowerPC
>   Embedded}.)

Right. I adopted your text.

> >   A @dfn{masked watchpoint} specifies a mask in addition to an address
> >   to watch.  The mask specifies that some bits of an address (the bits
> >   which are reset in the mask) should be ignored when matching the
> >   address accessed by the inferior against the watchpoint address.
> >   Thus, a masked watchpoint watches many addresses
> >   simultaneously---those addresses whose unmasked bits are identical
> >   to the unmasked bits in the watchpoint address.
> > 
> > became
> > 
> >   A @dfn{masked watchpoint} specifies a mask in addition to an address
> >   to watch.  The @code{mask} argument implies the @code{-location}
> >   argument, which means that the expression will be resolved to a memory
> >   address at watchpoint creation time (@pxref{Set Watchpoints}.)
> 
> What do you mean by "implies"?  Do you mean that -location must be
> specified if "mask" is specified?  If so, "implies" is not a good
> word.

I mean that if you specify mask, then it's as if you specified -location
as well. Do you think it's not clear enough?

> I also don't really understand the part about "resolving to a memory
> address at watchpoint creation time".  What were you trying to say?

I tried to explain what -location does in a very short sentence. :-)

In this version I moved the explanation about masked watchpoints from
the PowerPC section to the Set Watchpoints section. I think it makes
more sense there. This also made unnecessary any separate explanation
about -location since it comes right after the masked watchpoint
explanation.

What do you think of this version?
-- 
[]'s
Thiago Jung Bauermann
IBM Linux Technology Center


2011-05-05  Sergio Durigan Junior  <sergiodj@linux.vnet.ibm.com>
	    Thiago Jung Bauermann  <bauerman@br.ibm.com>

	Implement support for PowerPC BookE masked watchpoints.

gdb/
	* NEWS: Mention masked watchpoint support.  Create "Changed commands"
	section.
	* breakpoint.h (struct breakpoint_ops) <works_in_software_mode>: New
	method.  Initialize to NULL in all existing breakpoint_ops instances.
	(struct breakpoint) <hw_wp_mask>: New field.
	* breakpoint.c (is_masked_watchpoint): Add prototype.
	(update_watchpoint): Don't set b->val for masked watchpoints.  Call
	breakpoint's breakpoint_ops.works_in_software_mode if available.
	(watchpoints_triggered): Handle the case of a hardware masked
	watchpoint trigger.
	(watchpoint_check): Likewise.
	(works_in_software_mode_watchpoint): New function.
	(insert_masked_watchpoint, remove_masked_watchpoint)
	(resources_needed_masked_watchpoint)
	(works_in_software_mode_masked_watchpoint, print_it_masked_watchpoint)
	(print_one_detail_masked_watchpoint, print_mention_masked_watchpoint)
	(print_recreate_masked_watchpoint, is_masked_watchpoint): New
	functions.
	(masked_watchpoint_breakpoint_ops): New structure.
	(watch_command_1): Check for the existence of the `mask' parameter.
	Set b->ops according to the type of hardware watchpoint being created.
	* ppc-linux-nat.c (ppc_linux_insert_mask_watchpoint)
	(ppc_linux_remove_mask_watchpoint)
	(ppc_linux_masked_watch_num_registers): New functions.
	(_initialize_ppc_linux_nat): Initialize to_insert_mask_watchpoint,
	to_remove_mask_watchpoint and to_masked_watch_num_registers.
	* target.c (update_current_target): Mention to_insert_mask_watchpoint,
	to_remove_mask_watchpoint, and to_masked_watch_num_registers.
	(target_insert_mask_watchpoint, target_remove_mask_watchpoint)
	(target_masked_watch_num_registers): New functions.
	* target.h (struct target_ops) <to_insert_mask_watchpoint>,
	<to_remove_mask_watchpoint>, <to_masked_watch_num_registers>: New
	methods.
	(target_insert_mask_watchpoint, target_remove_mask_watchpoint)
	(target_masked_watch_num_registers): Add prototypes.

gdb/doc/
	* gdb.texinfo (Set Watchpoints): Document mask parameter.
	(PowerPC Embedded): Mention support of masked watchpoints.


diff --git a/gdb/NEWS b/gdb/NEWS
index 1a22c66..9b59419 100644
--- a/gdb/NEWS
+++ b/gdb/NEWS
@@ -3,10 +3,24 @@
 
 *** Changes since GDB 7.3
 
+* When natively debugging programs on PowerPC BookE processors running
+  a Linux kernel version 2.6.34 or later, GDB supports masked hardware
+  watchpoints, which specify a mask in addition to an address to watch.
+  The mask specifies that some bits of an address (the bits which are
+  reset in the mask) should be ignored when matching the address accessed
+  by the inferior against the watchpoint address.  See the "PowerPC Embedded"
+  section in the user manual for more details.
+
 * The new option --once causes GDBserver to stop listening for connections once
   the first connection is made.  The listening port used by GDBserver will
   become available after that.
 
+* Changed commands
+
+watch EXPRESSION mask MASK_VALUE
+  The watch command now supports the mask argument which allows creation
+  of masked watchpoints, if the current architecture supports this feature.
+
 *** Changes in GDB 7.3
 
 * GDB has a new command: "thread find [REGEXP]".
diff --git a/gdb/ada-lang.c b/gdb/ada-lang.c
index d434521..ebd5fd2 100644
--- a/gdb/ada-lang.c
+++ b/gdb/ada-lang.c
@@ -10950,6 +10950,7 @@ static struct breakpoint_ops catch_exception_breakpoint_ops =
   NULL, /* remove */
   NULL, /* breakpoint_hit */
   NULL, /* resources_needed */
+  NULL, /* works_in_software_mode */
   print_it_catch_exception,
   print_one_catch_exception,
   NULL, /* print_one_detail */
@@ -10990,6 +10991,7 @@ static struct breakpoint_ops catch_exception_unhandled_breakpoint_ops = {
   NULL, /* remove */
   NULL, /* breakpoint_hit */
   NULL, /* resources_needed */
+  NULL, /* works_in_software_mode */
   print_it_catch_exception_unhandled,
   print_one_catch_exception_unhandled,
   NULL, /* print_one_detail */
@@ -11028,6 +11030,7 @@ static struct breakpoint_ops catch_assert_breakpoint_ops = {
   NULL, /* remove */
   NULL, /* breakpoint_hit */
   NULL, /* resources_needed */
+  NULL, /* works_in_software_mode */
   print_it_catch_assert,
   print_one_catch_assert,
   NULL, /* print_one_detail */
diff --git a/gdb/breakpoint.c b/gdb/breakpoint.c
index 8358dac..b864700 100644
--- a/gdb/breakpoint.c
+++ b/gdb/breakpoint.c
@@ -224,6 +224,8 @@ static void disable_trace_command (char *, int);
 
 static void trace_pass_command (char *, int);
 
+static int is_masked_watchpoint (const struct breakpoint *b);
+
 /* Assuming we're creating a static tracepoint, does S look like a
    static tracepoint marker spec ("-m MARKER_ID")?  */
 #define is_marker_spec(s)						\
@@ -1345,8 +1347,10 @@ update_watchpoint (struct breakpoint *b, int reparse)
       /* Avoid setting b->val if it's already set.  The meaning of
 	 b->val is 'the last value' user saw, and we should update
 	 it only if we reported that last value to user.  As it
-	 happens, the code that reports it updates b->val directly.  */
-      if (!b->val_valid)
+	 happens, the code that reports it updates b->val directly.
+	 We don't keep track of the memory value for masked
+	 watchpoints.  */
+      if (!b->val_valid && !is_masked_watchpoint (b))
 	{
 	  b->val = v;
 	  b->val_valid = 1;
@@ -1435,19 +1439,23 @@ update_watchpoint (struct breakpoint *b, int reparse)
 		    (b->type, i, other_type_used);
 	      if (target_resources_ok <= 0)
 		{
-		  if (target_resources_ok == 0
-		      && b->type != bp_hardware_watchpoint)
+		  /* If there's no works_in_software_mode method, we
+		     assume that the watchpoint works in software mode.  */
+		  int sw_mode = (!b->ops || !b->ops->works_in_software_mode
+				 || b->ops->works_in_software_mode (b));
+
+		  if (target_resources_ok == 0 && !sw_mode)
 		    error (_("Target does not support this type of "
 			     "hardware watchpoint."));
-		  else if (target_resources_ok < 0
-		      && b->type != bp_hardware_watchpoint)
-		    error (_("Target can only support one kind "
-			     "of HW watchpoint at a time."));
+		  else if (target_resources_ok < 0 && !sw_mode)
+		    error (_("There are not enough available hardware "
+			     "resources for this watchpoint."));
 		  else
 		    b->type = bp_watchpoint;
 		}
 	    }
-	  else if (b->type != bp_hardware_watchpoint)
+	  else if (b->ops && b->ops->works_in_software_mode
+		   && !b->ops->works_in_software_mode (b))
 	    error (_("Expression cannot be implemented with "
 		     "read/access watchpoint."));
 	  else
@@ -3694,15 +3702,27 @@ watchpoints_triggered (struct target_waitstatus *ws)
 
 	b->watchpoint_triggered = watch_triggered_no;
 	for (loc = b->loc; loc; loc = loc->next)
-	  /* Exact match not required.  Within range is
-	     sufficient.  */
-	  if (target_watchpoint_addr_within_range (&current_target,
-						   addr, loc->address,
-						   loc->length))
-	    {
-	      b->watchpoint_triggered = watch_triggered_yes;
-	      break;
-	    }
+	  {
+	    if (is_masked_watchpoint (loc->owner))
+	      {
+		CORE_ADDR newaddr = addr & loc->owner->hw_wp_mask;
+		CORE_ADDR start = loc->address & loc->owner->hw_wp_mask;
+
+		if (newaddr == start)
+		  {
+		    b->watchpoint_triggered = watch_triggered_yes;
+		    break;
+		  }
+	      }
+	    /* Exact match not required.  Within range is sufficient.  */
+	    else if (target_watchpoint_addr_within_range (&current_target,
+							 addr, loc->address,
+							 loc->length))
+	      {
+		b->watchpoint_triggered = watch_triggered_yes;
+		break;
+	      }
+	  }
       }
 
   return 1;
@@ -3799,9 +3819,16 @@ watchpoint_check (void *p)
          might be in the middle of evaluating a function call.  */
 
       int pc = 0;
-      struct value *mark = value_mark ();
+      struct value *mark;
       struct value *new_val;
 
+      if (is_masked_watchpoint (b))
+	/* Since we don't know the exact trigger address (from
+	   stopped_data_address), just tell the user we've triggered
+	   a mask watchpoint.  */
+	return WP_VALUE_CHANGED;
+
+      mark = value_mark ();
       fetch_subexp_value (b->exp, &pc, &new_val, NULL, NULL);
 
       /* We use value_equal_contents instead of value_equal because
@@ -6303,6 +6330,7 @@ static struct breakpoint_ops catch_fork_breakpoint_ops =
   remove_catch_fork,
   breakpoint_hit_catch_fork,
   NULL, /* resources_needed */
+  NULL, /* works_in_software_mode */
   print_it_catch_fork,
   print_one_catch_fork,
   NULL, /* print_one_detail */
@@ -6401,6 +6429,7 @@ static struct breakpoint_ops catch_vfork_breakpoint_ops =
   remove_catch_vfork,
   breakpoint_hit_catch_vfork,
   NULL, /* resources_needed */
+  NULL, /* works_in_software_mode */
   print_it_catch_vfork,
   print_one_catch_vfork,
   NULL, /* print_one_detail */
@@ -6688,6 +6717,7 @@ static struct breakpoint_ops catch_syscall_breakpoint_ops =
   remove_catch_syscall,
   breakpoint_hit_catch_syscall,
   NULL, /* resources_needed */
+  NULL, /* works_in_software_mode */
   print_it_catch_syscall,
   print_one_catch_syscall,
   NULL, /* print_one_detail */
@@ -6845,6 +6875,7 @@ static struct breakpoint_ops catch_exec_breakpoint_ops =
   remove_catch_exec,
   breakpoint_hit_catch_exec,
   NULL, /* resources_needed */
+  NULL, /* works_in_software_mode */
   print_it_catch_exec,
   print_one_catch_exec,
   NULL, /* print_one_detail */
@@ -8470,6 +8501,7 @@ static struct breakpoint_ops ranged_breakpoint_ops =
   NULL, /* remove */
   breakpoint_hit_ranged_breakpoint,
   resources_needed_ranged_breakpoint,
+  NULL, /* works_in_software_mode */
   print_it_ranged_breakpoint,
   print_one_ranged_breakpoint,
   print_one_detail_ranged_breakpoint,
@@ -8777,6 +8809,15 @@ resources_needed_watchpoint (const struct bp_location *bl)
   return target_region_ok_for_hw_watchpoint (bl->address, length);
 }
 
+/* Implement the "works_in_software_mode" breakpoint_ops method for
+   hardware watchpoints.  */
+
+int
+works_in_software_mode_watchpoint (const struct breakpoint *b)
+{
+  return b->type == bp_hardware_watchpoint;
+}
+
 /* The breakpoint_ops structure to be used in hardware watchpoints.  */
 
 static struct breakpoint_ops watchpoint_breakpoint_ops =
@@ -8785,6 +8826,7 @@ static struct breakpoint_ops watchpoint_breakpoint_ops =
   remove_watchpoint,
   NULL, /* breakpoint_hit */
   resources_needed_watchpoint,
+  works_in_software_mode_watchpoint,
   NULL, /* print_it */
   NULL, /* print_one */
   NULL, /* print_one_detail */
@@ -8792,6 +8834,192 @@ static struct breakpoint_ops watchpoint_breakpoint_ops =
   NULL  /* print_recreate */
 };
 
+/* Implement the "insert" breakpoint_ops method for
+   masked hardware watchpoints.  */
+
+static int
+insert_masked_watchpoint (struct bp_location *bl)
+{
+  return target_insert_mask_watchpoint (bl->address, bl->owner->hw_wp_mask,
+					bl->watchpoint_type);
+}
+
+/* Implement the "remove" breakpoint_ops method for
+   masked hardware watchpoints.  */
+
+static int
+remove_masked_watchpoint (struct bp_location *bl)
+{
+  return target_remove_mask_watchpoint (bl->address, bl->owner->hw_wp_mask,
+				        bl->watchpoint_type);
+}
+
+/* Implement the "resources_needed" breakpoint_ops method for
+   masked hardware watchpoints.  */
+
+static int
+resources_needed_masked_watchpoint (const struct bp_location *bl)
+{
+  return target_masked_watch_num_registers (bl->address,
+					    bl->owner->hw_wp_mask);
+}
+
+/* Implement the "works_in_software_mode" breakpoint_ops method for
+   masked hardware watchpoints.  */
+
+static int
+works_in_software_mode_masked_watchpoint (const struct breakpoint *b)
+{
+  return 0;
+}
+
+/* Implement the "print_it" breakpoint_ops method for
+   masked hardware watchpoints.  */
+
+static enum print_stop_action
+print_it_masked_watchpoint (struct breakpoint *b)
+{
+  /* Masked watchpoints have only one location.  */
+  gdb_assert (b->loc && b->loc->next == NULL);
+
+  switch (b->type)
+    {
+    case bp_hardware_watchpoint:
+      annotate_watchpoint (b->number);
+      if (ui_out_is_mi_like_p (uiout))
+	ui_out_field_string
+	  (uiout, "reason",
+	   async_reason_lookup (EXEC_ASYNC_WATCHPOINT_TRIGGER));
+      break;
+
+    case bp_read_watchpoint:
+      if (ui_out_is_mi_like_p (uiout))
+	ui_out_field_string
+	  (uiout, "reason",
+	   async_reason_lookup (EXEC_ASYNC_READ_WATCHPOINT_TRIGGER));
+      break;
+
+    case bp_access_watchpoint:
+      if (ui_out_is_mi_like_p (uiout))
+	ui_out_field_string
+	  (uiout, "reason",
+	   async_reason_lookup (EXEC_ASYNC_ACCESS_WATCHPOINT_TRIGGER));
+      break;
+    default:
+      internal_error (__FILE__, __LINE__,
+		      _("Invalid hardware watchpoint type."));
+    }
+
+  mention (b);
+  ui_out_text (uiout, _("\n\
+Check the underlying instruction at PC for the memory\n\
+address and value which triggered this watchpoint.\n"));
+  ui_out_text (uiout, "\n");
+
+  /* More than one watchpoint may have been triggered.  */
+  return PRINT_UNKNOWN;
+}
+
+/* Implement the "print_one_detail" breakpoint_ops method for
+   masked hardware watchpoints.  */
+
+static void
+print_one_detail_masked_watchpoint (const struct breakpoint *b,
+				    struct ui_out *uiout)
+{
+  /* Masked watchpoints have only one location.  */
+  gdb_assert (b->loc && b->loc->next == NULL);
+
+  ui_out_text (uiout, "\tmask ");
+  ui_out_field_core_addr (uiout, "mask", b->loc->gdbarch, b->hw_wp_mask);
+  ui_out_text (uiout, "\n");
+}
+
+/* Implement the "print_mention" breakpoint_ops method for
+   masked hardware watchpoints.  */
+
+static void
+print_mention_masked_watchpoint (struct breakpoint *b)
+{
+  struct cleanup *ui_out_chain;
+
+  switch (b->type)
+    {
+    case bp_hardware_watchpoint:
+      ui_out_text (uiout, "Masked hardware watchpoint ");
+      ui_out_chain = make_cleanup_ui_out_tuple_begin_end (uiout, "wpt");
+      break;
+    case bp_read_watchpoint:
+      ui_out_text (uiout, "Masked hardware read watchpoint ");
+      ui_out_chain = make_cleanup_ui_out_tuple_begin_end (uiout, "hw-rwpt");
+      break;
+    case bp_access_watchpoint:
+      ui_out_text (uiout, "Masked hardware access (read/write) watchpoint ");
+      ui_out_chain = make_cleanup_ui_out_tuple_begin_end (uiout, "hw-awpt");
+      break;
+    default:
+      internal_error (__FILE__, __LINE__,
+		      _("Invalid hardware watchpoint type."));
+    }
+
+  ui_out_field_int (uiout, "number", b->number);
+  ui_out_text (uiout, ": ");
+  ui_out_field_string (uiout, "exp", b->exp_string);
+  do_cleanups (ui_out_chain);
+}
+
+/* Implement the "print_recreate" breakpoint_ops method for
+   masked hardware watchpoints.  */
+
+static void
+print_recreate_masked_watchpoint (struct breakpoint *b, struct ui_file *fp)
+{
+  char tmp[40];
+
+  switch (b->type)
+    {
+    case bp_hardware_watchpoint:
+      fprintf_unfiltered (fp, "watch");
+      break;
+    case bp_read_watchpoint:
+      fprintf_unfiltered (fp, "rwatch");
+      break;
+    case bp_access_watchpoint:
+      fprintf_unfiltered (fp, "awatch");
+      break;
+    default:
+      internal_error (__FILE__, __LINE__,
+		      _("Invalid hardware watchpoint type."));
+    }
+
+  sprintf_vma (tmp, b->hw_wp_mask);
+  fprintf_unfiltered (fp, " %s mask 0x%s", b->exp_string, tmp);
+}
+
+/* The breakpoint_ops structure to be used in masked hardware watchpoints.  */
+
+static struct breakpoint_ops masked_watchpoint_breakpoint_ops =
+{
+  insert_masked_watchpoint,
+  remove_masked_watchpoint,
+  NULL, /* breakpoint_hit */
+  resources_needed_masked_watchpoint,
+  works_in_software_mode_masked_watchpoint,
+  print_it_masked_watchpoint,
+  NULL, /* print_one */
+  print_one_detail_masked_watchpoint,
+  print_mention_masked_watchpoint,
+  print_recreate_masked_watchpoint
+};
+
+/* Tell whether the given watchpoint is a masked hardware watchpoint.  */
+
+static int
+is_masked_watchpoint (const struct breakpoint *b)
+{
+  return b->ops == &masked_watchpoint_breakpoint_ops;
+}
+
 /* accessflag:  hw_write:  watch write, 
                 hw_read:   watch read, 
 		hw_access: watch access (read or write) */
@@ -8807,73 +9035,97 @@ watch_command_1 (char *arg, int accessflag, int from_tty,
   struct frame_info *frame;
   char *exp_start = NULL;
   char *exp_end = NULL;
-  char *tok, *id_tok_start, *end_tok;
-  int toklen;
+  char *tok, *end_tok;
+  int toklen = -1;
   char *cond_start = NULL;
   char *cond_end = NULL;
   enum bptype bp_type;
   int thread = -1;
   int pc = 0;
+  /* Flag to indicate whether we are going to use masks for
+     the hardware watchpoint.  */
+  int use_mask = 0;
+  CORE_ADDR mask = 0;
 
   /* Make sure that we actually have parameters to parse.  */
   if (arg != NULL && arg[0] != '\0')
     {
-      toklen = strlen (arg); /* Size of argument list.  */
+      char *value_start;
 
-      /* Points tok to the end of the argument list.  */
-      tok = arg + toklen - 1;
+      /* Look for "parameter value" pairs at the end
+	 of the arguments string.  */
+      for (tok = arg + strlen (arg) - 1; tok > arg; tok--)
+	{
+	  /* Skip whitespace at the end of the argument list.  */
+	  while (tok > arg && (*tok == ' ' || *tok == '\t'))
+	    tok--;
+
+	  /* Find the beginning of the last token.
+	     This is the value of the parameter.  */
+	  while (tok > arg && (*tok != ' ' && *tok != '\t'))
+	    tok--;
+	  value_start = tok + 1;
+
+	  /* Skip whitespace.  */
+	  while (tok > arg && (*tok == ' ' || *tok == '\t'))
+	    tok--;
+
+	  end_tok = tok;
+
+	  /* Find the beginning of the second to last token.
+	     This is the parameter itself.  */
+	  while (tok > arg && (*tok != ' ' && *tok != '\t'))
+	    tok--;
+	  tok++;
+	  toklen = end_tok - tok + 1;
+
+	  if (toklen == 6 && !strncmp (tok, "thread", 6))
+	    {
+	      /* At this point we've found a "thread" token, which means
+		 the user is trying to set a watchpoint that triggers
+		 only in a specific thread.  */
+	      char *endp;
 
-      /* Go backwards in the parameters list.  Skip the last
-         parameter.  If we're expecting a 'thread <thread_num>'
-         parameter, this should be the thread identifier.  */
-      while (tok > arg && (*tok == ' ' || *tok == '\t'))
-        tok--;
-      while (tok > arg && (*tok != ' ' && *tok != '\t'))
-        tok--;
+	      if (thread != -1)
+		error(_("You can specify only one thread."));
 
-      /* Points end_tok to the beginning of the last token.  */
-      id_tok_start = tok + 1;
+	      /* Extract the thread ID from the next token.  */
+	      thread = strtol (value_start, &endp, 0);
 
-      /* Go backwards in the parameters list.  Skip one more
-         parameter.  If we're expecting a 'thread <thread_num>'
-         parameter, we should reach a "thread" token.  */
-      while (tok > arg && (*tok == ' ' || *tok == '\t'))
-        tok--;
+	      /* Check if the user provided a valid numeric value for the
+		 thread ID.  */
+	      if (*endp != ' ' && *endp != '\t' && *endp != '\0')
+		error (_("Invalid thread ID specification %s."), value_start);
 
-      end_tok = tok;
+	      /* Check if the thread actually exists.  */
+	      if (!valid_thread_id (thread))
+		error (_("Unknown thread %d."), thread);
+	    }
+	  else if (toklen == 4 && !strncmp (tok, "mask", 4))
+	    {
+	      /* We've found a "mask" token, which means the user wants to
+		 create a hardware watchpoint that is going to have the mask
+		 facility.  */
+	      struct value *mask_value, *mark;
 
-      while (tok > arg && (*tok != ' ' && *tok != '\t'))
-        tok--;
+	      if (use_mask)
+		error(_("You can specify only one mask."));
 
-      /* Move the pointer forward to skip the whitespace and
-         calculate the length of the token.  */
-      tok++;
-      toklen = end_tok - tok;
+	      use_mask = just_location = 1;
 
-      if (toklen >= 1 && strncmp (tok, "thread", toklen) == 0)
-        {
-          /* At this point we've found a "thread" token, which means
-             the user is trying to set a watchpoint that triggers
-             only in a specific thread.  */
-          char *endp;
-
-          /* Extract the thread ID from the next token.  */
-          thread = strtol (id_tok_start, &endp, 0);
-
-          /* Check if the user provided a valid numeric value for the
-             thread ID.  */
-          if (*endp != ' ' && *endp != '\t' && *endp != '\0')
-            error (_("Invalid thread ID specification %s."), id_tok_start);
-
-          /* Check if the thread actually exists.  */
-          if (!valid_thread_id (thread))
-            error (_("Unknown thread %d."), thread);
-
-          /* Truncate the string and get rid of the thread <thread_num>
-             parameter before the parameter list is parsed by the
-             evaluate_expression() function.  */
-          *tok = '\0';
-        }
+	      mark = value_mark ();
+	      mask_value = parse_to_comma_and_eval (&value_start);
+	      mask = value_as_address (mask_value);
+	      value_free_to_mark (mark);
+	    }
+	  else
+	    /* We didn't recognize what we found.  We should stop here.  */
+	    break;
+
+	  /* Truncate the string and get rid of the "parameter value" pair before
+	     the arguments string is parsed by the parse_exp_1 function.  */
+	  *tok = '\0';
+	}
     }
 
   /* Parse the rest of the arguments.  */
@@ -8904,10 +9156,22 @@ watch_command_1 (char *arg, int accessflag, int from_tty,
 
   if (just_location)
     {
+      int ret;
+
       exp_valid_block = NULL;
       val = value_addr (result);
       release_value (val);
       value_free_to_mark (mark);
+
+      if (use_mask)
+	{
+	  ret = target_masked_watch_num_registers (value_as_address (val),
+						   mask);
+	  if (ret == -1)
+	    error (_("This target does not support masked watchpoints."));
+	  else if (ret == -2)
+	    error (_("Invalid mask or memory region."));
+	}
     }
   else if (val != NULL)
     release_value (val);
@@ -9004,9 +9268,18 @@ watch_command_1 (char *arg, int accessflag, int from_tty,
     }
   else
     b->exp_string = savestring (exp_start, exp_end - exp_start);
-  b->val = val;
-  b->val_valid = 1;
-  b->ops = &watchpoint_breakpoint_ops;
+
+  if (use_mask)
+    {
+      b->hw_wp_mask = mask;
+      b->ops = &masked_watchpoint_breakpoint_ops;
+    }
+  else
+    {
+      b->val = val;
+      b->val_valid = 1;
+      b->ops = &watchpoint_breakpoint_ops;
+    }
 
   if (cond_start)
     b->cond_string = savestring (cond_start, cond_end - cond_start);
@@ -9543,6 +9816,7 @@ static struct breakpoint_ops gnu_v3_exception_catchpoint_ops = {
   NULL, /* remove */
   NULL, /* breakpoint_hit */
   NULL, /* resources_needed */
+  NULL, /* works_in_software_mode */
   print_it_exception_catchpoint,
   print_one_exception_catchpoint,
   NULL, /* print_one_detail */
diff --git a/gdb/breakpoint.h b/gdb/breakpoint.h
index 7a9c2d4..7fa705f 100644
--- a/gdb/breakpoint.h
+++ b/gdb/breakpoint.h
@@ -410,6 +410,11 @@ struct breakpoint_ops
      the breakpoint or watchpoint needs one debug register.  */
   int (*resources_needed) (const struct bp_location *);
 
+  /* Tell whether we can downgrade from a hardware watchpoint to a software
+     one.  If not, the user will not be able to enable the watchpoint when
+     there are not enough hardware resources available.  */
+  int (*works_in_software_mode) (const struct breakpoint *);
+
   /* The normal print routine for this breakpoint, called when we
      hit it.  */
   enum print_stop_action (*print_it) (struct breakpoint *);
@@ -651,6 +656,9 @@ struct breakpoint
 
     /* Whether this watchpoint is exact (see target_exact_watchpoints).  */
     int exact;
+
+    /* The mask address for a masked hardware watchpoint.  */
+    CORE_ADDR hw_wp_mask;
   };
 
 typedef struct breakpoint *breakpoint_p;
diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo
index ff5b7cb..54da5ab 100644
--- a/gdb/doc/gdb.texinfo
+++ b/gdb/doc/gdb.texinfo
@@ -3728,7 +3728,7 @@ watchpoints, which do not slow down the running of your program.
 
 @table @code
 @kindex watch
-@item watch @r{[}-l@r{|}-location@r{]} @var{expr} @r{[}thread @var{threadnum}@r{]}
+@item watch @r{[}-l@r{|}-location@r{]} @var{expr} @r{[}thread @var{threadnum}@r{]} @r{[}mask @var{maskvalue}@r{]}
 Set a watchpoint for an expression.  @value{GDBN} will break when the
 expression @var{expr} is written into by the program and its value
 changes.  The simplest (and the most popular) use of this command is
@@ -3739,12 +3739,29 @@ to watch the value of a single variable:
 @end smallexample
 
 If the command includes a @code{@r{[}thread @var{threadnum}@r{]}}
-clause, @value{GDBN} breaks only when the thread identified by
+argument, @value{GDBN} breaks only when the thread identified by
 @var{threadnum} changes the value of @var{expr}.  If any other threads
 change the value of @var{expr}, @value{GDBN} will not break.  Note
 that watchpoints restricted to a single thread in this way only work
 with Hardware Watchpoints.
 
+The @code{@r{[}mask @var{maskvalue}@r{]}} argument allows creation
+of masked watchpoints, if the current architecture supports this
+feature (e.g., PowerPC Embedded architecture, see @ref{PowerPC
+Embedded}.)  A @dfn{masked watchpoint} specifies a mask in addition
+to an address to watch.  The mask specifies that some bits of an address
+(the bits which are reset in the mask) should be ignored when matching
+the address accessed by the inferior against the watchpoint address.
+Thus, a masked watchpoint watches many addresses simultaneously---those
+addresses whose unmasked bits are identical to the unmasked bits in the
+watchpoint address.  The @code{mask} argument implies the @code{-location}
+argument.  Examples:
+
+@smallexample
+(@value{GDBP}) watch foo mask 0xffff00ff
+(@value{GDBP}) watch *0xdeadbeef mask 0xffffff00
+@end smallexample
+
 Ordinarily a watchpoint respects the scope of variables in @var{expr}
 (see below).  The @code{-location} argument tells @value{GDBN} to
 instead watch the memory referred to by @var{expr}.  In this case,
@@ -3755,12 +3772,12 @@ result does not have an address, then @value{GDBN} will print an
 error.
 
 @kindex rwatch
-@item rwatch @r{[}-l@r{|}-location@r{]} @var{expr} @r{[}thread @var{threadnum}@r{]}
+@item rwatch @r{[}-l@r{|}-location@r{]} @var{expr} @r{[}thread @var{threadnum}@r{]} @r{[}mask @var{maskvalue}@r{]}
 Set a watchpoint that will break when the value of @var{expr} is read
 by the program.
 
 @kindex awatch
-@item awatch @r{[}-l@r{|}-location@r{]} @var{expr} @r{[}thread @var{threadnum}@r{]}
+@item awatch @r{[}-l@r{|}-location@r{]} @var{expr} @r{[}thread @var{threadnum}@r{]} @r{[}mask @var{maskvalue}@r{]}
 Set a watchpoint that will break when @var{expr} is either read from
 or written into by the program.
 
@@ -18783,6 +18800,9 @@ region using one of the following commands (@pxref{Expressions}):
 (@value{GDBP}) watch @{char[@var{length}]@} @var{address}
 @end smallexample
 
+PowerPC embedded processors support masked watchpoints.  See the discussion
+about the @code{mask} argument in @ref{Set Watchpoints}.
+
 @cindex ranged breakpoint
 PowerPC embedded processors support hardware accelerated
 @dfn{ranged breakpoints}.  A ranged breakpoint stops execution of
diff --git a/gdb/ppc-linux-nat.c b/gdb/ppc-linux-nat.c
index 6f11715..275de78 100644
--- a/gdb/ppc-linux-nat.c
+++ b/gdb/ppc-linux-nat.c
@@ -1739,6 +1739,64 @@ get_trigger_type (int rw)
   return t;
 }
 
+/* Insert a new masked watchpoint at ADDR using the mask MASK.
+   RW may be hw_read for a read watchpoint, hw_write for a write watchpoint
+   or hw_access for an access watchpoint.  Returns 0 on success and throws
+   an error on failure.  */
+
+static int
+ppc_linux_insert_mask_watchpoint (struct target_ops *ops, CORE_ADDR addr,
+				  CORE_ADDR mask, int rw)
+{
+  ptid_t ptid;
+  struct lwp_info *lp;
+  struct ppc_hw_breakpoint p;
+
+  gdb_assert (have_ptrace_booke_interface ());
+
+  p.version = PPC_DEBUG_CURRENT_VERSION;
+  p.trigger_type = get_trigger_type (rw);
+  p.addr_mode = PPC_BREAKPOINT_MODE_MASK;
+  p.condition_mode = PPC_BREAKPOINT_CONDITION_NONE;
+  p.addr = addr;
+  p.addr2 = mask;
+  p.condition_value = 0;
+
+  ALL_LWPS (lp, ptid)
+    booke_insert_point (&p, TIDGET (ptid));
+
+  return 0;
+}
+
+/* Remove a masked watchpoint at ADDR with the mask MASK.
+   RW may be hw_read for a read watchpoint, hw_write for a write watchpoint
+   or hw_access for an access watchpoint.  Returns 0 on success and throws
+   an error on failure.  */
+
+static int
+ppc_linux_remove_mask_watchpoint (struct target_ops *ops, CORE_ADDR addr,
+				  CORE_ADDR mask, int rw)
+{
+  ptid_t ptid;
+  struct lwp_info *lp;
+  struct ppc_hw_breakpoint p;
+
+  gdb_assert (have_ptrace_booke_interface ());
+
+  p.version = PPC_DEBUG_CURRENT_VERSION;
+  p.trigger_type = get_trigger_type (rw);
+  p.addr_mode = PPC_BREAKPOINT_MODE_MASK;
+  p.condition_mode = PPC_BREAKPOINT_CONDITION_NONE;
+  p.addr = addr;
+  p.addr2 = mask;
+  p.condition_value = 0;
+
+  ALL_LWPS (lp, ptid)
+    booke_remove_point (&p, TIDGET (ptid));
+
+  return 0;
+}
+
 /* Check whether we have at least one free DVC register.  */
 static int
 can_use_watchpoint_cond_accel (void)
@@ -2224,6 +2282,26 @@ ppc_linux_watchpoint_addr_within_range (struct target_ops *target,
   return start <= addr + mask && start + length - 1 >= addr;
 }
 
+/* Return the number of registers needed for a masked hardware watchpoint.  */
+
+static int
+ppc_linux_masked_watch_num_registers (struct target_ops *target,
+				      CORE_ADDR addr, CORE_ADDR mask)
+{
+  if (!have_ptrace_booke_interface ()
+	   || (booke_debug_info.features & PPC_DEBUG_FEATURE_DATA_BP_MASK) == 0)
+    return -1;
+  else if ((mask & 0xC0000000) != 0xC0000000)
+    {
+      warning (_("The given mask covers kernel address space "
+		 "and cannot be used.\n"));
+
+      return -2;
+    }
+  else
+    return 2;
+}
+
 static void
 ppc_linux_store_inferior_registers (struct target_ops *ops,
 				    struct regcache *regcache, int regno)
@@ -2438,11 +2516,14 @@ _initialize_ppc_linux_nat (void)
   t->to_region_ok_for_hw_watchpoint = ppc_linux_region_ok_for_hw_watchpoint;
   t->to_insert_watchpoint = ppc_linux_insert_watchpoint;
   t->to_remove_watchpoint = ppc_linux_remove_watchpoint;
+  t->to_insert_mask_watchpoint = ppc_linux_insert_mask_watchpoint;
+  t->to_remove_mask_watchpoint = ppc_linux_remove_mask_watchpoint;
   t->to_stopped_by_watchpoint = ppc_linux_stopped_by_watchpoint;
   t->to_stopped_data_address = ppc_linux_stopped_data_address;
   t->to_watchpoint_addr_within_range = ppc_linux_watchpoint_addr_within_range;
   t->to_can_accel_watchpoint_condition
     = ppc_linux_can_accel_watchpoint_condition;
+  t->to_masked_watch_num_registers = ppc_linux_masked_watch_num_registers;
   t->to_ranged_break_num_registers = ppc_linux_ranged_break_num_registers;
 
   t->to_read_description = ppc_linux_read_description;
diff --git a/gdb/target.c b/gdb/target.c
index 1e1c38e..9c522cb 100644
--- a/gdb/target.c
+++ b/gdb/target.c
@@ -595,6 +595,8 @@ update_current_target (void)
       /* Do not inherit to_ranged_break_num_registers.  */
       INHERIT (to_insert_watchpoint, t);
       INHERIT (to_remove_watchpoint, t);
+      /* Do not inherit to_insert_mask_watchpoint.  */
+      /* Do not inherit to_remove_mask_watchpoint.  */
       INHERIT (to_stopped_data_address, t);
       INHERIT (to_have_steppable_watchpoint, t);
       INHERIT (to_have_continuable_watchpoint, t);
@@ -602,6 +604,7 @@ update_current_target (void)
       INHERIT (to_watchpoint_addr_within_range, t);
       INHERIT (to_region_ok_for_hw_watchpoint, t);
       INHERIT (to_can_accel_watchpoint_condition, t);
+      /* Do not inherit to_masked_watch_num_registers.  */
       INHERIT (to_terminal_init, t);
       INHERIT (to_terminal_inferior, t);
       INHERIT (to_terminal_ours_for_output, t);
@@ -3518,6 +3521,75 @@ target_verify_memory (const gdb_byte *data, CORE_ADDR memaddr, ULONGEST size)
   tcomplain ();
 }
 
+/* The documentation for this function is in its prototype declaration in
+   target.h.  */
+
+int
+target_insert_mask_watchpoint (CORE_ADDR addr, CORE_ADDR mask, int rw)
+{
+  struct target_ops *t;
+
+  for (t = current_target.beneath; t != NULL; t = t->beneath)
+    if (t->to_insert_mask_watchpoint != NULL)
+      {
+	int ret;
+
+	ret = t->to_insert_mask_watchpoint (t, addr, mask, rw);
+
+	if (targetdebug)
+	  fprintf_unfiltered (gdb_stdlog, "\
+target_insert_mask_watchpoint (%s, %s, %d) = %d\n",
+			      core_addr_to_string (addr),
+			      core_addr_to_string (mask), rw, ret);
+
+	return ret;
+      }
+
+  return 1;
+}
+
+/* The documentation for this function is in its prototype declaration in
+   target.h.  */
+
+int
+target_remove_mask_watchpoint (CORE_ADDR addr, CORE_ADDR mask, int rw)
+{
+  struct target_ops *t;
+
+  for (t = current_target.beneath; t != NULL; t = t->beneath)
+    if (t->to_remove_mask_watchpoint != NULL)
+      {
+	int ret;
+
+	ret = t->to_remove_mask_watchpoint (t, addr, mask, rw);
+
+	if (targetdebug)
+	  fprintf_unfiltered (gdb_stdlog, "\
+target_remove_mask_watchpoint (%s, %s, %d) = %d\n",
+			      core_addr_to_string (addr),
+			      core_addr_to_string (mask), rw, ret);
+
+	return ret;
+      }
+
+  return 1;
+}
+
+/* The documentation for this function is in its prototype declaration
+   in target.h.  */
+
+int
+target_masked_watch_num_registers (CORE_ADDR addr, CORE_ADDR mask)
+{
+  struct target_ops *t;
+
+  for (t = current_target.beneath; t != NULL; t = t->beneath)
+    if (t->to_masked_watch_num_registers != NULL)
+      return t->to_masked_watch_num_registers (t, addr, mask);
+
+  return -1;
+}
+
 /* The documentation for this function is in its prototype declaration
    in target.h.  */
 
diff --git a/gdb/target.h b/gdb/target.h
index 11380ed..52e0276 100644
--- a/gdb/target.h
+++ b/gdb/target.h
@@ -459,6 +459,10 @@ struct target_ops
     int (*to_remove_watchpoint) (CORE_ADDR, int, int, struct expression *);
     int (*to_insert_watchpoint) (CORE_ADDR, int, int, struct expression *);
 
+    int (*to_insert_mask_watchpoint) (struct target_ops *,
+				      CORE_ADDR, CORE_ADDR, int);
+    int (*to_remove_mask_watchpoint) (struct target_ops *,
+				      CORE_ADDR, CORE_ADDR, int);
     int (*to_stopped_by_watchpoint) (void);
     int to_have_steppable_watchpoint;
     int to_have_continuable_watchpoint;
@@ -472,6 +476,8 @@ struct target_ops
 
     int (*to_can_accel_watchpoint_condition) (CORE_ADDR, int, int,
 					      struct expression *);
+    int (*to_masked_watch_num_registers) (struct target_ops *,
+					  CORE_ADDR, CORE_ADDR);
     void (*to_terminal_init) (void);
     void (*to_terminal_inferior) (void);
     void (*to_terminal_ours_for_output) (void);
@@ -1362,6 +1368,20 @@ extern char *target_thread_name (struct thread_info *);
 #define	target_remove_watchpoint(addr, len, type, cond) \
      (*current_target.to_remove_watchpoint) (addr, len, type, cond)
 
+/* Insert a new masked watchpoint at ADDR using the mask MASK.
+   RW may be hw_read for a read watchpoint, hw_write for a write watchpoint
+   or hw_access for an access watchpoint.  Returns 0 for success, 1 if
+   masked watchpoints are not supported, -1 for failure.  */
+
+extern int target_insert_mask_watchpoint (CORE_ADDR, CORE_ADDR, int);
+
+/* Remove a masked watchpoint at ADDR with the mask MASK.
+   RW may be hw_read for a read watchpoint, hw_write for a write watchpoint
+   or hw_access for an access watchpoint.  Returns 0 for success, non-zero
+   for failure.  */
+
+extern int target_remove_mask_watchpoint (CORE_ADDR, CORE_ADDR, int);
+
 #define target_insert_hw_breakpoint(gdbarch, bp_tgt) \
      (*current_target.to_insert_hw_breakpoint) (gdbarch, bp_tgt)
 
@@ -1395,6 +1415,12 @@ extern int target_ranged_break_num_registers (void);
 #define target_can_accel_watchpoint_condition(addr, len, type, cond) \
   (*current_target.to_can_accel_watchpoint_condition) (addr, len, type, cond)
 
+/* Return number of debug registers needed for a masked watchpoint,
+   -1 if masked watchpoints are not supported or -2 if the given address
+   and mask combination cannot be used.  */
+
+extern int target_masked_watch_num_registers (CORE_ADDR addr, CORE_ADDR mask);
+
 /* Target can execute in reverse?  */
 #define target_can_execute_reverse \
      (current_target.to_can_execute_reverse ? \


^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [needs doc review] Re: [RFA 3/3] Implement support for PowerPC BookE masked watchpoints
  2011-05-05 21:57           ` Thiago Jung Bauermann
@ 2011-05-06 10:28             ` Eli Zaretskii
  2011-05-06 20:35               ` Thiago Jung Bauermann
  0 siblings, 1 reply; 38+ messages in thread
From: Eli Zaretskii @ 2011-05-06 10:28 UTC (permalink / raw)
  To: Thiago Jung Bauermann; +Cc: uweigand, gdb-patches

> From: Thiago Jung Bauermann <bauerman@br.ibm.com>
> Cc: uweigand@de.ibm.com, gdb-patches ml <gdb-patches@sourceware.org>
> Date: Thu, 05 May 2011 18:56:58 -0300
> 
> > >   A @dfn{masked watchpoint} specifies a mask in addition to an address
> > >   to watch.  The @code{mask} argument implies the @code{-location}
> > >   argument, which means that the expression will be resolved to a memory
> > >   address at watchpoint creation time (@pxref{Set Watchpoints}.)
> > 
> > What do you mean by "implies"?  Do you mean that -location must be
> > specified if "mask" is specified?  If so, "implies" is not a good
> > word.
> 
> I mean that if you specify mask, then it's as if you specified -location
> as well. Do you think it's not clear enough?
> 
> > I also don't really understand the part about "resolving to a memory
> > address at watchpoint creation time".  What were you trying to say?
> 
> I tried to explain what -location does in a very short sentence. :-)
> 
> In this version I moved the explanation about masked watchpoints from
> the PowerPC section to the Set Watchpoints section. I think it makes
> more sense there. This also made unnecessary any separate explanation
> about -location since it comes right after the masked watchpoint
> explanation.
> 
> What do you think of this version?

It's okay, but I think the last sentence would be clearer with this
minor change:

   The @code{mask} argument implies @code{-location}.

If you move the paragraph you added below the one that describes the
`-location' switch, this will be perfect, since `-location' will have
been explained immediately before the reference to it in your new text
about masked watchpoints.

Okay with that change.

Thanks.

^ permalink raw reply	[flat|nested] 38+ messages in thread

* Re: [needs doc review] Re: [RFA 3/3] Implement support for PowerPC BookE masked watchpoints
  2011-05-06 10:28             ` Eli Zaretskii
@ 2011-05-06 20:35               ` Thiago Jung Bauermann
  0 siblings, 0 replies; 38+ messages in thread
From: Thiago Jung Bauermann @ 2011-05-06 20:35 UTC (permalink / raw)
  To: Eli Zaretskii
  Cc: uweigand, gdb-patches, Pedro Alves, Joel Brobecker, Jan Kratochvil

On Fri, 2011-05-06 at 13:27 +0300, Eli Zaretskii wrote:
> > From: Thiago Jung Bauermann <bauerman@br.ibm.com>
> > Cc: uweigand@de.ibm.com, gdb-patches ml <gdb-patches@sourceware.org>
> > Date: Thu, 05 May 2011 18:56:58 -0300
> > 
> > What do you think of this version?
> 
> It's okay, but I think the last sentence would be clearer with this
> minor change:
> 
>    The @code{mask} argument implies @code{-location}.

Done.

> If you move the paragraph you added below the one that describes the
> `-location' switch, this will be perfect, since `-location' will have
> been explained immediately before the reference to it in your new text
> about masked watchpoints.

Indeed. That's what I did.

> Okay with that change.

Thanks! Since the code part was approved by Ulrich, I committed the
following.

Finally the BookE debug features enablement work is finished, I can't
believe it. :-) I'd like to thank you all for reviewing the many
versions of these patches and for the suggestions you gave.
-- 
[]'s
Thiago Jung Bauermann
IBM Linux Technology Center


2011-05-06  Sergio Durigan Junior  <sergiodj@linux.vnet.ibm.com>
	    Thiago Jung Bauermann  <bauerman@br.ibm.com>

	Implement support for PowerPC BookE masked watchpoints.

gdb/
	* NEWS: Mention masked watchpoint support.  Create "Changed commands"
	section.
	* breakpoint.h (struct breakpoint_ops) <works_in_software_mode>: New
	method.  Initialize to NULL in all existing breakpoint_ops instances.
	(struct breakpoint) <hw_wp_mask>: New field.
	* breakpoint.c (is_masked_watchpoint): Add prototype.
	(update_watchpoint): Don't set b->val for masked watchpoints.  Call
	breakpoint's breakpoint_ops.works_in_software_mode if available.
	(watchpoints_triggered): Handle the case of a hardware masked
	watchpoint trigger.
	(watchpoint_check): Likewise.
	(works_in_software_mode_watchpoint): New function.
	(insert_masked_watchpoint, remove_masked_watchpoint)
	(resources_needed_masked_watchpoint)
	(works_in_software_mode_masked_watchpoint, print_it_masked_watchpoint)
	(print_one_detail_masked_watchpoint, print_mention_masked_watchpoint)
	(print_recreate_masked_watchpoint, is_masked_watchpoint): New
	functions.
	(masked_watchpoint_breakpoint_ops): New structure.
	(watch_command_1): Check for the existence of the `mask' parameter.
	Set b->ops according to the type of hardware watchpoint being created.
	* ppc-linux-nat.c (ppc_linux_insert_mask_watchpoint)
	(ppc_linux_remove_mask_watchpoint)
	(ppc_linux_masked_watch_num_registers): New functions.
	(_initialize_ppc_linux_nat): Initialize to_insert_mask_watchpoint,
	to_remove_mask_watchpoint and to_masked_watch_num_registers.
	* target.c (update_current_target): Mention to_insert_mask_watchpoint,
	to_remove_mask_watchpoint, and to_masked_watch_num_registers.
	(target_insert_mask_watchpoint, target_remove_mask_watchpoint)
	(target_masked_watch_num_registers): New functions.
	* target.h (struct target_ops) <to_insert_mask_watchpoint>,
	<to_remove_mask_watchpoint>, <to_masked_watch_num_registers>: New
	methods.
	(target_insert_mask_watchpoint, target_remove_mask_watchpoint)
	(target_masked_watch_num_registers): Add prototypes.

gdb/doc/
	* gdb.texinfo (Set Watchpoints): Document mask parameter.
	(PowerPC Embedded): Mention support of masked watchpoints.


diff --git a/gdb/NEWS b/gdb/NEWS
index 1a22c66..9b59419 100644
--- a/gdb/NEWS
+++ b/gdb/NEWS
@@ -3,10 +3,24 @@
 
 *** Changes since GDB 7.3
 
+* When natively debugging programs on PowerPC BookE processors running
+  a Linux kernel version 2.6.34 or later, GDB supports masked hardware
+  watchpoints, which specify a mask in addition to an address to watch.
+  The mask specifies that some bits of an address (the bits which are
+  reset in the mask) should be ignored when matching the address accessed
+  by the inferior against the watchpoint address.  See the "PowerPC Embedded"
+  section in the user manual for more details.
+
 * The new option --once causes GDBserver to stop listening for connections once
   the first connection is made.  The listening port used by GDBserver will
   become available after that.
 
+* Changed commands
+
+watch EXPRESSION mask MASK_VALUE
+  The watch command now supports the mask argument which allows creation
+  of masked watchpoints, if the current architecture supports this feature.
+
 *** Changes in GDB 7.3
 
 * GDB has a new command: "thread find [REGEXP]".
diff --git a/gdb/ada-lang.c b/gdb/ada-lang.c
index d434521..ebd5fd2 100644
--- a/gdb/ada-lang.c
+++ b/gdb/ada-lang.c
@@ -10950,6 +10950,7 @@ static struct breakpoint_ops catch_exception_breakpoint_ops =
   NULL, /* remove */
   NULL, /* breakpoint_hit */
   NULL, /* resources_needed */
+  NULL, /* works_in_software_mode */
   print_it_catch_exception,
   print_one_catch_exception,
   NULL, /* print_one_detail */
@@ -10990,6 +10991,7 @@ static struct breakpoint_ops catch_exception_unhandled_breakpoint_ops = {
   NULL, /* remove */
   NULL, /* breakpoint_hit */
   NULL, /* resources_needed */
+  NULL, /* works_in_software_mode */
   print_it_catch_exception_unhandled,
   print_one_catch_exception_unhandled,
   NULL, /* print_one_detail */
@@ -11028,6 +11030,7 @@ static struct breakpoint_ops catch_assert_breakpoint_ops = {
   NULL, /* remove */
   NULL, /* breakpoint_hit */
   NULL, /* resources_needed */
+  NULL, /* works_in_software_mode */
   print_it_catch_assert,
   print_one_catch_assert,
   NULL, /* print_one_detail */
diff --git a/gdb/breakpoint.c b/gdb/breakpoint.c
index 8358dac..b864700 100644
--- a/gdb/breakpoint.c
+++ b/gdb/breakpoint.c
@@ -224,6 +224,8 @@ static void disable_trace_command (char *, int);
 
 static void trace_pass_command (char *, int);
 
+static int is_masked_watchpoint (const struct breakpoint *b);
+
 /* Assuming we're creating a static tracepoint, does S look like a
    static tracepoint marker spec ("-m MARKER_ID")?  */
 #define is_marker_spec(s)						\
@@ -1345,8 +1347,10 @@ update_watchpoint (struct breakpoint *b, int reparse)
       /* Avoid setting b->val if it's already set.  The meaning of
 	 b->val is 'the last value' user saw, and we should update
 	 it only if we reported that last value to user.  As it
-	 happens, the code that reports it updates b->val directly.  */
-      if (!b->val_valid)
+	 happens, the code that reports it updates b->val directly.
+	 We don't keep track of the memory value for masked
+	 watchpoints.  */
+      if (!b->val_valid && !is_masked_watchpoint (b))
 	{
 	  b->val = v;
 	  b->val_valid = 1;
@@ -1435,19 +1439,23 @@ update_watchpoint (struct breakpoint *b, int reparse)
 		    (b->type, i, other_type_used);
 	      if (target_resources_ok <= 0)
 		{
-		  if (target_resources_ok == 0
-		      && b->type != bp_hardware_watchpoint)
+		  /* If there's no works_in_software_mode method, we
+		     assume that the watchpoint works in software mode.  */
+		  int sw_mode = (!b->ops || !b->ops->works_in_software_mode
+				 || b->ops->works_in_software_mode (b));
+
+		  if (target_resources_ok == 0 && !sw_mode)
 		    error (_("Target does not support this type of "
 			     "hardware watchpoint."));
-		  else if (target_resources_ok < 0
-		      && b->type != bp_hardware_watchpoint)
-		    error (_("Target can only support one kind "
-			     "of HW watchpoint at a time."));
+		  else if (target_resources_ok < 0 && !sw_mode)
+		    error (_("There are not enough available hardware "
+			     "resources for this watchpoint."));
 		  else
 		    b->type = bp_watchpoint;
 		}
 	    }
-	  else if (b->type != bp_hardware_watchpoint)
+	  else if (b->ops && b->ops->works_in_software_mode
+		   && !b->ops->works_in_software_mode (b))
 	    error (_("Expression cannot be implemented with "
 		     "read/access watchpoint."));
 	  else
@@ -3694,15 +3702,27 @@ watchpoints_triggered (struct target_waitstatus *ws)
 
 	b->watchpoint_triggered = watch_triggered_no;
 	for (loc = b->loc; loc; loc = loc->next)
-	  /* Exact match not required.  Within range is
-	     sufficient.  */
-	  if (target_watchpoint_addr_within_range (&current_target,
-						   addr, loc->address,
-						   loc->length))
-	    {
-	      b->watchpoint_triggered = watch_triggered_yes;
-	      break;
-	    }
+	  {
+	    if (is_masked_watchpoint (loc->owner))
+	      {
+		CORE_ADDR newaddr = addr & loc->owner->hw_wp_mask;
+		CORE_ADDR start = loc->address & loc->owner->hw_wp_mask;
+
+		if (newaddr == start)
+		  {
+		    b->watchpoint_triggered = watch_triggered_yes;
+		    break;
+		  }
+	      }
+	    /* Exact match not required.  Within range is sufficient.  */
+	    else if (target_watchpoint_addr_within_range (&current_target,
+							 addr, loc->address,
+							 loc->length))
+	      {
+		b->watchpoint_triggered = watch_triggered_yes;
+		break;
+	      }
+	  }
       }
 
   return 1;
@@ -3799,9 +3819,16 @@ watchpoint_check (void *p)
          might be in the middle of evaluating a function call.  */
 
       int pc = 0;
-      struct value *mark = value_mark ();
+      struct value *mark;
       struct value *new_val;
 
+      if (is_masked_watchpoint (b))
+	/* Since we don't know the exact trigger address (from
+	   stopped_data_address), just tell the user we've triggered
+	   a mask watchpoint.  */
+	return WP_VALUE_CHANGED;
+
+      mark = value_mark ();
       fetch_subexp_value (b->exp, &pc, &new_val, NULL, NULL);
 
       /* We use value_equal_contents instead of value_equal because
@@ -6303,6 +6330,7 @@ static struct breakpoint_ops catch_fork_breakpoint_ops =
   remove_catch_fork,
   breakpoint_hit_catch_fork,
   NULL, /* resources_needed */
+  NULL, /* works_in_software_mode */
   print_it_catch_fork,
   print_one_catch_fork,
   NULL, /* print_one_detail */
@@ -6401,6 +6429,7 @@ static struct breakpoint_ops catch_vfork_breakpoint_ops =
   remove_catch_vfork,
   breakpoint_hit_catch_vfork,
   NULL, /* resources_needed */
+  NULL, /* works_in_software_mode */
   print_it_catch_vfork,
   print_one_catch_vfork,
   NULL, /* print_one_detail */
@@ -6688,6 +6717,7 @@ static struct breakpoint_ops catch_syscall_breakpoint_ops =
   remove_catch_syscall,
   breakpoint_hit_catch_syscall,
   NULL, /* resources_needed */
+  NULL, /* works_in_software_mode */
   print_it_catch_syscall,
   print_one_catch_syscall,
   NULL, /* print_one_detail */
@@ -6845,6 +6875,7 @@ static struct breakpoint_ops catch_exec_breakpoint_ops =
   remove_catch_exec,
   breakpoint_hit_catch_exec,
   NULL, /* resources_needed */
+  NULL, /* works_in_software_mode */
   print_it_catch_exec,
   print_one_catch_exec,
   NULL, /* print_one_detail */
@@ -8470,6 +8501,7 @@ static struct breakpoint_ops ranged_breakpoint_ops =
   NULL, /* remove */
   breakpoint_hit_ranged_breakpoint,
   resources_needed_ranged_breakpoint,
+  NULL, /* works_in_software_mode */
   print_it_ranged_breakpoint,
   print_one_ranged_breakpoint,
   print_one_detail_ranged_breakpoint,
@@ -8777,6 +8809,15 @@ resources_needed_watchpoint (const struct bp_location *bl)
   return target_region_ok_for_hw_watchpoint (bl->address, length);
 }
 
+/* Implement the "works_in_software_mode" breakpoint_ops method for
+   hardware watchpoints.  */
+
+int
+works_in_software_mode_watchpoint (const struct breakpoint *b)
+{
+  return b->type == bp_hardware_watchpoint;
+}
+
 /* The breakpoint_ops structure to be used in hardware watchpoints.  */
 
 static struct breakpoint_ops watchpoint_breakpoint_ops =
@@ -8785,6 +8826,7 @@ static struct breakpoint_ops watchpoint_breakpoint_ops =
   remove_watchpoint,
   NULL, /* breakpoint_hit */
   resources_needed_watchpoint,
+  works_in_software_mode_watchpoint,
   NULL, /* print_it */
   NULL, /* print_one */
   NULL, /* print_one_detail */
@@ -8792,6 +8834,192 @@ static struct breakpoint_ops watchpoint_breakpoint_ops =
   NULL  /* print_recreate */
 };
 
+/* Implement the "insert" breakpoint_ops method for
+   masked hardware watchpoints.  */
+
+static int
+insert_masked_watchpoint (struct bp_location *bl)
+{
+  return target_insert_mask_watchpoint (bl->address, bl->owner->hw_wp_mask,
+					bl->watchpoint_type);
+}
+
+/* Implement the "remove" breakpoint_ops method for
+   masked hardware watchpoints.  */
+
+static int
+remove_masked_watchpoint (struct bp_location *bl)
+{
+  return target_remove_mask_watchpoint (bl->address, bl->owner->hw_wp_mask,
+				        bl->watchpoint_type);
+}
+
+/* Implement the "resources_needed" breakpoint_ops method for
+   masked hardware watchpoints.  */
+
+static int
+resources_needed_masked_watchpoint (const struct bp_location *bl)
+{
+  return target_masked_watch_num_registers (bl->address,
+					    bl->owner->hw_wp_mask);
+}
+
+/* Implement the "works_in_software_mode" breakpoint_ops method for
+   masked hardware watchpoints.  */
+
+static int
+works_in_software_mode_masked_watchpoint (const struct breakpoint *b)
+{
+  return 0;
+}
+
+/* Implement the "print_it" breakpoint_ops method for
+   masked hardware watchpoints.  */
+
+static enum print_stop_action
+print_it_masked_watchpoint (struct breakpoint *b)
+{
+  /* Masked watchpoints have only one location.  */
+  gdb_assert (b->loc && b->loc->next == NULL);
+
+  switch (b->type)
+    {
+    case bp_hardware_watchpoint:
+      annotate_watchpoint (b->number);
+      if (ui_out_is_mi_like_p (uiout))
+	ui_out_field_string
+	  (uiout, "reason",
+	   async_reason_lookup (EXEC_ASYNC_WATCHPOINT_TRIGGER));
+      break;
+
+    case bp_read_watchpoint:
+      if (ui_out_is_mi_like_p (uiout))
+	ui_out_field_string
+	  (uiout, "reason",
+	   async_reason_lookup (EXEC_ASYNC_READ_WATCHPOINT_TRIGGER));
+      break;
+
+    case bp_access_watchpoint:
+      if (ui_out_is_mi_like_p (uiout))
+	ui_out_field_string
+	  (uiout, "reason",
+	   async_reason_lookup (EXEC_ASYNC_ACCESS_WATCHPOINT_TRIGGER));
+      break;
+    default:
+      internal_error (__FILE__, __LINE__,
+		      _("Invalid hardware watchpoint type."));
+    }
+
+  mention (b);
+  ui_out_text (uiout, _("\n\
+Check the underlying instruction at PC for the memory\n\
+address and value which triggered this watchpoint.\n"));
+  ui_out_text (uiout, "\n");
+
+  /* More than one watchpoint may have been triggered.  */
+  return PRINT_UNKNOWN;
+}
+
+/* Implement the "print_one_detail" breakpoint_ops method for
+   masked hardware watchpoints.  */
+
+static void
+print_one_detail_masked_watchpoint (const struct breakpoint *b,
+				    struct ui_out *uiout)
+{
+  /* Masked watchpoints have only one location.  */
+  gdb_assert (b->loc && b->loc->next == NULL);
+
+  ui_out_text (uiout, "\tmask ");
+  ui_out_field_core_addr (uiout, "mask", b->loc->gdbarch, b->hw_wp_mask);
+  ui_out_text (uiout, "\n");
+}
+
+/* Implement the "print_mention" breakpoint_ops method for
+   masked hardware watchpoints.  */
+
+static void
+print_mention_masked_watchpoint (struct breakpoint *b)
+{
+  struct cleanup *ui_out_chain;
+
+  switch (b->type)
+    {
+    case bp_hardware_watchpoint:
+      ui_out_text (uiout, "Masked hardware watchpoint ");
+      ui_out_chain = make_cleanup_ui_out_tuple_begin_end (uiout, "wpt");
+      break;
+    case bp_read_watchpoint:
+      ui_out_text (uiout, "Masked hardware read watchpoint ");
+      ui_out_chain = make_cleanup_ui_out_tuple_begin_end (uiout, "hw-rwpt");
+      break;
+    case bp_access_watchpoint:
+      ui_out_text (uiout, "Masked hardware access (read/write) watchpoint ");
+      ui_out_chain = make_cleanup_ui_out_tuple_begin_end (uiout, "hw-awpt");
+      break;
+    default:
+      internal_error (__FILE__, __LINE__,
+		      _("Invalid hardware watchpoint type."));
+    }
+
+  ui_out_field_int (uiout, "number", b->number);
+  ui_out_text (uiout, ": ");
+  ui_out_field_string (uiout, "exp", b->exp_string);
+  do_cleanups (ui_out_chain);
+}
+
+/* Implement the "print_recreate" breakpoint_ops method for
+   masked hardware watchpoints.  */
+
+static void
+print_recreate_masked_watchpoint (struct breakpoint *b, struct ui_file *fp)
+{
+  char tmp[40];
+
+  switch (b->type)
+    {
+    case bp_hardware_watchpoint:
+      fprintf_unfiltered (fp, "watch");
+      break;
+    case bp_read_watchpoint:
+      fprintf_unfiltered (fp, "rwatch");
+      break;
+    case bp_access_watchpoint:
+      fprintf_unfiltered (fp, "awatch");
+      break;
+    default:
+      internal_error (__FILE__, __LINE__,
+		      _("Invalid hardware watchpoint type."));
+    }
+
+  sprintf_vma (tmp, b->hw_wp_mask);
+  fprintf_unfiltered (fp, " %s mask 0x%s", b->exp_string, tmp);
+}
+
+/* The breakpoint_ops structure to be used in masked hardware watchpoints.  */
+
+static struct breakpoint_ops masked_watchpoint_breakpoint_ops =
+{
+  insert_masked_watchpoint,
+  remove_masked_watchpoint,
+  NULL, /* breakpoint_hit */
+  resources_needed_masked_watchpoint,
+  works_in_software_mode_masked_watchpoint,
+  print_it_masked_watchpoint,
+  NULL, /* print_one */
+  print_one_detail_masked_watchpoint,
+  print_mention_masked_watchpoint,
+  print_recreate_masked_watchpoint
+};
+
+/* Tell whether the given watchpoint is a masked hardware watchpoint.  */
+
+static int
+is_masked_watchpoint (const struct breakpoint *b)
+{
+  return b->ops == &masked_watchpoint_breakpoint_ops;
+}
+
 /* accessflag:  hw_write:  watch write, 
                 hw_read:   watch read, 
 		hw_access: watch access (read or write) */
@@ -8807,73 +9035,97 @@ watch_command_1 (char *arg, int accessflag, int from_tty,
   struct frame_info *frame;
   char *exp_start = NULL;
   char *exp_end = NULL;
-  char *tok, *id_tok_start, *end_tok;
-  int toklen;
+  char *tok, *end_tok;
+  int toklen = -1;
   char *cond_start = NULL;
   char *cond_end = NULL;
   enum bptype bp_type;
   int thread = -1;
   int pc = 0;
+  /* Flag to indicate whether we are going to use masks for
+     the hardware watchpoint.  */
+  int use_mask = 0;
+  CORE_ADDR mask = 0;
 
   /* Make sure that we actually have parameters to parse.  */
   if (arg != NULL && arg[0] != '\0')
     {
-      toklen = strlen (arg); /* Size of argument list.  */
+      char *value_start;
 
-      /* Points tok to the end of the argument list.  */
-      tok = arg + toklen - 1;
+      /* Look for "parameter value" pairs at the end
+	 of the arguments string.  */
+      for (tok = arg + strlen (arg) - 1; tok > arg; tok--)
+	{
+	  /* Skip whitespace at the end of the argument list.  */
+	  while (tok > arg && (*tok == ' ' || *tok == '\t'))
+	    tok--;
+
+	  /* Find the beginning of the last token.
+	     This is the value of the parameter.  */
+	  while (tok > arg && (*tok != ' ' && *tok != '\t'))
+	    tok--;
+	  value_start = tok + 1;
+
+	  /* Skip whitespace.  */
+	  while (tok > arg && (*tok == ' ' || *tok == '\t'))
+	    tok--;
+
+	  end_tok = tok;
+
+	  /* Find the beginning of the second to last token.
+	     This is the parameter itself.  */
+	  while (tok > arg && (*tok != ' ' && *tok != '\t'))
+	    tok--;
+	  tok++;
+	  toklen = end_tok - tok + 1;
+
+	  if (toklen == 6 && !strncmp (tok, "thread", 6))
+	    {
+	      /* At this point we've found a "thread" token, which means
+		 the user is trying to set a watchpoint that triggers
+		 only in a specific thread.  */
+	      char *endp;
 
-      /* Go backwards in the parameters list.  Skip the last
-         parameter.  If we're expecting a 'thread <thread_num>'
-         parameter, this should be the thread identifier.  */
-      while (tok > arg && (*tok == ' ' || *tok == '\t'))
-        tok--;
-      while (tok > arg && (*tok != ' ' && *tok != '\t'))
-        tok--;
+	      if (thread != -1)
+		error(_("You can specify only one thread."));
 
-      /* Points end_tok to the beginning of the last token.  */
-      id_tok_start = tok + 1;
+	      /* Extract the thread ID from the next token.  */
+	      thread = strtol (value_start, &endp, 0);
 
-      /* Go backwards in the parameters list.  Skip one more
-         parameter.  If we're expecting a 'thread <thread_num>'
-         parameter, we should reach a "thread" token.  */
-      while (tok > arg && (*tok == ' ' || *tok == '\t'))
-        tok--;
+	      /* Check if the user provided a valid numeric value for the
+		 thread ID.  */
+	      if (*endp != ' ' && *endp != '\t' && *endp != '\0')
+		error (_("Invalid thread ID specification %s."), value_start);
 
-      end_tok = tok;
+	      /* Check if the thread actually exists.  */
+	      if (!valid_thread_id (thread))
+		error (_("Unknown thread %d."), thread);
+	    }
+	  else if (toklen == 4 && !strncmp (tok, "mask", 4))
+	    {
+	      /* We've found a "mask" token, which means the user wants to
+		 create a hardware watchpoint that is going to have the mask
+		 facility.  */
+	      struct value *mask_value, *mark;
 
-      while (tok > arg && (*tok != ' ' && *tok != '\t'))
-        tok--;
+	      if (use_mask)
+		error(_("You can specify only one mask."));
 
-      /* Move the pointer forward to skip the whitespace and
-         calculate the length of the token.  */
-      tok++;
-      toklen = end_tok - tok;
+	      use_mask = just_location = 1;
 
-      if (toklen >= 1 && strncmp (tok, "thread", toklen) == 0)
-        {
-          /* At this point we've found a "thread" token, which means
-             the user is trying to set a watchpoint that triggers
-             only in a specific thread.  */
-          char *endp;
-
-          /* Extract the thread ID from the next token.  */
-          thread = strtol (id_tok_start, &endp, 0);
-
-          /* Check if the user provided a valid numeric value for the
-             thread ID.  */
-          if (*endp != ' ' && *endp != '\t' && *endp != '\0')
-            error (_("Invalid thread ID specification %s."), id_tok_start);
-
-          /* Check if the thread actually exists.  */
-          if (!valid_thread_id (thread))
-            error (_("Unknown thread %d."), thread);
-
-          /* Truncate the string and get rid of the thread <thread_num>
-             parameter before the parameter list is parsed by the
-             evaluate_expression() function.  */
-          *tok = '\0';
-        }
+	      mark = value_mark ();
+	      mask_value = parse_to_comma_and_eval (&value_start);
+	      mask = value_as_address (mask_value);
+	      value_free_to_mark (mark);
+	    }
+	  else
+	    /* We didn't recognize what we found.  We should stop here.  */
+	    break;
+
+	  /* Truncate the string and get rid of the "parameter value" pair before
+	     the arguments string is parsed by the parse_exp_1 function.  */
+	  *tok = '\0';
+	}
     }
 
   /* Parse the rest of the arguments.  */
@@ -8904,10 +9156,22 @@ watch_command_1 (char *arg, int accessflag, int from_tty,
 
   if (just_location)
     {
+      int ret;
+
       exp_valid_block = NULL;
       val = value_addr (result);
       release_value (val);
       value_free_to_mark (mark);
+
+      if (use_mask)
+	{
+	  ret = target_masked_watch_num_registers (value_as_address (val),
+						   mask);
+	  if (ret == -1)
+	    error (_("This target does not support masked watchpoints."));
+	  else if (ret == -2)
+	    error (_("Invalid mask or memory region."));
+	}
     }
   else if (val != NULL)
     release_value (val);
@@ -9004,9 +9268,18 @@ watch_command_1 (char *arg, int accessflag, int from_tty,
     }
   else
     b->exp_string = savestring (exp_start, exp_end - exp_start);
-  b->val = val;
-  b->val_valid = 1;
-  b->ops = &watchpoint_breakpoint_ops;
+
+  if (use_mask)
+    {
+      b->hw_wp_mask = mask;
+      b->ops = &masked_watchpoint_breakpoint_ops;
+    }
+  else
+    {
+      b->val = val;
+      b->val_valid = 1;
+      b->ops = &watchpoint_breakpoint_ops;
+    }
 
   if (cond_start)
     b->cond_string = savestring (cond_start, cond_end - cond_start);
@@ -9543,6 +9816,7 @@ static struct breakpoint_ops gnu_v3_exception_catchpoint_ops = {
   NULL, /* remove */
   NULL, /* breakpoint_hit */
   NULL, /* resources_needed */
+  NULL, /* works_in_software_mode */
   print_it_exception_catchpoint,
   print_one_exception_catchpoint,
   NULL, /* print_one_detail */
diff --git a/gdb/breakpoint.h b/gdb/breakpoint.h
index 7a9c2d4..7fa705f 100644
--- a/gdb/breakpoint.h
+++ b/gdb/breakpoint.h
@@ -410,6 +410,11 @@ struct breakpoint_ops
      the breakpoint or watchpoint needs one debug register.  */
   int (*resources_needed) (const struct bp_location *);
 
+  /* Tell whether we can downgrade from a hardware watchpoint to a software
+     one.  If not, the user will not be able to enable the watchpoint when
+     there are not enough hardware resources available.  */
+  int (*works_in_software_mode) (const struct breakpoint *);
+
   /* The normal print routine for this breakpoint, called when we
      hit it.  */
   enum print_stop_action (*print_it) (struct breakpoint *);
@@ -651,6 +656,9 @@ struct breakpoint
 
     /* Whether this watchpoint is exact (see target_exact_watchpoints).  */
     int exact;
+
+    /* The mask address for a masked hardware watchpoint.  */
+    CORE_ADDR hw_wp_mask;
   };
 
 typedef struct breakpoint *breakpoint_p;
diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo
index ff5b7cb..4bb1581 100644
--- a/gdb/doc/gdb.texinfo
+++ b/gdb/doc/gdb.texinfo
@@ -3728,7 +3728,7 @@ watchpoints, which do not slow down the running of your program.
 
 @table @code
 @kindex watch
-@item watch @r{[}-l@r{|}-location@r{]} @var{expr} @r{[}thread @var{threadnum}@r{]}
+@item watch @r{[}-l@r{|}-location@r{]} @var{expr} @r{[}thread @var{threadnum}@r{]} @r{[}mask @var{maskvalue}@r{]}
 Set a watchpoint for an expression.  @value{GDBN} will break when the
 expression @var{expr} is written into by the program and its value
 changes.  The simplest (and the most popular) use of this command is
@@ -3739,7 +3739,7 @@ to watch the value of a single variable:
 @end smallexample
 
 If the command includes a @code{@r{[}thread @var{threadnum}@r{]}}
-clause, @value{GDBN} breaks only when the thread identified by
+argument, @value{GDBN} breaks only when the thread identified by
 @var{threadnum} changes the value of @var{expr}.  If any other threads
 change the value of @var{expr}, @value{GDBN} will not break.  Note
 that watchpoints restricted to a single thread in this way only work
@@ -3754,13 +3754,30 @@ to determine the size of the watched memory.  If the expression's
 result does not have an address, then @value{GDBN} will print an
 error.
 
+The @code{@r{[}mask @var{maskvalue}@r{]}} argument allows creation
+of masked watchpoints, if the current architecture supports this
+feature (e.g., PowerPC Embedded architecture, see @ref{PowerPC
+Embedded}.)  A @dfn{masked watchpoint} specifies a mask in addition
+to an address to watch.  The mask specifies that some bits of an address
+(the bits which are reset in the mask) should be ignored when matching
+the address accessed by the inferior against the watchpoint address.
+Thus, a masked watchpoint watches many addresses simultaneously---those
+addresses whose unmasked bits are identical to the unmasked bits in the
+watchpoint address.  The @code{mask} argument implies @code{-location}.
+Examples:
+
+@smallexample
+(@value{GDBP}) watch foo mask 0xffff00ff
+(@value{GDBP}) watch *0xdeadbeef mask 0xffffff00
+@end smallexample
+
 @kindex rwatch
-@item rwatch @r{[}-l@r{|}-location@r{]} @var{expr} @r{[}thread @var{threadnum}@r{]}
+@item rwatch @r{[}-l@r{|}-location@r{]} @var{expr} @r{[}thread @var{threadnum}@r{]} @r{[}mask @var{maskvalue}@r{]}
 Set a watchpoint that will break when the value of @var{expr} is read
 by the program.
 
 @kindex awatch
-@item awatch @r{[}-l@r{|}-location@r{]} @var{expr} @r{[}thread @var{threadnum}@r{]}
+@item awatch @r{[}-l@r{|}-location@r{]} @var{expr} @r{[}thread @var{threadnum}@r{]} @r{[}mask @var{maskvalue}@r{]}
 Set a watchpoint that will break when @var{expr} is either read from
 or written into by the program.
 
@@ -18783,6 +18800,9 @@ region using one of the following commands (@pxref{Expressions}):
 (@value{GDBP}) watch @{char[@var{length}]@} @var{address}
 @end smallexample
 
+PowerPC embedded processors support masked watchpoints.  See the discussion
+about the @code{mask} argument in @ref{Set Watchpoints}.
+
 @cindex ranged breakpoint
 PowerPC embedded processors support hardware accelerated
 @dfn{ranged breakpoints}.  A ranged breakpoint stops execution of
diff --git a/gdb/ppc-linux-nat.c b/gdb/ppc-linux-nat.c
index 6f11715..275de78 100644
--- a/gdb/ppc-linux-nat.c
+++ b/gdb/ppc-linux-nat.c
@@ -1739,6 +1739,64 @@ get_trigger_type (int rw)
   return t;
 }
 
+/* Insert a new masked watchpoint at ADDR using the mask MASK.
+   RW may be hw_read for a read watchpoint, hw_write for a write watchpoint
+   or hw_access for an access watchpoint.  Returns 0 on success and throws
+   an error on failure.  */
+
+static int
+ppc_linux_insert_mask_watchpoint (struct target_ops *ops, CORE_ADDR addr,
+				  CORE_ADDR mask, int rw)
+{
+  ptid_t ptid;
+  struct lwp_info *lp;
+  struct ppc_hw_breakpoint p;
+
+  gdb_assert (have_ptrace_booke_interface ());
+
+  p.version = PPC_DEBUG_CURRENT_VERSION;
+  p.trigger_type = get_trigger_type (rw);
+  p.addr_mode = PPC_BREAKPOINT_MODE_MASK;
+  p.condition_mode = PPC_BREAKPOINT_CONDITION_NONE;
+  p.addr = addr;
+  p.addr2 = mask;
+  p.condition_value = 0;
+
+  ALL_LWPS (lp, ptid)
+    booke_insert_point (&p, TIDGET (ptid));
+
+  return 0;
+}
+
+/* Remove a masked watchpoint at ADDR with the mask MASK.
+   RW may be hw_read for a read watchpoint, hw_write for a write watchpoint
+   or hw_access for an access watchpoint.  Returns 0 on success and throws
+   an error on failure.  */
+
+static int
+ppc_linux_remove_mask_watchpoint (struct target_ops *ops, CORE_ADDR addr,
+				  CORE_ADDR mask, int rw)
+{
+  ptid_t ptid;
+  struct lwp_info *lp;
+  struct ppc_hw_breakpoint p;
+
+  gdb_assert (have_ptrace_booke_interface ());
+
+  p.version = PPC_DEBUG_CURRENT_VERSION;
+  p.trigger_type = get_trigger_type (rw);
+  p.addr_mode = PPC_BREAKPOINT_MODE_MASK;
+  p.condition_mode = PPC_BREAKPOINT_CONDITION_NONE;
+  p.addr = addr;
+  p.addr2 = mask;
+  p.condition_value = 0;
+
+  ALL_LWPS (lp, ptid)
+    booke_remove_point (&p, TIDGET (ptid));
+
+  return 0;
+}
+
 /* Check whether we have at least one free DVC register.  */
 static int
 can_use_watchpoint_cond_accel (void)
@@ -2224,6 +2282,26 @@ ppc_linux_watchpoint_addr_within_range (struct target_ops *target,
   return start <= addr + mask && start + length - 1 >= addr;
 }
 
+/* Return the number of registers needed for a masked hardware watchpoint.  */
+
+static int
+ppc_linux_masked_watch_num_registers (struct target_ops *target,
+				      CORE_ADDR addr, CORE_ADDR mask)
+{
+  if (!have_ptrace_booke_interface ()
+	   || (booke_debug_info.features & PPC_DEBUG_FEATURE_DATA_BP_MASK) == 0)
+    return -1;
+  else if ((mask & 0xC0000000) != 0xC0000000)
+    {
+      warning (_("The given mask covers kernel address space "
+		 "and cannot be used.\n"));
+
+      return -2;
+    }
+  else
+    return 2;
+}
+
 static void
 ppc_linux_store_inferior_registers (struct target_ops *ops,
 				    struct regcache *regcache, int regno)
@@ -2438,11 +2516,14 @@ _initialize_ppc_linux_nat (void)
   t->to_region_ok_for_hw_watchpoint = ppc_linux_region_ok_for_hw_watchpoint;
   t->to_insert_watchpoint = ppc_linux_insert_watchpoint;
   t->to_remove_watchpoint = ppc_linux_remove_watchpoint;
+  t->to_insert_mask_watchpoint = ppc_linux_insert_mask_watchpoint;
+  t->to_remove_mask_watchpoint = ppc_linux_remove_mask_watchpoint;
   t->to_stopped_by_watchpoint = ppc_linux_stopped_by_watchpoint;
   t->to_stopped_data_address = ppc_linux_stopped_data_address;
   t->to_watchpoint_addr_within_range = ppc_linux_watchpoint_addr_within_range;
   t->to_can_accel_watchpoint_condition
     = ppc_linux_can_accel_watchpoint_condition;
+  t->to_masked_watch_num_registers = ppc_linux_masked_watch_num_registers;
   t->to_ranged_break_num_registers = ppc_linux_ranged_break_num_registers;
 
   t->to_read_description = ppc_linux_read_description;
diff --git a/gdb/target.c b/gdb/target.c
index 1e1c38e..9c522cb 100644
--- a/gdb/target.c
+++ b/gdb/target.c
@@ -595,6 +595,8 @@ update_current_target (void)
       /* Do not inherit to_ranged_break_num_registers.  */
       INHERIT (to_insert_watchpoint, t);
       INHERIT (to_remove_watchpoint, t);
+      /* Do not inherit to_insert_mask_watchpoint.  */
+      /* Do not inherit to_remove_mask_watchpoint.  */
       INHERIT (to_stopped_data_address, t);
       INHERIT (to_have_steppable_watchpoint, t);
       INHERIT (to_have_continuable_watchpoint, t);
@@ -602,6 +604,7 @@ update_current_target (void)
       INHERIT (to_watchpoint_addr_within_range, t);
       INHERIT (to_region_ok_for_hw_watchpoint, t);
       INHERIT (to_can_accel_watchpoint_condition, t);
+      /* Do not inherit to_masked_watch_num_registers.  */
       INHERIT (to_terminal_init, t);
       INHERIT (to_terminal_inferior, t);
       INHERIT (to_terminal_ours_for_output, t);
@@ -3518,6 +3521,75 @@ target_verify_memory (const gdb_byte *data, CORE_ADDR memaddr, ULONGEST size)
   tcomplain ();
 }
 
+/* The documentation for this function is in its prototype declaration in
+   target.h.  */
+
+int
+target_insert_mask_watchpoint (CORE_ADDR addr, CORE_ADDR mask, int rw)
+{
+  struct target_ops *t;
+
+  for (t = current_target.beneath; t != NULL; t = t->beneath)
+    if (t->to_insert_mask_watchpoint != NULL)
+      {
+	int ret;
+
+	ret = t->to_insert_mask_watchpoint (t, addr, mask, rw);
+
+	if (targetdebug)
+	  fprintf_unfiltered (gdb_stdlog, "\
+target_insert_mask_watchpoint (%s, %s, %d) = %d\n",
+			      core_addr_to_string (addr),
+			      core_addr_to_string (mask), rw, ret);
+
+	return ret;
+      }
+
+  return 1;
+}
+
+/* The documentation for this function is in its prototype declaration in
+   target.h.  */
+
+int
+target_remove_mask_watchpoint (CORE_ADDR addr, CORE_ADDR mask, int rw)
+{
+  struct target_ops *t;
+
+  for (t = current_target.beneath; t != NULL; t = t->beneath)
+    if (t->to_remove_mask_watchpoint != NULL)
+      {
+	int ret;
+
+	ret = t->to_remove_mask_watchpoint (t, addr, mask, rw);
+
+	if (targetdebug)
+	  fprintf_unfiltered (gdb_stdlog, "\
+target_remove_mask_watchpoint (%s, %s, %d) = %d\n",
+			      core_addr_to_string (addr),
+			      core_addr_to_string (mask), rw, ret);
+
+	return ret;
+      }
+
+  return 1;
+}
+
+/* The documentation for this function is in its prototype declaration
+   in target.h.  */
+
+int
+target_masked_watch_num_registers (CORE_ADDR addr, CORE_ADDR mask)
+{
+  struct target_ops *t;
+
+  for (t = current_target.beneath; t != NULL; t = t->beneath)
+    if (t->to_masked_watch_num_registers != NULL)
+      return t->to_masked_watch_num_registers (t, addr, mask);
+
+  return -1;
+}
+
 /* The documentation for this function is in its prototype declaration
    in target.h.  */
 
diff --git a/gdb/target.h b/gdb/target.h
index 11380ed..52e0276 100644
--- a/gdb/target.h
+++ b/gdb/target.h
@@ -459,6 +459,10 @@ struct target_ops
     int (*to_remove_watchpoint) (CORE_ADDR, int, int, struct expression *);
     int (*to_insert_watchpoint) (CORE_ADDR, int, int, struct expression *);
 
+    int (*to_insert_mask_watchpoint) (struct target_ops *,
+				      CORE_ADDR, CORE_ADDR, int);
+    int (*to_remove_mask_watchpoint) (struct target_ops *,
+				      CORE_ADDR, CORE_ADDR, int);
     int (*to_stopped_by_watchpoint) (void);
     int to_have_steppable_watchpoint;
     int to_have_continuable_watchpoint;
@@ -472,6 +476,8 @@ struct target_ops
 
     int (*to_can_accel_watchpoint_condition) (CORE_ADDR, int, int,
 					      struct expression *);
+    int (*to_masked_watch_num_registers) (struct target_ops *,
+					  CORE_ADDR, CORE_ADDR);
     void (*to_terminal_init) (void);
     void (*to_terminal_inferior) (void);
     void (*to_terminal_ours_for_output) (void);
@@ -1362,6 +1368,20 @@ extern char *target_thread_name (struct thread_info *);
 #define	target_remove_watchpoint(addr, len, type, cond) \
      (*current_target.to_remove_watchpoint) (addr, len, type, cond)
 
+/* Insert a new masked watchpoint at ADDR using the mask MASK.
+   RW may be hw_read for a read watchpoint, hw_write for a write watchpoint
+   or hw_access for an access watchpoint.  Returns 0 for success, 1 if
+   masked watchpoints are not supported, -1 for failure.  */
+
+extern int target_insert_mask_watchpoint (CORE_ADDR, CORE_ADDR, int);
+
+/* Remove a masked watchpoint at ADDR with the mask MASK.
+   RW may be hw_read for a read watchpoint, hw_write for a write watchpoint
+   or hw_access for an access watchpoint.  Returns 0 for success, non-zero
+   for failure.  */
+
+extern int target_remove_mask_watchpoint (CORE_ADDR, CORE_ADDR, int);
+
 #define target_insert_hw_breakpoint(gdbarch, bp_tgt) \
      (*current_target.to_insert_hw_breakpoint) (gdbarch, bp_tgt)
 
@@ -1395,6 +1415,12 @@ extern int target_ranged_break_num_registers (void);
 #define target_can_accel_watchpoint_condition(addr, len, type, cond) \
   (*current_target.to_can_accel_watchpoint_condition) (addr, len, type, cond)
 
+/* Return number of debug registers needed for a masked watchpoint,
+   -1 if masked watchpoints are not supported or -2 if the given address
+   and mask combination cannot be used.  */
+
+extern int target_masked_watch_num_registers (CORE_ADDR addr, CORE_ADDR mask);
+
 /* Target can execute in reverse?  */
 #define target_can_execute_reverse \
      (current_target.to_can_execute_reverse ? \


^ permalink raw reply	[flat|nested] 38+ messages in thread

end of thread, other threads:[~2011-05-06 20:35 UTC | newest]

Thread overview: 38+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2011-01-13 20:55 [RFA] Implement support for PowerPC BookE masked watchpoints Thiago Jung Bauermann
2011-01-31 20:09 ` Thiago Jung Bauermann
2011-02-17 15:10 ` Ulrich Weigand
2011-04-18 21:22   ` [RFA 2/3] Demote to sw watchpoint only in update_watchpoint Thiago Jung Bauermann
2011-04-29 17:26     ` Ulrich Weigand
2011-05-03  4:56       ` Thiago Jung Bauermann
2011-05-03  6:05         ` Eli Zaretskii
2011-05-03  9:58           ` Pedro Alves
2011-05-03 16:57             ` Eli Zaretskii
2011-05-03 17:41               ` Pedro Alves
2011-05-03 18:03                 ` Eli Zaretskii
2011-05-03 18:12                   ` Pedro Alves
2011-05-03 20:30                     ` Eli Zaretskii
2011-05-04  0:03                       ` Thiago Jung Bauermann
2011-05-04  3:07                         ` Eli Zaretskii
2011-05-04 22:21                           ` Thiago Jung Bauermann
2011-05-05  3:09                             ` Eli Zaretskii
2011-05-05  8:15                             ` Pedro Alves
2011-05-05 10:28                               ` Eli Zaretskii
2011-05-05 15:27                                 ` Pedro Alves
2011-05-05 16:27                                   ` Eli Zaretskii
2011-05-05 11:10                               ` Ulrich Weigand
2011-05-05 15:21                                 ` Pedro Alves
2011-05-04 19:12           ` Thiago Jung Bauermann
2011-05-04 20:31             ` Eli Zaretskii
2011-05-04 22:22               ` Thiago Jung Bauermann
2011-05-05 11:04         ` Ulrich Weigand
2011-04-18 21:22   ` [RFA 1/3] Change watchpoint's enable state in do_enable_breakpoint Thiago Jung Bauermann
2011-04-29 17:21     ` Ulrich Weigand
2011-05-04  0:11       ` Thiago Jung Bauermann
2011-04-18 21:24   ` [RFA 3/3] Implement support for PowerPC BookE masked watchpoints Thiago Jung Bauermann
2011-04-29 17:46     ` Ulrich Weigand
2011-05-03  4:56       ` [needs doc review] " Thiago Jung Bauermann
2011-05-03  6:24         ` Eli Zaretskii
2011-05-05 21:57           ` Thiago Jung Bauermann
2011-05-06 10:28             ` Eli Zaretskii
2011-05-06 20:35               ` Thiago Jung Bauermann
2011-05-05 11:07         ` Ulrich Weigand

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).