[gdb/breakpoints] Fix longjmp master breakpoint with separate debug info
[deliverable/binutils-gdb.git] / gdb / breakpoint.c
index a4ae8b2d8c9b99735898f70357108858d24ebd47..70b0d88cb45aedcf24a389e6bbfcbee0c926a8c4 100644 (file)
@@ -1,6 +1,6 @@
 /* Everything about breakpoints, for GDB.
 
-   Copyright (C) 1986-2020 Free Software Foundation, Inc.
+   Copyright (C) 1986-2021 Free Software Foundation, Inc.
 
    This file is part of GDB.
 
@@ -172,8 +172,6 @@ static int hw_watchpoint_used_count_others (struct breakpoint *except,
 static void enable_breakpoint_disp (struct breakpoint *, enum bpdisp,
                                    int count);
 
-static void free_bp_location (struct bp_location *loc);
-static void incref_bp_location (struct bp_location *loc);
 static void decref_bp_location (struct bp_location **loc);
 
 static struct bp_location *allocate_bp_location (struct breakpoint *bpt);
@@ -2173,7 +2171,7 @@ should_be_inserted (struct bp_location *bl)
       && stepping_past_nonsteppable_watchpoint ())
     {
       infrun_debug_printf ("stepping past non-steppable watchpoint. "
-                          "skipping watchpoint at %s:%d\n",
+                          "skipping watchpoint at %s:%d",
                           paddress (bl->gdbarch, bl->address), bl->length);
       return 0;
     }
@@ -3329,100 +3327,134 @@ create_overlay_event_breakpoint (void)
     }
 }
 
-static void
-create_longjmp_master_breakpoint (void)
+/* Install a master longjmp breakpoint for OBJFILE using a probe.  Return
+   true if a breakpoint was installed.  */
+
+static bool
+create_longjmp_master_breakpoint_probe (objfile *objfile)
 {
-  scoped_restore_current_program_space restore_pspace;
+  struct gdbarch *gdbarch = objfile->arch ();
+  struct breakpoint_objfile_data *bp_objfile_data
+    = get_breakpoint_objfile_data (objfile);
 
-  for (struct program_space *pspace : program_spaces)
+  if (!bp_objfile_data->longjmp_searched)
     {
-      set_current_program_space (pspace);
+      std::vector<probe *> ret
+       = find_probes_in_objfile (objfile, "libc", "longjmp");
 
-      for (objfile *objfile : current_program_space->objfiles ())
+      if (!ret.empty ())
        {
-         int i;
-         struct gdbarch *gdbarch;
-         struct breakpoint_objfile_data *bp_objfile_data;
+         /* We are only interested in checking one element.  */
+         probe *p = ret[0];
 
-         gdbarch = objfile->arch ();
+         if (!p->can_evaluate_arguments ())
+           {
+             /* We cannot use the probe interface here,
+                because it does not know how to evaluate
+                arguments.  */
+             ret.clear ();
+           }
+       }
+      bp_objfile_data->longjmp_probes = ret;
+      bp_objfile_data->longjmp_searched = 1;
+    }
 
-         bp_objfile_data = get_breakpoint_objfile_data (objfile);
+  if (bp_objfile_data->longjmp_probes.empty ())
+    return false;
 
-         if (!bp_objfile_data->longjmp_searched)
-           {
-             std::vector<probe *> ret
-               = find_probes_in_objfile (objfile, "libc", "longjmp");
+  for (probe *p : bp_objfile_data->longjmp_probes)
+    {
+      struct breakpoint *b;
 
-             if (!ret.empty ())
-               {
-                 /* We are only interested in checking one element.  */
-                 probe *p = ret[0];
+      b = create_internal_breakpoint (gdbarch,
+                                     p->get_relocated_address (objfile),
+                                     bp_longjmp_master,
+                                     &internal_breakpoint_ops);
+      b->location = new_probe_location ("-probe-stap libc:longjmp");
+      b->enable_state = bp_disabled;
+    }
 
-                 if (!p->can_evaluate_arguments ())
-                   {
-                     /* We cannot use the probe interface here,
-                        because it does not know how to evaluate
-                        arguments.  */
-                     ret.clear ();
-                   }
-               }
-             bp_objfile_data->longjmp_probes = ret;
-             bp_objfile_data->longjmp_searched = 1;
-           }
+  return true;
+}
 
-         if (!bp_objfile_data->longjmp_probes.empty ())
-           {
-             for (probe *p : bp_objfile_data->longjmp_probes)
-               {
-                 struct breakpoint *b;
-
-                 b = create_internal_breakpoint (gdbarch,
-                                                 p->get_relocated_address (objfile),
-                                                 bp_longjmp_master,
-                                                 &internal_breakpoint_ops);
-                 b->location = new_probe_location ("-probe-stap libc:longjmp");
-                 b->enable_state = bp_disabled;
-               }
+/* Install master longjmp breakpoints for OBJFILE using longjmp_names.
+   Return true if at least one breakpoint was installed.  */
 
+static bool
+create_longjmp_master_breakpoint_names (objfile *objfile)
+{
+  struct gdbarch *gdbarch = objfile->arch ();
+  if (!gdbarch_get_longjmp_target_p (gdbarch))
+    return false;
+
+  struct breakpoint_objfile_data *bp_objfile_data
+    = get_breakpoint_objfile_data (objfile);
+  unsigned int installed_bp = 0;
+
+  for (int i = 0; i < NUM_LONGJMP_NAMES; i++)
+    {
+      struct breakpoint *b;
+      const char *func_name;
+      CORE_ADDR addr;
+      struct explicit_location explicit_loc;
+
+      if (msym_not_found_p (bp_objfile_data->longjmp_msym[i].minsym))
+       continue;
+
+      func_name = longjmp_names[i];
+      if (bp_objfile_data->longjmp_msym[i].minsym == NULL)
+       {
+         struct bound_minimal_symbol m;
+
+         m = lookup_minimal_symbol_text (func_name, objfile);
+         if (m.minsym == NULL)
+           {
+             /* Prevent future lookups in this objfile.  */
+             bp_objfile_data->longjmp_msym[i].minsym = &msym_not_found;
              continue;
            }
+         bp_objfile_data->longjmp_msym[i] = m;
+       }
 
-         if (!gdbarch_get_longjmp_target_p (gdbarch))
-           continue;
+      addr = BMSYMBOL_VALUE_ADDRESS (bp_objfile_data->longjmp_msym[i]);
+      b = create_internal_breakpoint (gdbarch, addr, bp_longjmp_master,
+                                     &internal_breakpoint_ops);
+      initialize_explicit_location (&explicit_loc);
+      explicit_loc.function_name = ASTRDUP (func_name);
+      b->location = new_explicit_location (&explicit_loc);
+      b->enable_state = bp_disabled;
+      installed_bp++;
+    }
 
-         for (i = 0; i < NUM_LONGJMP_NAMES; i++)
-           {
-             struct breakpoint *b;
-             const char *func_name;
-             CORE_ADDR addr;
-             struct explicit_location explicit_loc;
+  return installed_bp > 0;
+}
 
-             if (msym_not_found_p (bp_objfile_data->longjmp_msym[i].minsym))
-               continue;
+/* Create a master longjmp breakpoint.  */
 
-             func_name = longjmp_names[i];
-             if (bp_objfile_data->longjmp_msym[i].minsym == NULL)
-               {
-                 struct bound_minimal_symbol m;
+static void
+create_longjmp_master_breakpoint (void)
+{
+  scoped_restore_current_program_space restore_pspace;
 
-                 m = lookup_minimal_symbol_text (func_name, objfile);
-                 if (m.minsym == NULL)
-                   {
-                     /* Prevent future lookups in this objfile.  */
-                     bp_objfile_data->longjmp_msym[i].minsym = &msym_not_found;
-                     continue;
-                   }
-                 bp_objfile_data->longjmp_msym[i] = m;
-               }
+  for (struct program_space *pspace : program_spaces)
+    {
+      set_current_program_space (pspace);
 
-             addr = BMSYMBOL_VALUE_ADDRESS (bp_objfile_data->longjmp_msym[i]);
-             b = create_internal_breakpoint (gdbarch, addr, bp_longjmp_master,
-                                             &internal_breakpoint_ops);
-             initialize_explicit_location (&explicit_loc);
-             explicit_loc.function_name = ASTRDUP (func_name);
-             b->location = new_explicit_location (&explicit_loc);
-             b->enable_state = bp_disabled;
-           }
+      for (objfile *obj : current_program_space->objfiles ())
+       {
+         /* Skip separate debug object, it's handled in the loop below.  */
+         if (obj->separate_debug_objfile_backlink != nullptr)
+           continue;
+
+         /* Try a probe kind breakpoint on main objfile.  */
+         if (create_longjmp_master_breakpoint_probe (obj))
+           continue;
+
+         /* Try longjmp_names kind breakpoints on main and separate_debug
+            objfiles.  */
+         for (objfile *debug_objfile : obj->separate_debug_objfiles ())
+           if (create_longjmp_master_breakpoint_names (debug_objfile))
+             break;
        }
     }
 }
@@ -3479,92 +3511,126 @@ create_std_terminate_master_breakpoint (void)
     }
 }
 
-/* Install a master breakpoint on the unwinder's debug hook.  */
+/* Install a master breakpoint on the unwinder's debug hook for OBJFILE using a
+   probe.  Return true if a breakpoint was installed.  */
 
-static void
-create_exception_master_breakpoint (void)
+static bool
+create_exception_master_breakpoint_probe (objfile *objfile)
 {
-  const char *const func_name = "_Unwind_DebugHook";
+  struct breakpoint *b;
+  struct gdbarch *gdbarch;
+  struct breakpoint_objfile_data *bp_objfile_data;
 
-  for (objfile *objfile : current_program_space->objfiles ())
-    {
-      struct breakpoint *b;
-      struct gdbarch *gdbarch;
-      struct breakpoint_objfile_data *bp_objfile_data;
-      CORE_ADDR addr;
-      struct explicit_location explicit_loc;
+  bp_objfile_data = get_breakpoint_objfile_data (objfile);
 
-      bp_objfile_data = get_breakpoint_objfile_data (objfile);
+  /* We prefer the SystemTap probe point if it exists.  */
+  if (!bp_objfile_data->exception_searched)
+    {
+      std::vector<probe *> ret
+       = find_probes_in_objfile (objfile, "libgcc", "unwind");
 
-      /* We prefer the SystemTap probe point if it exists.  */
-      if (!bp_objfile_data->exception_searched)
+      if (!ret.empty ())
        {
-         std::vector<probe *> ret
-           = find_probes_in_objfile (objfile, "libgcc", "unwind");
+         /* We are only interested in checking one element.  */
+         probe *p = ret[0];
 
-         if (!ret.empty ())
+         if (!p->can_evaluate_arguments ())
            {
-             /* We are only interested in checking one element.  */
-             probe *p = ret[0];
-
-             if (!p->can_evaluate_arguments ())
-               {
-                 /* We cannot use the probe interface here, because it does
-                    not know how to evaluate arguments.  */
-                 ret.clear ();
-               }
+             /* We cannot use the probe interface here, because it does
+                not know how to evaluate arguments.  */
+             ret.clear ();
            }
-         bp_objfile_data->exception_probes = ret;
-         bp_objfile_data->exception_searched = 1;
        }
+      bp_objfile_data->exception_probes = ret;
+      bp_objfile_data->exception_searched = 1;
+    }
 
-      if (!bp_objfile_data->exception_probes.empty ())
-       {
-         gdbarch = objfile->arch ();
+  if (bp_objfile_data->exception_probes.empty ())
+    return false;
 
-         for (probe *p : bp_objfile_data->exception_probes)
-           {
-             b = create_internal_breakpoint (gdbarch,
-                                             p->get_relocated_address (objfile),
-                                             bp_exception_master,
-                                             &internal_breakpoint_ops);
-             b->location = new_probe_location ("-probe-stap libgcc:unwind");
-             b->enable_state = bp_disabled;
-           }
+  gdbarch = objfile->arch ();
 
-         continue;
-       }
+  for (probe *p : bp_objfile_data->exception_probes)
+    {
+      b = create_internal_breakpoint (gdbarch,
+                                     p->get_relocated_address (objfile),
+                                     bp_exception_master,
+                                     &internal_breakpoint_ops);
+      b->location = new_probe_location ("-probe-stap libgcc:unwind");
+      b->enable_state = bp_disabled;
+    }
 
-      /* Otherwise, try the hook function.  */
+  return true;
+}
 
-      if (msym_not_found_p (bp_objfile_data->exception_msym.minsym))
-       continue;
+/* Install a master breakpoint on the unwinder's debug hook for OBJFILE using
+   _Unwind_DebugHook.  Return true if a breakpoint was installed.  */
 
-      gdbarch = objfile->arch ();
+static bool
+create_exception_master_breakpoint_hook (objfile *objfile)
+{
+  const char *const func_name = "_Unwind_DebugHook";
+  struct breakpoint *b;
+  struct gdbarch *gdbarch;
+  struct breakpoint_objfile_data *bp_objfile_data;
+  CORE_ADDR addr;
+  struct explicit_location explicit_loc;
 
-      if (bp_objfile_data->exception_msym.minsym == NULL)
-       {
-         struct bound_minimal_symbol debug_hook;
+  bp_objfile_data = get_breakpoint_objfile_data (objfile);
 
-         debug_hook = lookup_minimal_symbol (func_name, NULL, objfile);
-         if (debug_hook.minsym == NULL)
-           {
-             bp_objfile_data->exception_msym.minsym = &msym_not_found;
-             continue;
-           }
+  if (msym_not_found_p (bp_objfile_data->exception_msym.minsym))
+    return false;
+
+  gdbarch = objfile->arch ();
 
-         bp_objfile_data->exception_msym = debug_hook;
+  if (bp_objfile_data->exception_msym.minsym == NULL)
+    {
+      struct bound_minimal_symbol debug_hook;
+
+      debug_hook = lookup_minimal_symbol (func_name, NULL, objfile);
+      if (debug_hook.minsym == NULL)
+       {
+         bp_objfile_data->exception_msym.minsym = &msym_not_found;
+         return false;
        }
 
-      addr = BMSYMBOL_VALUE_ADDRESS (bp_objfile_data->exception_msym);
-      addr = gdbarch_convert_from_func_ptr_addr (gdbarch, addr,
-                                                current_top_target ());
-      b = create_internal_breakpoint (gdbarch, addr, bp_exception_master,
-                                     &internal_breakpoint_ops);
-      initialize_explicit_location (&explicit_loc);
-      explicit_loc.function_name = ASTRDUP (func_name);
-      b->location = new_explicit_location (&explicit_loc);
-      b->enable_state = bp_disabled;
+      bp_objfile_data->exception_msym = debug_hook;
+    }
+
+  addr = BMSYMBOL_VALUE_ADDRESS (bp_objfile_data->exception_msym);
+  addr = gdbarch_convert_from_func_ptr_addr (gdbarch, addr,
+                                            current_top_target ());
+  b = create_internal_breakpoint (gdbarch, addr, bp_exception_master,
+                                 &internal_breakpoint_ops);
+  initialize_explicit_location (&explicit_loc);
+  explicit_loc.function_name = ASTRDUP (func_name);
+  b->location = new_explicit_location (&explicit_loc);
+  b->enable_state = bp_disabled;
+
+  return true;
+}
+
+/* Install a master breakpoint on the unwinder's debug hook.  */
+
+static void
+create_exception_master_breakpoint (void)
+{
+  for (objfile *obj : current_program_space->objfiles ())
+    {
+      /* Skip separate debug object.  */
+      if (obj->separate_debug_objfile_backlink)
+       continue;
+
+      /* Try a probe kind breakpoint.  */
+      if (create_exception_master_breakpoint_probe (obj))
+       continue;
+
+      /* Iterate over separate debug objects and try an _Unwind_DebugHook
+        kind breakpoint.  */
+      for (objfile *sepdebug = obj->separate_debug_objfile;
+          sepdebug != nullptr; sepdebug = sepdebug->separate_debug_objfile)
+       if (create_exception_master_breakpoint_hook (sepdebug))
+         break;
     }
 }
 
@@ -4242,15 +4308,6 @@ is_catchpoint (struct breakpoint *b)
   return (b->type == bp_catchpoint);
 }
 
-/* Frees any storage that is part of a bpstat.  Does not walk the
-   'next' chain.  */
-
-bpstats::~bpstats ()
-{
-  if (bp_location_at != NULL)
-    decref_bp_location (&bp_location_at);
-}
-
 /* Clear a bpstat so that it says we are not at any breakpoint.
    Also free any storage that is part of a bpstat.  */
 
@@ -4283,7 +4340,6 @@ bpstats::bpstats (const bpstats &other)
 {
   if (other.old_val != NULL)
     old_val = release_value (value_copy (other.old_val.get ()));
-  incref_bp_location (bp_location_at);
 }
 
 /* Return a copy of a bpstat.  Like "bs1 = bs2" but all storage that
@@ -4768,21 +4824,19 @@ breakpoint_cond_eval (expression *exp)
 
 bpstats::bpstats (struct bp_location *bl, bpstat **bs_link_pointer)
   : next (NULL),
-    bp_location_at (bl),
+    bp_location_at (bp_location_ref_ptr::new_reference (bl)),
     breakpoint_at (bl->owner),
     commands (NULL),
     print (0),
     stop (0),
     print_it (print_it_normal)
 {
-  incref_bp_location (bl);
   **bs_link_pointer = this;
   *bs_link_pointer = &next;
 }
 
 bpstats::bpstats ()
   : next (NULL),
-    bp_location_at (NULL),
     breakpoint_at (NULL),
     commands (NULL),
     print (0),
@@ -5060,7 +5114,7 @@ bpstat_check_watchpoint (bpstat bs)
   struct watchpoint *b;
 
   /* BS is built for existing struct breakpoint.  */
-  bl = bs->bp_location_at;
+  bl = bs->bp_location_at.get ();
   gdb_assert (bl != NULL);
   b = (struct watchpoint *) bs->breakpoint_at;
   gdb_assert (b != NULL);
@@ -5236,7 +5290,7 @@ bpstat_check_breakpoint_conditions (bpstat bs, thread_info *thread)
   gdb_assert (bs->stop);
 
   /* BS is built for existing struct breakpoint.  */
-  bl = bs->bp_location_at;
+  bl = bs->bp_location_at.get ();
   gdb_assert (bl != NULL);
   b = bs->breakpoint_at;
   gdb_assert (b != NULL);
@@ -7101,7 +7155,7 @@ bp_location::bp_location (breakpoint *owner, bp_loc_type type)
       || this->loc_type == bp_loc_hardware_breakpoint)
     mark_breakpoint_location_modified (this);
 
-  this->refc = 1;
+  incref ();
 }
 
 bp_location::bp_location (breakpoint *owner)
@@ -7118,30 +7172,13 @@ allocate_bp_location (struct breakpoint *bpt)
   return bpt->ops->allocate_location (bpt);
 }
 
-static void
-free_bp_location (struct bp_location *loc)
-{
-  delete loc;
-}
-
-/* Increment reference count.  */
-
-static void
-incref_bp_location (struct bp_location *bl)
-{
-  ++bl->refc;
-}
-
 /* Decrement reference count.  If the reference count reaches 0,
    destroy the bp_location.  Sets *BLP to NULL.  */
 
 static void
 decref_bp_location (struct bp_location **blp)
 {
-  gdb_assert ((*blp)->refc > 0);
-
-  if (--(*blp)->refc == 0)
-    free_bp_location (*blp);
+  bp_location_ref_policy::decref (*blp);
   *blp = NULL;
 }
 
@@ -9263,7 +9300,7 @@ find_condition_and_thread (const char *tok, CORE_ADDR pc,
        }
       else if (toklen >= 1 && strncmp (tok, "-force-condition", toklen) == 0)
        {
-         tok = cond_start = end_tok + 1;
+         tok = tok + toklen;
          force = true;
        }
       else if (toklen >= 1 && strncmp (tok, "thread", toklen) == 0)
@@ -10084,7 +10121,7 @@ break_range_command (const char *arg, int from_tty)
     some constant expressions and in such case still falsely return
     zero.  */
 
-static int
+static bool
 watchpoint_exp_is_const (const struct expression *exp)
 {
   int i = exp->nelts;
@@ -10177,7 +10214,7 @@ watchpoint_exp_is_const (const struct expression *exp)
            if (SYMBOL_CLASS (s) != LOC_BLOCK
                && SYMBOL_CLASS (s) != LOC_CONST
                && SYMBOL_CLASS (s) != LOC_CONST_BYTES)
-             return 0;
+             return false;
            break;
          }
 
@@ -10185,11 +10222,11 @@ watchpoint_exp_is_const (const struct expression *exp)
           the optimistic approach here: If we don't know something,
           then it is not a constant.  */
        default:
-         return 0;
+         return false;
        }
     }
 
-  return 1;
+  return true;
 }
 
 /* Watchpoint destructor.  */
@@ -11082,20 +11119,74 @@ watch_command_wrapper (const char *arg, int from_tty, bool internal)
   watch_command_1 (arg, hw_write, from_tty, 0, internal);
 }
 
+/* Options for the watch, awatch, and rwatch commands.  */
+
+struct watch_options
+{
+  /* For -location.  */
+  bool location = false;
+};
+
+/* Definitions of options for the "watch", "awatch", and "rwatch" commands.
+
+   Historically GDB always accepted both '-location' and '-l' flags for
+   these commands (both flags being synonyms).  When converting to the
+   newer option scheme only '-location' is added here.  That's fine (for
+   backward compatibility) as any non-ambiguous prefix of a flag will be
+   accepted, so '-l', '-loc', are now all accepted.
+
+   What this means is that, if in the future, we add any new flag here
+   that starts with '-l' then this will break backward compatibility, so
+   please, don't do that!  */
+
+static const gdb::option::option_def watch_option_defs[] = {
+  gdb::option::flag_option_def<watch_options> {
+    "location",
+    [] (watch_options *opt) { return &opt->location; },
+    N_("\
+This evaluates EXPRESSION and watches the memory to which is refers.\n\
+-l can be used as a short form of -location."),
+  },
+};
+
+/* Returns the option group used by 'watch', 'awatch', and 'rwatch'
+   commands.  */
+
+static gdb::option::option_def_group
+make_watch_options_def_group (watch_options *opts)
+{
+  return {{watch_option_defs}, opts};
+}
+
 /* A helper function that looks for the "-location" argument and then
    calls watch_command_1.  */
 
 static void
 watch_maybe_just_location (const char *arg, int accessflag, int from_tty)
 {
-  bool just_location = false;
+  watch_options opts;
+  auto grp = make_watch_options_def_group (&opts);
+  gdb::option::process_options
+    (&arg, gdb::option::PROCESS_OPTIONS_UNKNOWN_IS_OPERAND, grp);
+  if (arg != nullptr && *arg == '\0')
+    arg = nullptr;
 
-  if (arg
-      && (check_for_argument (&arg, "-location", sizeof ("-location") - 1)
-         || check_for_argument (&arg, "-l", sizeof ("-l") - 1)))
-    just_location = true;
+  watch_command_1 (arg, accessflag, from_tty, opts.location, false);
+}
 
-  watch_command_1 (arg, accessflag, from_tty, just_location, false);
+/* Command completion for 'watch', 'awatch', and 'rwatch' commands.   */
+static void
+watch_command_completer (struct cmd_list_element *ignore,
+                        completion_tracker &tracker,
+                        const char *text, const char * /*word*/)
+{
+  const auto group = make_watch_options_def_group (nullptr);
+  if (gdb::option::complete_options
+      (tracker, &text, gdb::option::PROCESS_OPTIONS_UNKNOWN_IS_OPERAND, group))
+    return;
+
+  const char *word = advance_to_expression_complete_word_point (tracker, text);
+  expression_completer (ignore, tracker, text, word);
 }
 
 static void
@@ -12626,7 +12717,7 @@ bkpt_print_it (bpstat bs)
 
   gdb_assert (bs->bp_location_at != NULL);
 
-  bl = bs->bp_location_at;
+  bl = bs->bp_location_at.get ();
   b = bs->breakpoint_at;
 
   bp_temp = b->disposition == disp_del;
@@ -15914,32 +16005,46 @@ If REGEX is given, only stop for libraries matching the regular expression."),
                     CATCH_PERMANENT,
                     CATCH_TEMPORARY);
 
-  c = add_com ("watch", class_breakpoint, watch_command, _("\
-Set a watchpoint for an expression.\n\
-Usage: watch [-l|-location] EXPRESSION\n\
-A watchpoint stops execution of your program whenever the value of\n\
-an expression changes.\n\
-If -l or -location is given, this evaluates EXPRESSION and watches\n\
-the memory to which it refers."));
-  set_cmd_completer (c, expression_completer);
-
-  c = add_com ("rwatch", class_breakpoint, rwatch_command, _("\
-Set a read watchpoint for an expression.\n\
-Usage: rwatch [-l|-location] EXPRESSION\n\
-A watchpoint stops execution of your program whenever the value of\n\
-an expression is read.\n\
-If -l or -location is given, this evaluates EXPRESSION and watches\n\
-the memory to which it refers."));
-  set_cmd_completer (c, expression_completer);
-
-  c = add_com ("awatch", class_breakpoint, awatch_command, _("\
-Set a watchpoint for an expression.\n\
-Usage: awatch [-l|-location] EXPRESSION\n\
+  const auto opts = make_watch_options_def_group (nullptr);
+
+  static const std::string watch_help = gdb::option::build_help (_("\
+Set a watchpoint for EXPRESSION.\n\
+Usage: watch [-location] EXPRESSION\n\
+\n\
+Options:\n\
+%OPTIONS%\n\
+\n\
 A watchpoint stops execution of your program whenever the value of\n\
-an expression is either read or written.\n\
-If -l or -location is given, this evaluates EXPRESSION and watches\n\
-the memory to which it refers."));
-  set_cmd_completer (c, expression_completer);
+an expression changes."), opts);
+  c = add_com ("watch", class_breakpoint, watch_command,
+              watch_help.c_str ());
+  set_cmd_completer_handle_brkchars (c, watch_command_completer);
+
+  static const std::string rwatch_help = gdb::option::build_help (_("\
+Set a read watchpoint for EXPRESSION.\n\
+Usage: rwatch [-location] EXPRESSION\n\
+\n\
+Options:\n\
+%OPTIONS%\n\
+\n\
+A read watchpoint stops execution of your program whenever the value of\n\
+an expression is read."), opts);
+  c = add_com ("rwatch", class_breakpoint, rwatch_command,
+              rwatch_help.c_str ());
+  set_cmd_completer_handle_brkchars (c, watch_command_completer);
+
+  static const std::string awatch_help = gdb::option::build_help (_("\
+Set an access watchpoint for EXPRESSION.\n\
+Usage: awatch [-location] EXPRESSION\n\
+\n\
+Options:\n\
+%OPTIONS%\n\
+\n\
+An access watchpoint stops execution of your program whenever the value\n\
+of an expression is either read or written."), opts);
+  c = add_com ("awatch", class_breakpoint, awatch_command,
+              awatch_help.c_str ());
+  set_cmd_completer_handle_brkchars (c, watch_command_completer);
 
   add_info ("watchpoints", info_watchpoints_command, _("\
 Status of specified watchpoints (all watchpoints if no argument)."));
This page took 0.033499 seconds and 4 git commands to generate.