This is the mail archive of the gdb-patches@sourceware.org mailing list for the GDB project.


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

Re: [patch 1/3] Implement support for PowerPC BookE masked watchpoints


Hi,

This is the latest version of this patch, refreshed to apply on top of
the ranged watchpoints patch.

I also got rid of the hw_point_flag enum, which was a source of
criticism before, at the expense of one additional target method per new
type of special breakpoint or watchpoint:
target_masked_watch_num_extra_regs and
target_ranged_break_num_extra_regs (for the upcoming new version of the
ranged breakpoints patch).

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 indentation change:

---- 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


2010-12-23  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)
	(extra_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_extra_regs): New functions.
	(_initialize_ppc_linux_nat): Initialize to_insert_mask_watchpoint,
	to_remove_mask_watchpoint and to_masked_watch_num_extra_regs.
	* target.c (update_current_target): Mention to_insert_mask_watchpoint,
	to_remove_mask_watchpoint, and to_masked_watch_num_extra_regs.
	(target_insert_mask_watchpoint, target_remove_mask_watchpoint)
	(target_masked_watch_num_extra_regs): New functions.
	* target.h (struct target_ops) <to_insert_mask_watchpoint>,
	<to_remove_mask_watchpoint>, <to_masked_watch_num_extra_regs>: New
	methods.
	(target_insert_mask_watchpoint, target_remove_mask_watchpoint)
	(target_masked_watch_num_extra_regs): 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 91f1835..c4a9c79 100644
--- a/gdb/NEWS
+++ b/gdb/NEWS
@@ -106,6 +106,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),
@@ -122,6 +130,19 @@
 
   ** 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 3a2a266..cd87a47 100644
--- a/gdb/ada-lang.c
+++ b/gdb/ada-lang.c
@@ -10793,7 +10793,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);
 }
@@ -10822,8 +10822,10 @@ static struct breakpoint_ops catch_exception_breakpoint_ops =
   NULL, /* remove */
   NULL, /* breakpoint_hit */
   NULL, /* extra_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
 };
@@ -10831,7 +10833,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);
 }
@@ -10861,8 +10864,10 @@ static struct breakpoint_ops catch_exception_unhandled_breakpoint_ops = {
   NULL, /* remove */
   NULL, /* breakpoint_hit */
   NULL, /* extra_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
 };
@@ -10870,7 +10875,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);
 }
@@ -10898,8 +10903,10 @@ static struct breakpoint_ops catch_assert_breakpoint_ops = {
   NULL, /* remove */
   NULL, /* breakpoint_hit */
   NULL, /* extra_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 9c10b30..9213289 100644
--- a/gdb/breakpoint.c
+++ b/gdb/breakpoint.c
@@ -219,6 +219,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)						\
@@ -1402,7 +1404,14 @@ update_watchpoint (struct breakpoint *b, int reparse)
 	    reg_cnt = can_use_hardware_watchpoint (val_chain, b->exact);
 
 	    if (!reg_cnt)
-	      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;
+	      }
 	    else
 	      {
 		int i, other_type_used, target_resources_ok;
@@ -1425,7 +1434,17 @@ update_watchpoint (struct breakpoint *b, int reparse)
 		target_resources_ok = target_can_use_hardware_watchpoint
 		  (bp_hardware_watchpoint, i + reg_cnt, 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))
+		      {
+			b->type = bp_hardware_watchpoint;
+			error (_("This watchpoint cannot be used in software mode."));
+		      }
+		    else
+		      b->type = bp_watchpoint;
+		  }
 		else
 		  b->type = bp_hardware_watchpoint;
 	      }
@@ -3433,7 +3452,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);
       }
@@ -3569,15 +3588,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;
@@ -3691,6 +3725,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.  */
@@ -4774,9 +4813,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);
@@ -5957,7 +5999,7 @@ breakpoint_hit_catch_fork (struct breakpoint *b)
 /* Implement the "print_it" breakpoint_ops method for fork 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), "),
@@ -6016,8 +6058,10 @@ static struct breakpoint_ops catch_fork_breakpoint_ops =
   remove_catch_fork,
   breakpoint_hit_catch_fork,
   NULL, /* extra_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
 };
@@ -6050,7 +6094,7 @@ breakpoint_hit_catch_vfork (struct breakpoint *b)
 /* Implement the "print_it" breakpoint_ops method for vfork 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), "),
@@ -6108,8 +6152,10 @@ static struct breakpoint_ops catch_vfork_breakpoint_ops =
   remove_catch_vfork,
   breakpoint_hit_catch_vfork,
   NULL, /* extra_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
 };
@@ -6229,7 +6275,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
@@ -6390,8 +6436,10 @@ static struct breakpoint_ops catch_syscall_breakpoint_ops =
   remove_catch_syscall,
   breakpoint_hit_catch_syscall,
   NULL, /* extra_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
 };
@@ -6493,7 +6541,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,
@@ -6544,8 +6592,10 @@ static struct breakpoint_ops catch_exec_breakpoint_ops =
   remove_catch_exec,
   breakpoint_hit_catch_exec,
   NULL, /* extra_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
 };
@@ -8190,12 +8240,206 @@ static struct breakpoint_ops watchpoint_breakpoint_ops =
   remove_watchpoint,
   NULL, /* breakpoint_hit */
   extra_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 "extra_resources_needed" breakpoint_ops method for
+   masked hardware watchpoints.  */
+
+static int
+extra_resources_needed_masked_watchpoint (const struct breakpoint *b,
+					  const struct bp_location *bl)
+{
+  return target_masked_watch_num_extra_regs ();
+}
+
+/* Implement the "works_in_software_mode_masked_watchpoint" 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, _("\nCheck the underlying instruction \
+at PC for address and value related to this watchpoint trigger.\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);
+}
+
+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 */
+  extra_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
+};
+
+/* Tells 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) */
@@ -8210,8 +8454,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;
@@ -8219,66 +8463,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;
 
-      /* 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--;
+	      /* 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."));
 
-      /* Move the pointer forward to skip the whitespace and
-         calculate the length of the token.  */
-      tok++;
-      toklen = end_tok - tok;
+	      if (use_mask)
+		error(_("You can specify only one mask."));
 
-      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';
-        }
+	      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';
+	}
     }
 
   /* Parse the rest of the arguments.  */
@@ -8356,6 +8629,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_extra_regs ();
+
       i = hw_watchpoint_used_count (bp_type, &other_type_used);
       target_resources_ok = 
 	target_can_use_hardware_watchpoint (bp_type, i + reg_cnt,
@@ -8367,10 +8645,19 @@ watch_command_1 (char *arg, int accessflag, int from_tty,
 	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;
+    {
+      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);
 
@@ -8438,7 +8725,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 only when there's one memory region to be
      watched, which needs only one debug register.  */
@@ -8890,7 +9184,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;
 
@@ -8980,8 +9275,10 @@ static struct breakpoint_ops gnu_v3_exception_catchpoint_ops = {
   NULL, /* remove */
   NULL, /* breakpoint_hit */
   NULL, /* extra_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 8e68532..74565c0 100644
--- a/gdb/breakpoint.h
+++ b/gdb/breakpoint.h
@@ -27,6 +27,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 size
@@ -382,13 +383,33 @@ struct breakpoint_ops
   int (*extra_resources_needed) (const struct breakpoint *,
 				 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 *);
@@ -597,6 +618,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 cef320e..b7ab17b 100644
--- a/gdb/doc/gdb.texinfo
+++ b/gdb/doc/gdb.texinfo
@@ -3745,7 +3745,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
@@ -3756,12 +3756,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,
@@ -3772,12 +3777,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.
 
@@ -18748,6 +18753,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 7c853a9..7806df0 100644
--- a/gdb/ppc-linux-nat.c
+++ b/gdb/ppc-linux-nat.c
@@ -1692,6 +1692,59 @@ get_trigger_type (int rw)
   return t;
 }
 
+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;
+}
+
+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)
@@ -2158,6 +2211,14 @@ ppc_linux_watchpoint_addr_within_range (struct target_ops *target,
   return start <= addr + mask && start + length - 1 >= addr;
 }
 
+static int
+ppc_linux_masked_watch_num_extra_regs (struct target_ops *target)
+{
+  return ((have_ptrace_booke_interface ()
+	   && booke_debug_info.features & PPC_DEBUG_FEATURE_DATA_BP_MASK)?
+	  1 : -1);
+}
+
 static void
 ppc_linux_store_inferior_registers (struct target_ops *ops,
 				    struct regcache *regcache, int regno)
@@ -2371,10 +2432,13 @@ _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_extra_regs = ppc_linux_masked_watch_num_extra_regs;
 
   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 dd976c9..0283425 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_extra_regs.  */
       INHERIT (to_terminal_init, t);
       INHERIT (to_terminal_inferior, t);
       INHERIT (to_terminal_ours_for_output, t);
@@ -3334,6 +3337,64 @@ target_verify_memory (const gdb_byte *data, CORE_ADDR memaddr, ULONGEST size)
   tcomplain ();
 }
 
+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_minus_one ();
+}
+
+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_minus_one ();
+}
+
+int
+target_masked_watch_num_extra_regs (void)
+{
+  struct target_ops *t;
+
+  for (t = current_target.beneath; t != NULL; t = t->beneath)
+    if (t->to_masked_watch_num_extra_regs != NULL)
+      return t->to_masked_watch_num_extra_regs (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 2ef5c56..d956e98 100644
--- a/gdb/target.h
+++ b/gdb/target.h
@@ -446,6 +446,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;
@@ -459,6 +463,7 @@ struct target_ops
 
     int (*to_can_accel_watchpoint_condition) (CORE_ADDR, int, int,
 					      struct expression *);
+    int (*to_masked_watch_num_extra_regs) (struct target_ops *);
     void (*to_terminal_init) (void);
     void (*to_terminal_inferior) (void);
     void (*to_terminal_ours_for_output) (void);
@@ -1336,6 +1341,11 @@ 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)
 
+/* Hardware watchpoints with an associated address mask.  */
+
+extern int target_insert_mask_watchpoint (CORE_ADDR, CORE_ADDR, int);
+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)
 
@@ -1364,6 +1374,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 extra debug registers needed for a masked watchpoint,
+   or -1 if masked watchpoints are not supported.  */
+
+extern int target_masked_watch_num_extra_regs (void);
+
 /* Target can execute in reverse?  */
 #define target_can_execute_reverse \
      (current_target.to_can_execute_reverse ? \



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