2011-05-06 Sergio Durigan Junior <sergiodj@linux.vnet.ibm.com>
authorThiago Jung Bauermann <bauerman@br.ibm.com>
Fri, 6 May 2011 18:46:33 +0000 (18:46 +0000)
committerThiago Jung Bauermann <bauerman@br.ibm.com>
Fri, 6 May 2011 18:46:33 +0000 (18:46 +0000)
    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.

gdb/ChangeLog
gdb/NEWS
gdb/ada-lang.c
gdb/breakpoint.c
gdb/breakpoint.h
gdb/doc/ChangeLog
gdb/doc/gdb.texinfo
gdb/ppc-linux-nat.c
gdb/target.c
gdb/target.h

index 1306b88..61b8b15 100644 (file)
@@ -1,3 +1,43 @@
+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.
+       * 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.
+
 2011-05-06  Jan Kratochvil  <jan.kratochvil@redhat.com>
 
        PR 12573
index 1a22c66..9b59419 100644 (file)
--- 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]".
index d434521..ebd5fd2 100644 (file)
@@ -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 */
index b5fc448..e582c36 100644 (file)
@@ -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 */
index 7a9c2d4..7fa705f 100644 (file)
@@ -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;
index d7e610d..2eacb32 100644 (file)
@@ -1,3 +1,10 @@
+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.texinfo (Set Watchpoints): Document mask parameter.
+       (PowerPC Embedded): Mention support of masked watchpoints.
+
 2011-05-03  Joel Brobecker  <brobecker@adacore.com>
 
        * gdb.texinfo (In Memoriam): Replace litteral uses of `GDB' with
index 0ac5672..3618b70 100644 (file)
@@ -3725,7 +3725,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
@@ -3736,7 +3736,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
@@ -3751,13 +3751,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.
 
@@ -18780,6 +18797,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
index 6f11715..275de78 100644 (file)
@@ -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;
index 1e1c38e..9c522cb 100644 (file)
@@ -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.  */
 
index 11380ed..52e0276 100644 (file)
@@ -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 ? \