2011-08-04 Pedro Alves <pedro@codesourcery.com>
[deliverable/binutils-gdb.git] / gdb / breakpoint.c
index b5fc44865a4193651bf3f11222bb24a970bf6df0..1495a5eb207c631b4ee41d356bc7dba746b16cc1 100644 (file)
@@ -64,6 +64,7 @@
 #include "xml-syscall.h"
 #include "parser-defs.h"
 #include "cli/cli-utils.h"
+#include "continuations.h"
 
 /* readline include files */
 #include "readline/readline.h"
 #include "mi/mi-common.h"
 #include "python/python.h"
 
-/* Arguments to pass as context to some catch command handlers.  */
-#define CATCH_PERMANENT ((void *) (uintptr_t) 0)
-#define CATCH_TEMPORARY ((void *) (uintptr_t) 1)
-
 /* Prototypes for local functions.  */
 
 static void enable_delete_command (char *, int);
@@ -97,6 +94,8 @@ static void ignore_command (char *, int);
 
 static int breakpoint_re_set_one (void *);
 
+static void breakpoint_re_set_default (struct breakpoint *);
+
 static void clear_command (char *, int);
 
 static void catch_command (char *, int);
@@ -107,11 +106,20 @@ static void break_command_1 (char *, int, int);
 
 static void mention (struct breakpoint *);
 
+static struct breakpoint *set_raw_breakpoint_without_location (struct gdbarch *,
+                                                              enum bptype,
+                                                              const struct breakpoint_ops *);
 /* This function is used in gdbtk sources and thus can not be made
    static.  */
 struct breakpoint *set_raw_breakpoint (struct gdbarch *gdbarch,
-                                             struct symtab_and_line,
-                                             enum bptype);
+                                      struct symtab_and_line,
+                                      enum bptype,
+                                      const struct breakpoint_ops *);
+
+static struct breakpoint *
+  momentary_breakpoint_from_master (struct breakpoint *orig,
+                                   enum bptype type,
+                                   const struct breakpoint_ops *ops);
 
 static void breakpoint_adjustment_warning (CORE_ADDR, CORE_ADDR, int, int);
 
@@ -160,8 +168,6 @@ insertion_state_t;
 static int remove_breakpoint (struct bp_location *, insertion_state_t);
 static int remove_breakpoint_1 (struct bp_location *, insertion_state_t);
 
-static enum print_stop_action print_it_typical (bpstat);
-
 static enum print_stop_action print_bp_stop_message (bpstat bs);
 
 static int watchpoint_check (void *);
@@ -176,7 +182,7 @@ static void hbreak_command (char *, int);
 
 static void thbreak_command (char *, int);
 
-static void do_enable_breakpoint (struct breakpoint *, enum bpdisp);
+static void enable_breakpoint_disp (struct breakpoint *, enum bpdisp);
 
 static void stop_command (char *arg, int from_tty);
 
@@ -208,8 +214,6 @@ static void update_global_location_list_nothrow (int);
 
 static int is_hardware_watchpoint (const struct breakpoint *bpt);
 
-static int is_watchpoint (const struct breakpoint *bpt);
-
 static void insert_breakpoint_locations (void);
 
 static int syscall_catchpoint_p (struct breakpoint *b);
@@ -224,11 +228,32 @@ 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)                                              \
   (s != NULL && strncmp (s, "-m", 2) == 0 && ((s)[2] == ' ' || (s)[2] == '\t'))
 
+/* The abstract base class all breakpoint_ops structures inherit
+   from.  */
+static struct breakpoint_ops base_breakpoint_ops;
+
+/* The breakpoint_ops structure to be inherited by all breakpoint_ops
+   that are implemented on top of software or hardware breakpoints
+   (user breakpoints, internal and momentary breakpoints, etc.).  */
+static struct breakpoint_ops bkpt_base_breakpoint_ops;
+
+/* Internal breakpoints class type.  */
+static struct breakpoint_ops internal_breakpoint_ops;
+
+/* Momentary breakpoints class type.  */
+static struct breakpoint_ops momentary_breakpoint_ops;
+
+/* The breakpoint_ops structure to be used in regular user created
+   breakpoints.  */
+struct breakpoint_ops bkpt_breakpoint_ops;
+
 /* A reference-counted struct command_line.  This lets multiple
    breakpoints share a single command list.  */
 struct counted_command_line
@@ -359,7 +384,7 @@ static int overlay_events_enabled;
 int target_exact_watchpoints = 0;
 
 /* Walk the following statement or block through all breakpoints.
-   ALL_BREAKPOINTS_SAFE does so even if the statment deletes the
+   ALL_BREAKPOINTS_SAFE does so even if the statement deletes the
    current breakpoint.  */
 
 #define ALL_BREAKPOINTS(B)  for (B = breakpoint_chain; B; B = B->next)
@@ -578,17 +603,26 @@ void
 set_breakpoint_condition (struct breakpoint *b, char *exp,
                          int from_tty)
 {
-  struct bp_location *loc = b->loc;
+  xfree (b->cond_string);
+  b->cond_string = NULL;
 
-  for (; loc; loc = loc->next)
+  if (is_watchpoint (b))
     {
-      xfree (loc->cond);
-      loc->cond = NULL;
+      struct watchpoint *w = (struct watchpoint *) b;
+
+      xfree (w->cond_exp);
+      w->cond_exp = NULL;
+    }
+  else
+    {
+      struct bp_location *loc;
+
+      for (loc = b->loc; loc; loc = loc->next)
+       {
+         xfree (loc->cond);
+         loc->cond = NULL;
+       }
     }
-  xfree (b->cond_string);
-  b->cond_string = NULL;
-  xfree (b->cond_exp);
-  b->cond_exp = NULL;
 
   if (*exp == 0)
     {
@@ -606,15 +640,19 @@ set_breakpoint_condition (struct breakpoint *b, char *exp,
 
       if (is_watchpoint (b))
        {
+         struct watchpoint *w = (struct watchpoint *) b;
+
          innermost_block = NULL;
          arg = exp;
-         b->cond_exp = parse_exp_1 (&arg, 0, 0);
+         w->cond_exp = parse_exp_1 (&arg, 0, 0);
          if (*arg)
            error (_("Junk at end of expression"));
-         b->cond_exp_valid_block = innermost_block;
+         w->cond_exp_valid_block = innermost_block;
        }
       else
        {
+         struct bp_location *loc;
+
          for (loc = b->loc; loc; loc = loc->next)
            {
              arg = exp;
@@ -697,15 +735,21 @@ check_no_tracepoint_commands (struct command_line *commands)
 
 /* Encapsulate tests for different types of tracepoints.  */
 
+static int
+is_tracepoint_type (enum bptype type)
+{
+  return (type == bp_tracepoint
+         || type == bp_fast_tracepoint
+         || type == bp_static_tracepoint);
+}
+
 int
 is_tracepoint (const struct breakpoint *b)
 {
-  return (b->type == bp_tracepoint
-         || b->type == bp_fast_tracepoint
-         || b->type == bp_static_tracepoint);
+  return is_tracepoint_type (b->type);
 }
-  
-/* A helper function that validsates that COMMANDS are valid for a
+
+/* A helper function that validates that COMMANDS are valid for a
    breakpoint.  This function will throw an exception if a problem is
    found.  */
 
@@ -987,7 +1031,7 @@ bp_location_has_shadow (struct bp_location *bl)
   if (!bl->inserted)
     return 0;
   if (bl->target_info.shadow_len == 0)
-    /* bp isn't valid, or doesn't shadow memory.  */
+    /* BL isn't valid, or doesn't shadow memory.  */
     return 0;
   return 1;
 }
@@ -1075,7 +1119,7 @@ breakpoint_restore_shadows (gdb_byte *buf, ULONGEST memaddr, LONGEST len)
       warning (_("reading through apparently deleted breakpoint #%d?"),
               bl->owner->number);
 
-    /* Performance optimization: any futher element can no longer affect BUF
+    /* Performance optimization: any further element can no longer affect BUF
        content.  */
 
     if (bl->address >= bp_location_placed_address_before_address_max
@@ -1138,25 +1182,24 @@ is_hardware_watchpoint (const struct breakpoint *bpt)
 /* Return true if BPT is of any watchpoint kind, hardware or
    software.  */
 
-static int
+int
 is_watchpoint (const struct breakpoint *bpt)
 {
   return (is_hardware_watchpoint (bpt)
          || bpt->type == bp_watchpoint);
 }
 
-/* Assuming that B is a watchpoint: returns true if the current thread
-   and its running state are safe to evaluate or update watchpoint B.
-   Watchpoints on local expressions need to be evaluated in the
-   context of the thread that was current when the watchpoint was
-   created, and, that thread needs to be stopped to be able to select
-   the correct frame context.  Watchpoints on global expressions can
-   be evaluated on any thread, and in any state.  It is presently left
-   to the target allowing memory accesses when threads are
-   running.  */
+/* Returns true if the current thread and its running state are safe
+   to evaluate or update watchpoint B.  Watchpoints on local
+   expressions need to be evaluated in the context of the thread that
+   was current when the watchpoint was created, and, that thread needs
+   to be stopped to be able to select the correct frame context.
+   Watchpoints on global expressions can be evaluated on any thread,
+   and in any state.  It is presently left to the target allowing
+   memory accesses when threads are running.  */
 
 static int
-watchpoint_in_thread_scope (struct breakpoint *b)
+watchpoint_in_thread_scope (struct watchpoint *b)
 {
   return (ptid_equal (b->watchpoint_thread, null_ptid)
          || (ptid_equal (inferior_ptid, b->watchpoint_thread)
@@ -1167,9 +1210,9 @@ watchpoint_in_thread_scope (struct breakpoint *b)
    associated bp_watchpoint_scope breakpoint.  */
 
 static void
-watchpoint_del_at_next_stop (struct breakpoint *b)
+watchpoint_del_at_next_stop (struct watchpoint *w)
 {
-  gdb_assert (is_watchpoint (b));
+  struct breakpoint *b = &w->base;
 
   if (b->related_breakpoint != b)
     {
@@ -1235,21 +1278,19 @@ watchpoint_del_at_next_stop (struct breakpoint *b)
    watchpoint removal from inferior.  */
 
 static void
-update_watchpoint (struct breakpoint *b, int reparse)
+update_watchpoint (struct watchpoint *b, int reparse)
 {
   int within_current_scope;
   struct frame_id saved_frame_id;
   int frame_saved;
 
-  gdb_assert (is_watchpoint (b));
-
   /* If this is a local watchpoint, we only want to check if the
      watchpoint frame is in scope if the current thread is the thread
      that was used to create the watchpoint.  */
   if (!watchpoint_in_thread_scope (b))
     return;
 
-  if (b->disposition == disp_del_at_next_stop)
+  if (b->base.disposition == disp_del_at_next_stop)
     return;
  
   frame_saved = 0;
@@ -1286,7 +1327,7 @@ update_watchpoint (struct breakpoint *b, int reparse)
   /* We don't free locations.  They are stored in the bp_location array
      and update_global_location_list will eventually delete them and
      remove breakpoints if needed.  */
-  b->loc = NULL;
+  b->base.loc = NULL;
 
   if (within_current_scope && reparse)
     {
@@ -1310,7 +1351,7 @@ update_watchpoint (struct breakpoint *b, int reparse)
       /* Note that unlike with breakpoints, the watchpoint's condition
         expression is stored in the breakpoint object, not in the
         locations (re)created below.  */
-      if (b->cond_string != NULL)
+      if (b->base.cond_string != NULL)
        {
          if (b->cond_exp != NULL)
            {
@@ -1318,7 +1359,7 @@ update_watchpoint (struct breakpoint *b, int reparse)
              b->cond_exp = NULL;
            }
 
-         s = b->cond_string;
+         s = b->base.cond_string;
          b->cond_exp = parse_exp_1 (&s, b->cond_exp_valid_block, 0);
        }
     }
@@ -1345,8 +1386,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->base))
        {
          b->val = v;
          b->val_valid = 1;
@@ -1381,13 +1424,13 @@ update_watchpoint (struct breakpoint *b, int reparse)
                  addr = value_address (v);
                  len = TYPE_LENGTH (value_type (v));
                  type = hw_write;
-                 if (b->type == bp_read_watchpoint)
+                 if (b->base.type == bp_read_watchpoint)
                    type = hw_read;
-                 else if (b->type == bp_access_watchpoint)
+                 else if (b->base.type == bp_access_watchpoint)
                    type = hw_access;
-                 
-                 loc = allocate_bp_location (b);
-                 for (tmp = &(b->loc); *tmp != NULL; tmp = &((*tmp)->next))
+
+                 loc = allocate_bp_location (&b->base);
+                 for (tmp = &(b->base.loc); *tmp != NULL; tmp = &((*tmp)->next))
                    ;
                  *tmp = loc;
                  loc->gdbarch = get_type_arch (value_type (v));
@@ -1427,35 +1470,35 @@ update_watchpoint (struct breakpoint *b, int reparse)
                 hw_watchpoint_used_count call below counts this
                 watchpoint, make sure that it is marked as a hardware
                 watchpoint.  */
-             if (b->type == bp_watchpoint)
-               b->type = bp_hardware_watchpoint;
+             if (b->base.type == bp_watchpoint)
+               b->base.type = bp_hardware_watchpoint;
 
-             i = hw_watchpoint_used_count (b->type, &other_type_used);
+             i = hw_watchpoint_used_count (b->base.type, &other_type_used);
              target_resources_ok = target_can_use_hardware_watchpoint
-                   (b->type, i, other_type_used);
+                   (b->base.type, i, other_type_used);
              if (target_resources_ok <= 0)
                {
-                 if (target_resources_ok == 0
-                     && b->type != bp_hardware_watchpoint)
+                 int sw_mode = b->base.ops->works_in_software_mode (&b->base);
+
+                 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;
+                   b->base.type = bp_watchpoint;
                }
            }
-         else if (b->type != bp_hardware_watchpoint)
+         else if (!b->base.ops->works_in_software_mode (&b->base))
            error (_("Expression cannot be implemented with "
                     "read/access watchpoint."));
          else
-           b->type = bp_watchpoint;
+           b->base.type = bp_watchpoint;
 
-         loc_type = (b->type == bp_watchpoint? bp_loc_other
+         loc_type = (b->base.type == bp_watchpoint? bp_loc_other
                      : bp_loc_hardware_watchpoint);
-         for (bl = b->loc; bl; bl = bl->next)
+         for (bl = b->base.loc; bl; bl = bl->next)
            bl->loc_type = loc_type;
        }
 
@@ -1470,13 +1513,14 @@ update_watchpoint (struct breakpoint *b, int reparse)
         above left it without any location set up.  But,
         bpstat_stop_status requires a location to be able to report
         stops, so make sure there's at least a dummy one.  */
-      if (b->type == bp_watchpoint && b->loc == NULL)
+      if (b->base.type == bp_watchpoint && b->base.loc == NULL)
        {
-         b->loc = allocate_bp_location (b);
-         b->loc->pspace = frame_pspace;
-         b->loc->address = -1;
-         b->loc->length = -1;
-         b->loc->watchpoint_type = -1;
+         struct breakpoint *base = &b->base;
+         base->loc = allocate_bp_location (base);
+         base->loc->pspace = frame_pspace;
+         base->loc->address = -1;
+         base->loc->length = -1;
+         base->loc->watchpoint_type = -1;
        }
     }
   else if (!within_current_scope)
@@ -1484,7 +1528,7 @@ update_watchpoint (struct breakpoint *b, int reparse)
       printf_filtered (_("\
 Watchpoint %d deleted because the program has left the block\n\
 in which its expression is valid.\n"),
-                      b->number);
+                      b->base.number);
       watchpoint_del_at_next_stop (b);
     }
 
@@ -1527,9 +1571,26 @@ should_be_inserted (struct bp_location *bl)
   return 1;
 }
 
+/* Same as should_be_inserted but does the check assuming
+   that the location is not duplicated.  */
+
+static int
+unduplicated_should_be_inserted (struct bp_location *bl)
+{
+  int result;
+  const int save_duplicate = bl->duplicate;
+
+  bl->duplicate = 0;
+  result = should_be_inserted (bl);
+  bl->duplicate = save_duplicate;
+  return result;
+}
+
 /* Insert a low-level "breakpoint" of some type.  BL is the breakpoint
    location.  Any error messages are printed to TMP_ERROR_STREAM; and
    DISABLED_BREAKS, and HW_BREAKPOINT_ERROR are used to report problems.
+   Returns 0 for success, 1 if the bp_location type is not supported or
+   -1 for failure.
 
    NOTE drow/2003-09-09: This routine could be broken down to an
    object-style method for each breakpoint or catchpoint type.  */
@@ -1617,12 +1678,7 @@ insert_bp_location (struct bp_location *bl,
        {
          /* No overlay handling: just set the breakpoint.  */
 
-         if (bl->loc_type == bp_loc_hardware_breakpoint)
-           val = target_insert_hw_breakpoint (bl->gdbarch,
-                                              &bl->target_info);
-         else
-           val = target_insert_breakpoint (bl->gdbarch,
-                                           &bl->target_info);
+         val = bl->owner->ops->insert_location (bl);
        }
       else
        {
@@ -1656,12 +1712,7 @@ insert_bp_location (struct bp_location *bl,
          if (section_is_mapped (bl->section))
            {
              /* Yes.  This overlay section is mapped into memory.  */
-             if (bl->loc_type == bp_loc_hardware_breakpoint)
-               val = target_insert_hw_breakpoint (bl->gdbarch,
-                                                  &bl->target_info);
-             else
-               val = target_insert_breakpoint (bl->gdbarch,
-                                               &bl->target_info);
+             val = bl->owner->ops->insert_location (bl);
            }
          else
            {
@@ -1853,7 +1904,11 @@ insert_breakpoints (void)
 
   ALL_BREAKPOINTS (bpt)
     if (is_hardware_watchpoint (bpt))
-      update_watchpoint (bpt, 0 /* don't reparse.  */);
+      {
+       struct watchpoint *w = (struct watchpoint *) bpt;
+
+       update_watchpoint (w, 0 /* don't reparse.  */);
+      }
 
   update_global_location_list (1);
 
@@ -1864,10 +1919,7 @@ insert_breakpoints (void)
     insert_breakpoint_locations ();
 }
 
-/* insert_breakpoints is used when starting or continuing the program.
-   remove_breakpoints is used when the program stops.
-   Both return zero if successful,
-   or an `errno' value if could not write the inferior.  */
+/* Used when starting or continuing the program.  */
 
 static void
 insert_breakpoint_locations (void)
@@ -1969,6 +2021,10 @@ You may have requested too many hardware breakpoints/watchpoints.\n");
   do_cleanups (cleanups);
 }
 
+/* Used when the program stops.
+   Returns zero if successful, or non-zero if there was a problem
+   removing a breakpoint location.  */
+
 int
 remove_breakpoints (void)
 {
@@ -2007,20 +2063,6 @@ remove_breakpoints_pid (int pid)
   return 0;
 }
 
-int
-remove_hw_watchpoints (void)
-{
-  struct bp_location *bl, **blp_tmp;
-  int val = 0;
-
-  ALL_BP_LOCATIONS (bl, blp_tmp)
-  {
-    if (bl->inserted && bl->loc_type == bp_loc_hardware_watchpoint)
-      val |= remove_breakpoint (bl, mark_uninserted);
-  }
-  return val;
-}
-
 int
 reattach_breakpoints (int pid)
 {
@@ -2069,7 +2111,7 @@ static int internal_breakpoint_number = -1;
 /* Set the breakpoint number of B, depending on the value of INTERNAL.
    If INTERNAL is non-zero, the breakpoint number will be populated
    from internal_breakpoint_number and that variable decremented.
-   Otherwis the breakpoint number will be populated from
+   Otherwise the breakpoint number will be populated from
    breakpoint_count and that value incremented.  Internal breakpoints
    do not set the internal var bpnum.  */
 static void
@@ -2086,7 +2128,8 @@ set_breakpoint_number (int internal, struct breakpoint *b)
 
 static struct breakpoint *
 create_internal_breakpoint (struct gdbarch *gdbarch,
-                           CORE_ADDR address, enum bptype type)
+                           CORE_ADDR address, enum bptype type,
+                           const struct breakpoint_ops *ops)
 {
   struct symtab_and_line sal;
   struct breakpoint *b;
@@ -2097,7 +2140,7 @@ create_internal_breakpoint (struct gdbarch *gdbarch,
   sal.section = find_pc_overlay (sal.pc);
   sal.pspace = current_program_space;
 
-  b = set_raw_breakpoint (gdbarch, sal, type);
+  b = set_raw_breakpoint (gdbarch, sal, type, ops);
   b->number = internal_breakpoint_number--;
   b->disposition = disp_donttouch;
 
@@ -2192,7 +2235,8 @@ create_overlay_event_breakpoint (void)
 
       addr = SYMBOL_VALUE_ADDRESS (bp_objfile_data->overlay_msym);
       b = create_internal_breakpoint (get_objfile_arch (objfile), addr,
-                                      bp_overlay_event);
+                                      bp_overlay_event,
+                                     &internal_breakpoint_ops);
       b->addr_string = xstrdup (func_name);
 
       if (overlay_debugging == ovly_auto)
@@ -2260,7 +2304,8 @@ create_longjmp_master_breakpoint (void)
            }
 
          addr = SYMBOL_VALUE_ADDRESS (bp_objfile_data->longjmp_msym[i]);
-         b = create_internal_breakpoint (gdbarch, addr, bp_longjmp_master);
+         b = create_internal_breakpoint (gdbarch, addr, bp_longjmp_master,
+                                         &internal_breakpoint_ops);
          b->addr_string = xstrdup (func_name);
          b->enable_state = bp_disabled;
        }
@@ -2315,7 +2360,8 @@ create_std_terminate_master_breakpoint (void)
 
       addr = SYMBOL_VALUE_ADDRESS (bp_objfile_data->terminate_msym);
       b = create_internal_breakpoint (get_objfile_arch (objfile), addr,
-                                      bp_std_terminate_master);
+                                      bp_std_terminate_master,
+                                     &internal_breakpoint_ops);
       b->addr_string = xstrdup (func_name);
       b->enable_state = bp_disabled;
     }
@@ -2365,7 +2411,8 @@ create_exception_master_breakpoint (void)
       addr = SYMBOL_VALUE_ADDRESS (bp_objfile_data->exception_msym);
       addr = gdbarch_convert_from_func_ptr_addr (gdbarch, addr,
                                                 &current_target);
-      b = create_internal_breakpoint (gdbarch, addr, bp_exception_master);
+      b = create_internal_breakpoint (gdbarch, addr, bp_exception_master,
+                                     &internal_breakpoint_ops);
       b->addr_string = xstrdup (func_name);
       b->enable_state = bp_disabled;
     }
@@ -2421,7 +2468,7 @@ update_breakpoints_after_exec (void)
       }
 
     /* Step-resume breakpoints are meaningless after an exec().  */
-    if (b->type == bp_step_resume)
+    if (b->type == bp_step_resume || b->type == bp_hp_step_resume)
       {
        delete_breakpoint (b);
        continue;
@@ -2460,7 +2507,7 @@ update_breakpoints_after_exec (void)
        gets 'round to deleting the "use to be a bp_finish" breakpoint.
        We really must allow finish_command to delete a bp_finish.
 
-       In the absense of a general solution for the "how do we know
+       In the absence of a general solution for the "how do we know
        it's safe to delete something others may have handles to?"
        problem, what we'll do here is just uninsert the bp_finish, and
        let finish_command delete it.
@@ -2556,11 +2603,7 @@ remove_breakpoint_1 (struct bp_location *bl, insertion_state_t is)
          || !(section_is_overlay (bl->section)))
        {
          /* No overlay handling: just remove the breakpoint.  */
-
-         if (bl->loc_type == bp_loc_hardware_breakpoint)
-           val = target_remove_hw_breakpoint (bl->gdbarch, &bl->target_info);
-         else
-           val = target_remove_breakpoint (bl->gdbarch, &bl->target_info);
+         val = bl->owner->ops->remove_location (bl);
        }
       else
        {
@@ -2588,16 +2631,13 @@ remove_breakpoint_1 (struct bp_location *bl, insertion_state_t is)
                 remove the breakpoint if the section had been
                 unmapped, but let's not rely on that being safe.  We
                 don't know what the overlay manager might do.  */
-             if (bl->loc_type == bp_loc_hardware_breakpoint)
-               val = target_remove_hw_breakpoint (bl->gdbarch,
-                                                  &bl->target_info);
 
              /* However, we should remove *software* breakpoints only
                 if the section is still mapped, or else we overwrite
                 wrong code with the saved shadow contents.  */
-             else if (section_is_mapped (bl->section))
-               val = target_remove_breakpoint (bl->gdbarch,
-                                               &bl->target_info);
+             if (bl->loc_type == bp_loc_hardware_breakpoint
+                 || section_is_mapped (bl->section))
+               val = bl->owner->ops->remove_location (bl);
              else
                val = 0;
            }
@@ -2760,19 +2800,22 @@ breakpoint_init_inferior (enum inf_context context)
       case bp_hardware_watchpoint:
       case bp_read_watchpoint:
       case bp_access_watchpoint:
+       {
+         struct watchpoint *w = (struct watchpoint *) b;
 
-       /* Likewise for watchpoints on local expressions.  */
-       if (b->exp_valid_block != NULL)
-         delete_breakpoint (b);
-       else if (context == inf_starting) 
-         {
-           /* Reset val field to force reread of starting value in
-              insert_breakpoints.  */
-           if (b->val)
-             value_free (b->val);
-           b->val = NULL;
-           b->val_valid = 0;
+         /* Likewise for watchpoints on local expressions.  */
+         if (w->exp_valid_block != NULL)
+           delete_breakpoint (b);
+         else if (context == inf_starting)
+           {
+             /* Reset val field to force reread of starting value in
+                insert_breakpoints.  */
+             if (w->val)
+               value_free (w->val);
+             w->val = NULL;
+             w->val_valid = 0;
          }
+       }
        break;
       default:
        break;
@@ -2796,7 +2839,7 @@ breakpoint_init_inferior (enum inf_context context)
    permanent breakpoint.
    - When continuing from a location with an ordinary breakpoint, we
      actually single step once before calling insert_breakpoints.
-   - When continuing from a localion with a permanent breakpoint, we
+   - When continuing from a location with a permanent breakpoint, we
      need to use the `SKIP_PERMANENT_BREAKPOINT' macro, provided by
      the target, to advance the PC past the breakpoint.  */
 
@@ -3212,6 +3255,8 @@ bpstat_do_actions_1 (bpstat *bsp)
   executing_breakpoint_commands = 1;
   old_chain = make_cleanup (cleanup_executing_breakpoints, 0);
 
+  prevent_dont_repeat ();
+
   /* This pointer will iterate over the list of bpstat's.  */
   bs = *bsp;
 
@@ -3312,218 +3357,6 @@ watchpoint_value_print (struct value *val, struct ui_file *stream)
     }
 }
 
-/* This is the normal print function for a bpstat.  In the future,
-   much of this logic could (should?) be moved to bpstat_stop_status,
-   by having it set different print_it values.
-
-   Current scheme: When we stop, bpstat_print() is called.  It loops
-   through the bpstat list of things causing this stop, calling the
-   print_bp_stop_message function on each one.  The behavior of the
-   print_bp_stop_message function depends on the print_it field of
-   bpstat.  If such field so indicates, call this function here.
-
-   Return values from this routine (ultimately used by bpstat_print()
-   and normal_stop() to decide what to do): 
-   PRINT_NOTHING: Means we already printed all we needed to print,
-   don't print anything else.
-   PRINT_SRC_ONLY: Means we printed something, and we do *not* desire
-   that something to be followed by a location.
-   PRINT_SCR_AND_LOC: Means we printed something, and we *do* desire
-   that something to be followed by a location.
-   PRINT_UNKNOWN: Means we printed nothing or we need to do some more
-   analysis.  */
-
-static enum print_stop_action
-print_it_typical (bpstat bs)
-{
-  struct cleanup *old_chain;
-  struct breakpoint *b;
-  const struct bp_location *bl;
-  struct ui_stream *stb;
-  int bp_temp = 0;
-  enum print_stop_action result;
-
-  gdb_assert (bs->bp_location_at != NULL);
-
-  bl = bs->bp_location_at;
-  b = bs->breakpoint_at;
-
-  stb = ui_out_stream_new (uiout);
-  old_chain = make_cleanup_ui_out_stream_delete (stb);
-
-  switch (b->type)
-    {
-    case bp_breakpoint:
-    case bp_hardware_breakpoint:
-      bp_temp = b->disposition == disp_del;
-      if (bl->address != bl->requested_address)
-       breakpoint_adjustment_warning (bl->requested_address,
-                                      bl->address,
-                                      b->number, 1);
-      annotate_breakpoint (b->number);
-      if (bp_temp) 
-       ui_out_text (uiout, "\nTemporary breakpoint ");
-      else
-       ui_out_text (uiout, "\nBreakpoint ");
-      if (ui_out_is_mi_like_p (uiout))
-       {
-         ui_out_field_string (uiout, "reason", 
-                         async_reason_lookup (EXEC_ASYNC_BREAKPOINT_HIT));
-         ui_out_field_string (uiout, "disp", bpdisp_text (b->disposition));
-       }
-      ui_out_field_int (uiout, "bkptno", b->number);
-      ui_out_text (uiout, ", ");
-      result = PRINT_SRC_AND_LOC;
-      break;
-
-    case bp_shlib_event:
-      /* Did we stop because the user set the stop_on_solib_events
-        variable?  (If so, we report this as a generic, "Stopped due
-        to shlib event" message.) */
-      printf_filtered (_("Stopped due to shared library event\n"));
-      result = PRINT_NOTHING;
-      break;
-
-    case bp_thread_event:
-      /* Not sure how we will get here.
-        GDB should not stop for these breakpoints.  */
-      printf_filtered (_("Thread Event Breakpoint: gdb should not stop!\n"));
-      result = PRINT_NOTHING;
-      break;
-
-    case bp_overlay_event:
-      /* By analogy with the thread event, GDB should not stop for these.  */
-      printf_filtered (_("Overlay Event Breakpoint: gdb should not stop!\n"));
-      result = PRINT_NOTHING;
-      break;
-
-    case bp_longjmp_master:
-      /* These should never be enabled.  */
-      printf_filtered (_("Longjmp Master Breakpoint: gdb should not stop!\n"));
-      result = PRINT_NOTHING;
-      break;
-
-    case bp_std_terminate_master:
-      /* These should never be enabled.  */
-      printf_filtered (_("std::terminate Master Breakpoint: "
-                        "gdb should not stop!\n"));
-      result = PRINT_NOTHING;
-      break;
-
-    case bp_exception_master:
-      /* These should never be enabled.  */
-      printf_filtered (_("Exception Master Breakpoint: "
-                        "gdb should not stop!\n"));
-      result = PRINT_NOTHING;
-      break;
-
-    case bp_watchpoint:
-    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));
-      mention (b);
-      make_cleanup_ui_out_tuple_begin_end (uiout, "value");
-      ui_out_text (uiout, "\nOld value = ");
-      watchpoint_value_print (bs->old_val, stb->stream);
-      ui_out_field_stream (uiout, "old", stb);
-      ui_out_text (uiout, "\nNew value = ");
-      watchpoint_value_print (b->val, stb->stream);
-      ui_out_field_stream (uiout, "new", stb);
-      ui_out_text (uiout, "\n");
-      /* More than one watchpoint may have been triggered.  */
-      result = PRINT_UNKNOWN;
-      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));
-      mention (b);
-      make_cleanup_ui_out_tuple_begin_end (uiout, "value");
-      ui_out_text (uiout, "\nValue = ");
-      watchpoint_value_print (b->val, stb->stream);
-      ui_out_field_stream (uiout, "value", stb);
-      ui_out_text (uiout, "\n");
-      result = PRINT_UNKNOWN;
-      break;
-
-    case bp_access_watchpoint:
-      if (bs->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));
-         mention (b);
-         make_cleanup_ui_out_tuple_begin_end (uiout, "value");
-         ui_out_text (uiout, "\nOld value = ");
-         watchpoint_value_print (bs->old_val, stb->stream);
-         ui_out_field_stream (uiout, "old", stb);
-         ui_out_text (uiout, "\nNew value = ");
-       }
-      else 
-       {
-         mention (b);
-         if (ui_out_is_mi_like_p (uiout))
-           ui_out_field_string
-             (uiout, "reason",
-              async_reason_lookup (EXEC_ASYNC_ACCESS_WATCHPOINT_TRIGGER));
-         make_cleanup_ui_out_tuple_begin_end (uiout, "value");
-         ui_out_text (uiout, "\nValue = ");
-       }
-      watchpoint_value_print (b->val, stb->stream);
-      ui_out_field_stream (uiout, "new", stb);
-      ui_out_text (uiout, "\n");
-      result = PRINT_UNKNOWN;
-      break;
-
-    /* Fall through, we don't deal with these types of breakpoints
-       here.  */
-
-    case bp_finish:
-      if (ui_out_is_mi_like_p (uiout))
-       ui_out_field_string
-         (uiout, "reason",
-          async_reason_lookup (EXEC_ASYNC_FUNCTION_FINISHED));
-      result = PRINT_UNKNOWN;
-      break;
-
-    case bp_until:
-      if (ui_out_is_mi_like_p (uiout))
-       ui_out_field_string
-         (uiout, "reason",
-          async_reason_lookup (EXEC_ASYNC_LOCATION_REACHED));
-      result = PRINT_UNKNOWN;
-      break;
-
-    case bp_none:
-    case bp_longjmp:
-    case bp_longjmp_resume:
-    case bp_exception:
-    case bp_exception_resume:
-    case bp_step_resume:
-    case bp_watchpoint_scope:
-    case bp_call_dummy:
-    case bp_std_terminate:
-    case bp_tracepoint:
-    case bp_fast_tracepoint:
-    case bp_jit_event:
-    case bp_gnu_ifunc_resolver:
-    case bp_gnu_ifunc_resolver_return:
-    default:
-      result = PRINT_UNKNOWN;
-      break;
-    }
-
-  do_cleanups (old_chain);
-  return result;
-}
-
 /* Generic routine for printing messages indicating why we
    stopped.  The behavior of this function depends on the value
    'print_it' in the bpstat structure.  Under some circumstances we
@@ -3555,14 +3388,10 @@ print_bp_stop_message (bpstat bs)
        if (b == NULL)
          return PRINT_UNKNOWN;
 
-       /* Normal case.  Call the breakpoint's print_it method, or
-          print_it_typical.  */
-       if (b->ops != NULL && b->ops->print_it != NULL)
-         return b->ops->print_it (b);
-       else
-         return print_it_typical (bs);
+       /* Normal case.  Call the breakpoint's print_it method.  */
+       return b->ops->print_it (bs);
       }
-       break;
+      break;
 
     default:
       internal_error (__FILE__, __LINE__,
@@ -3667,7 +3496,11 @@ watchpoints_triggered (struct target_waitstatus *ws)
         as not triggered.  */
       ALL_BREAKPOINTS (b)
        if (is_hardware_watchpoint (b))
-         b->watchpoint_triggered = watch_triggered_no;
+         {
+           struct watchpoint *w = (struct watchpoint *) b;
+
+           w->watchpoint_triggered = watch_triggered_no;
+         }
 
       return 0;
     }
@@ -3678,7 +3511,11 @@ watchpoints_triggered (struct target_waitstatus *ws)
         Mark all watchpoints as unknown.  */
       ALL_BREAKPOINTS (b)
        if (is_hardware_watchpoint (b))
-         b->watchpoint_triggered = watch_triggered_unknown;
+         {
+           struct watchpoint *w = (struct watchpoint *) b;
+
+           w->watchpoint_triggered = watch_triggered_unknown;
+         }
 
       return stopped_by_watchpoint;
     }
@@ -3690,19 +3527,32 @@ watchpoints_triggered (struct target_waitstatus *ws)
   ALL_BREAKPOINTS (b)
     if (is_hardware_watchpoint (b))
       {
+       struct watchpoint *w = (struct watchpoint *) b;
        struct bp_location *loc;
 
-       b->watchpoint_triggered = watch_triggered_no;
+       w->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 (b))
+             {
+               CORE_ADDR newaddr = addr & w->hw_wp_mask;
+               CORE_ADDR start = loc->address & w->hw_wp_mask;
+
+               if (newaddr == start)
+                 {
+                   w->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))
+             {
+               w->watchpoint_triggered = watch_triggered_yes;
+               break;
+             }
+         }
       }
 
   return 1;
@@ -3732,15 +3582,13 @@ static int
 watchpoint_check (void *p)
 {
   bpstat bs = (bpstat) p;
-  struct breakpoint *b;
+  struct watchpoint *b;
   struct frame_info *fr;
   int within_current_scope;
 
   /* BS is built from an existing struct breakpoint.  */
   gdb_assert (bs->breakpoint_at != NULL);
-  b = bs->breakpoint_at;
-
-  gdb_assert (is_watchpoint (b));
+  b = (struct watchpoint *) bs->breakpoint_at;
 
   /* If this is a local watchpoint, we only want to check if the
      watchpoint frame is in scope if the current thread is the thread
@@ -3799,9 +3647,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->base))
+       /* 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
@@ -3830,6 +3685,8 @@ watchpoint_check (void *p)
     }
   else
     {
+      struct ui_out *uiout = current_uiout;
+
       /* This seems like the only logical thing to do because
          if we temporarily ignored the watchpoint, then when
          we reenter the block in which it is valid it contains
@@ -3838,19 +3695,22 @@ watchpoint_check (void *p)
          So we can't even detect the first assignment to it and
          watch after that (since the garbage may or may not equal
          the first value assigned).  */
-      /* We print all the stop information in print_it_typical(), but
-        in this case, by the time we call print_it_typical() this bp
-        will be deleted already.  So we have no choice but print the
-        information here.  */
+      /* We print all the stop information in
+        breakpoint_ops->print_it, but in this case, by the time we
+        call breakpoint_ops->print_it this bp will be deleted
+        already.  So we have no choice but print the information
+        here.  */
       if (ui_out_is_mi_like_p (uiout))
        ui_out_field_string
          (uiout, "reason", async_reason_lookup (EXEC_ASYNC_WATCHPOINT_SCOPE));
       ui_out_text (uiout, "\nWatchpoint ");
-      ui_out_field_int (uiout, "wpnum", b->number);
+      ui_out_field_int (uiout, "wpnum", b->base.number);
       ui_out_text (uiout,
                   " deleted because the program has left the block in\n\
 which its expression is valid.\n");     
 
+      /* Make sure the watchpoint's commands aren't executed.  */
+      decref_counted_command_line (&b->base.commands);
       watchpoint_del_at_next_stop (b);
 
       return WP_DELETED;
@@ -3858,82 +3718,40 @@ which its expression is valid.\n");
 }
 
 /* Return true if it looks like target has stopped due to hitting
-   breakpoint location BL.  This function does not check if we
-   should stop, only if BL explains the stop.   */
+   breakpoint location BL.  This function does not check if we should
+   stop, only if BL explains the stop.  */
+
 static int
 bpstat_check_location (const struct bp_location *bl,
                       struct address_space *aspace, CORE_ADDR bp_addr)
 {
   struct breakpoint *b = bl->owner;
 
-  /* BL is from existing struct breakpoint.  */
+  /* BL is from an existing breakpoint.  */
   gdb_assert (b != NULL);
 
-  if (b->ops && b->ops->breakpoint_hit)
-    return b->ops->breakpoint_hit (bl, aspace, bp_addr);
-
-  /* By definition, the inferior does not report stops at
-     tracepoints.  */
-  if (is_tracepoint (b))
-    return 0;
-
-  if (!is_watchpoint (b)
-      && b->type != bp_hardware_breakpoint
-      && b->type != bp_catchpoint)     /* a non-watchpoint bp */
-    {
-      if (!breakpoint_address_match (bl->pspace->aspace, bl->address,
-                                    aspace, bp_addr))
-       return 0;
-      if (overlay_debugging            /* unmapped overlay section */
-         && section_is_overlay (bl->section)
-         && !section_is_mapped (bl->section))
-       return 0;
-    }
-
-  /* Continuable hardware watchpoints are treated as non-existent if the
-     reason we stopped wasn't a hardware watchpoint (we didn't stop on
-     some data address).  Otherwise gdb won't stop on a break instruction
-     in the code (not from a breakpoint) when a hardware watchpoint has
-     been defined.  Also skip watchpoints which we know did not trigger
-     (did not match the data address).  */
-
-  if (is_hardware_watchpoint (b)
-      && b->watchpoint_triggered == watch_triggered_no)
-    return 0;
-
-  if (b->type == bp_hardware_breakpoint)
-    {
-      if (bl->address != bp_addr)
-       return 0;
-      if (overlay_debugging            /* unmapped overlay section */
-         && section_is_overlay (bl->section)
-         && !section_is_mapped (bl->section))
-       return 0;
-    }
-
-  return 1;
+  return b->ops->breakpoint_hit (bl, aspace, bp_addr);
 }
 
-/* If BS refers to a watchpoint, determine if the watched values
-   has actually changed, and we should stop.  If not, set BS->stop
-   to 0.  */
+/* Determine if the watched values have actually changed, and we
+   should stop.  If not, set BS->stop to 0.  */
+
 static void
 bpstat_check_watchpoint (bpstat bs)
 {
   const struct bp_location *bl;
-  struct breakpoint *b;
+  struct watchpoint *b;
 
   /* BS is built for existing struct breakpoint.  */
   bl = bs->bp_location_at;
   gdb_assert (bl != NULL);
-  b = bs->breakpoint_at;
+  b = (struct watchpoint *) bs->breakpoint_at;
   gdb_assert (b != NULL);
 
-  if (is_watchpoint (b))
     {
       int must_check_value = 0;
       
-      if (b->type == bp_watchpoint)
+      if (b->base.type == bp_watchpoint)
        /* For a software watchpoint, we must always check the
           watched value.  */
        must_check_value = 1;
@@ -3943,18 +3761,18 @@ bpstat_check_watchpoint (bpstat bs)
           this watchpoint.  */
        must_check_value = 1;
       else if (b->watchpoint_triggered == watch_triggered_unknown
-              && b->type == bp_hardware_watchpoint)
+              && b->base.type == bp_hardware_watchpoint)
        /* We were stopped by a hardware watchpoint, but the target could
           not report the data address.  We must check the watchpoint's
           value.  Access and read watchpoints are out of luck; without
           a data address, we can't figure it out.  */
        must_check_value = 1;
-      
+
       if (must_check_value)
        {
          char *message
            = xstrprintf ("Error evaluating expression for watchpoint %d\n",
-                         b->number);
+                         b->base.number);
          struct cleanup *cleanups = make_cleanup (xfree, message);
          int e = catch_errors (watchpoint_check, bs, message,
                                RETURN_MASK_ALL);
@@ -3971,7 +3789,7 @@ bpstat_check_watchpoint (bpstat bs)
              bs->stop = 0;
              break;
            case WP_VALUE_CHANGED:
-             if (b->type == bp_read_watchpoint)
+             if (b->base.type == bp_read_watchpoint)
                {
                  /* There are two cases to consider here:
 
@@ -4014,13 +3832,18 @@ bpstat_check_watchpoint (bpstat bs)
                      struct breakpoint *other_b;
 
                      ALL_BREAKPOINTS (other_b)
-                       if ((other_b->type == bp_hardware_watchpoint
-                            || other_b->type == bp_access_watchpoint)
-                           && (other_b->watchpoint_triggered
-                               == watch_triggered_yes))
+                       if (other_b->type == bp_hardware_watchpoint
+                           || other_b->type == bp_access_watchpoint)
                          {
-                           other_write_watchpoint = 1;
-                           break;
+                           struct watchpoint *other_w =
+                             (struct watchpoint *) other_b;
+
+                           if (other_w->watchpoint_triggered
+                               == watch_triggered_yes)
+                             {
+                               other_write_watchpoint = 1;
+                               break;
+                             }
                          }
                    }
 
@@ -4037,8 +3860,8 @@ bpstat_check_watchpoint (bpstat bs)
                }
              break;
            case WP_VALUE_NOT_CHANGED:
-             if (b->type == bp_hardware_watchpoint
-                 || b->type == bp_watchpoint)
+             if (b->base.type == bp_hardware_watchpoint
+                 || b->base.type == bp_watchpoint)
                {
                  /* Don't stop: write watchpoints shouldn't fire if
                     the value hasn't changed.  */
@@ -4051,7 +3874,7 @@ bpstat_check_watchpoint (bpstat bs)
              /* Can't happen.  */
            case 0:
              /* Error from catch_errors.  */
-             printf_filtered (_("Watchpoint %d deleted.\n"), b->number);
+             printf_filtered (_("Watchpoint %d deleted.\n"), b->base.number);
              watchpoint_del_at_next_stop (b);
              /* We've already printed what needs to be printed.  */
              bs->print_it = print_it_done;
@@ -4102,13 +3925,18 @@ bpstat_check_breakpoint_conditions (bpstat bs, ptid_t ptid)
        bs->stop = gdbpy_should_stop (b->py_bp_object);
 
       if (is_watchpoint (b))
-       cond = b->cond_exp;
+       {
+         struct watchpoint *w = (struct watchpoint *) b;
+
+         cond = w->cond_exp;
+       }
       else
        cond = bl->cond;
 
       if (cond && b->disposition != disp_del_at_next_stop)
        {
          int within_current_scope = 1;
+         struct watchpoint * w;
 
          /* We use value_mark and value_free_to_mark because it could
             be a long time before we return to the command level and
@@ -4117,13 +3945,18 @@ bpstat_check_breakpoint_conditions (bpstat bs, ptid_t ptid)
             function call.  */
          struct value *mark = value_mark ();
 
+         if (is_watchpoint (b))
+           w = (struct watchpoint *) b;
+         else
+           w = NULL;
+
          /* Need to select the frame, with all that implies so that
             the conditions will have the right context.  Because we
             use the frame, we will not see an inlined function's
             variables when we arrive at a breakpoint at the start
             of the inlined function; the current frame will be the
             call site.  */
-         if (!is_watchpoint (b) || b->cond_exp_valid_block == NULL)
+         if (w == NULL || w->cond_exp_valid_block == NULL)
            select_frame (get_current_frame ());
          else
            {
@@ -4143,7 +3976,7 @@ bpstat_check_breakpoint_conditions (bpstat bs, ptid_t ptid)
                 the innermost frame that's executing where it makes
                 sense to evaluate the condition.  It seems
                 intuitive.  */
-             frame = block_innermost_frame (b->cond_exp_valid_block);
+             frame = block_innermost_frame (w->cond_exp_valid_block);
              if (frame != NULL)
                select_frame (frame);
              else
@@ -4265,7 +4098,11 @@ bpstat_stop_status (struct address_space *aspace,
             out-of-scope event.  We'll get to the watchpoint next
             iteration.  */
          if (b->type == bp_watchpoint_scope && b->related_breakpoint != b)
-           b->related_breakpoint->watchpoint_triggered = watch_triggered_yes;
+           {
+             struct watchpoint *w = (struct watchpoint *) b->related_breakpoint;
+
+             w->watchpoint_triggered = watch_triggered_yes;
+           }
        }
     }
 
@@ -4292,20 +4129,11 @@ bpstat_stop_status (struct address_space *aspace,
       if (!bs->stop)
        continue;
 
-      bpstat_check_watchpoint (bs);
-      if (!bs->stop)
-       continue;
-
       b = bs->breakpoint_at;
-
-         if (b->type == bp_thread_event || b->type == bp_overlay_event
-             || b->type == bp_longjmp_master
-             || b->type == bp_std_terminate_master
-             || b->type == bp_exception_master)
-           /* We do not stop for these.  */
-           bs->stop = 0;
-         else
-           bpstat_check_breakpoint_conditions (bs, ptid);
+      b->ops->check_status (bs);
+      if (bs->stop)
+       {
+         bpstat_check_breakpoint_conditions (bs, ptid);
 
          if (bs->stop)
            {
@@ -4335,9 +4163,10 @@ bpstat_stop_status (struct address_space *aspace,
                }
            }
 
-         /* Print nothing for this entry if we dont stop or dont print.  */
+         /* Print nothing for this entry if we don't stop or don't print.  */
          if (bs->stop == 0 || bs->print == 0)
            bs->print_it = print_it_noop;
+       }
     }
 
   /* If we aren't stopping, the value of some hardware watchpoint may
@@ -4351,7 +4180,9 @@ bpstat_stop_status (struct address_space *aspace,
          && bs->breakpoint_at
          && is_hardware_watchpoint (bs->breakpoint_at))
        {
-         update_watchpoint (bs->breakpoint_at, 0 /* don't reparse.  */);
+         struct watchpoint *w = (struct watchpoint *) bs->breakpoint_at;
+
+         update_watchpoint (w, 0 /* don't reparse.  */);
          need_remove_insert = 1;
        }
 
@@ -4413,8 +4244,6 @@ bpstat_what (bpstat bs_head)
             breakpoint which has since been deleted.  */
          bptype = bp_none;
        }
-      else if (bs->breakpoint_at == NULL)
-       bptype = bp_none;
       else
        bptype = bs->breakpoint_at->type;
 
@@ -4472,6 +4301,15 @@ bpstat_what (bpstat bs_head)
              this_action = BPSTAT_WHAT_SINGLE;
            }
          break;
+       case bp_hp_step_resume:
+         if (bs->stop)
+           this_action = BPSTAT_WHAT_HP_STEP_RESUME;
+         else
+           {
+             /* It is for the wrong frame.  */
+             this_action = BPSTAT_WHAT_SINGLE;
+           }
+         break;
        case bp_watchpoint_scope:
        case bp_thread_event:
        case bp_overlay_event:
@@ -4662,6 +4500,7 @@ static void
 print_breakpoint_location (struct breakpoint *b,
                           struct bp_location *loc)
 {
+  struct ui_out *uiout = current_uiout;
   struct cleanup *old_chain = save_current_program_space ();
 
   if (loc != NULL && loc->shlib_disabled)
@@ -4740,6 +4579,7 @@ bptype_string (enum bptype type)
     {bp_exception, "exception"},
     {bp_exception_resume, "exception resume"},
     {bp_step_resume, "step resume"},
+    {bp_hp_step_resume, "high-priority step resume"},
     {bp_watchpoint_scope, "watchpoint scope"},
     {bp_call_dummy, "call dummy"},
     {bp_std_terminate, "std::terminate"},
@@ -4779,6 +4619,7 @@ print_one_breakpoint_location (struct breakpoint *b,
   struct command_line *l;
   static char bpenables[] = "nynny";
 
+  struct ui_out *uiout = current_uiout;
   int header_of_multiple = 0;
   int part_of_multiple = (loc != NULL);
   struct value_print_options opts;
@@ -4857,13 +4698,17 @@ print_one_breakpoint_location (struct breakpoint *b,
       case bp_hardware_watchpoint:
       case bp_read_watchpoint:
       case bp_access_watchpoint:
-       /* Field 4, the address, is omitted (which makes the columns
-          not line up too nicely with the headers, but the effect
-          is relatively readable).  */
-       if (opts.addressprint)
-         ui_out_field_skip (uiout, "addr");
-       annotate_field (5);
-       ui_out_field_string (uiout, "what", b->exp_string);
+       {
+         struct watchpoint *w = (struct watchpoint *) b;
+
+         /* Field 4, the address, is omitted (which makes the columns
+            not line up too nicely with the headers, but the effect
+            is relatively readable).  */
+         if (opts.addressprint)
+           ui_out_field_skip (uiout, "addr");
+         annotate_field (5);
+         ui_out_field_string (uiout, "what", w->exp_string);
+       }
        break;
 
       case bp_breakpoint:
@@ -4875,6 +4720,7 @@ print_one_breakpoint_location (struct breakpoint *b,
       case bp_exception:
       case bp_exception_resume:
       case bp_step_resume:
+      case bp_hp_step_resume:
       case bp_watchpoint_scope:
       case bp_call_dummy:
       case bp_std_terminate:
@@ -4959,35 +4805,22 @@ print_one_breakpoint_location (struct breakpoint *b,
 
   ui_out_text (uiout, "\n");
 
-  if (!part_of_multiple && b->ops && b->ops->print_one_detail)
+  if (!part_of_multiple)
     b->ops->print_one_detail (b, uiout);
 
-  if (!part_of_multiple && b->static_trace_marker_id)
-    {
-      gdb_assert (b->type == bp_static_tracepoint);
-
-      ui_out_text (uiout, "\tmarker id is ");
-      ui_out_field_string (uiout, "static-tracepoint-marker-string-id",
-                          b->static_trace_marker_id);
-      ui_out_text (uiout, "\n");
-    }
-
   if (part_of_multiple && frame_id_p (b->frame_id))
     {
       annotate_field (6);
       ui_out_text (uiout, "\tstop only in stack frame at ");
-      /* FIXME: cagney/2002-12-01: Shouldn't be poeking around inside
+      /* FIXME: cagney/2002-12-01: Shouldn't be poking around inside
          the frame ID.  */
       ui_out_field_core_addr (uiout, "frame",
                              b->gdbarch, b->frame_id.stack_addr);
       ui_out_text (uiout, "\n");
     }
   
-  if (!part_of_multiple && b->cond_string && !ada_exception_catchpoint_p (b))
+  if (!part_of_multiple && b->cond_string)
     {
-      /* We do not print the condition for Ada exception catchpoints
-         because the condition is an internal implementation detail
-         that we do not want to expose to the user.  */
       annotate_field (7);
       if (is_tracepoint (b))
        ui_out_text (uiout, "\ttrace only if ");
@@ -5045,20 +4878,29 @@ print_one_breakpoint_location (struct breakpoint *b,
       do_cleanups (script_chain);
     }
 
-  if (!part_of_multiple && b->pass_count)
+  if (is_tracepoint (b))
     {
-      annotate_field (10);
-      ui_out_text (uiout, "\tpass count ");
-      ui_out_field_int (uiout, "pass", b->pass_count);
-      ui_out_text (uiout, " \n");
+      struct tracepoint *t = (struct tracepoint *) b;
+
+      if (!part_of_multiple && t->pass_count)
+       {
+         annotate_field (10);
+         ui_out_text (uiout, "\tpass count ");
+         ui_out_field_int (uiout, "pass", t->pass_count);
+         ui_out_text (uiout, " \n");
+       }
     }
 
   if (ui_out_is_mi_like_p (uiout) && !part_of_multiple)
     {
-      if (b->addr_string)
+      if (is_watchpoint (b))
+       {
+         struct watchpoint *w = (struct watchpoint *) b;
+
+         ui_out_field_string (uiout, "original-location", w->exp_string);
+       }
+      else if (b->addr_string)
        ui_out_field_string (uiout, "original-location", b->addr_string);
-      else if (b->exp_string)
-       ui_out_field_string (uiout, "original-location", b->exp_string);
     }
 }
 
@@ -5068,6 +4910,7 @@ print_one_breakpoint (struct breakpoint *b,
                      int allflag)
 {
   struct cleanup *bkpt_chain;
+  struct ui_out *uiout = current_uiout;
 
   bkpt_chain = make_cleanup_ui_out_tuple_begin_end (uiout, "bkpt");
 
@@ -5193,6 +5036,7 @@ breakpoint_1 (char *args, int allflag,
   struct value_print_options opts;
   int print_address_bits = 0;
   int print_type_col_width = 14;
+  struct ui_out *uiout = current_uiout;
 
   get_user_print_options (&opts);
 
@@ -5339,6 +5183,8 @@ breakpoint_1 (char *args, int allflag,
 static void
 default_collect_info (void)
 {
+  struct ui_out *uiout = current_uiout;
+
   /* If it has no value (which is frequently the case), say nothing; a
      message like "No default-collect." gets in user's face when it's
      not wanted.  */
@@ -5364,6 +5210,7 @@ static void
 watchpoints_info (char *args, int from_tty)
 {
   int num_printed = breakpoint_1 (args, 0, is_watchpoint);
+  struct ui_out *uiout = current_uiout;
 
   if (num_printed == 0)
     {
@@ -5490,9 +5337,12 @@ static int
 watchpoint_locations_match (struct bp_location *loc1, 
                            struct bp_location *loc2)
 {
-  /* Both of them must not be in moribund_locations.  */
-  gdb_assert (loc1->owner != NULL);
-  gdb_assert (loc2->owner != NULL);
+  struct watchpoint *w1 = (struct watchpoint *) loc1->owner;
+  struct watchpoint *w2 = (struct watchpoint *) loc2->owner;
+
+  /* Both of them must exist.  */
+  gdb_assert (w1 != NULL);
+  gdb_assert (w2 != NULL);
 
   /* If the target can evaluate the condition expression in hardware,
      then we we need to insert both watchpoints even if they are at
@@ -5500,16 +5350,16 @@ watchpoint_locations_match (struct bp_location *loc1,
      the condition of whichever watchpoint was inserted evaluates to
      true, not giving a chance for GDB to check the condition of the
      other watchpoint.  */
-  if ((loc1->owner->cond_exp
+  if ((w1->cond_exp
        && target_can_accel_watchpoint_condition (loc1->address, 
                                                 loc1->length,
                                                 loc1->watchpoint_type,
-                                                loc1->owner->cond_exp))
-      || (loc2->owner->cond_exp
+                                                w1->cond_exp))
+      || (w2->cond_exp
          && target_can_accel_watchpoint_condition (loc2->address, 
                                                    loc2->length,
                                                    loc2->watchpoint_type,
-                                                   loc2->owner->cond_exp)))
+                                                   w2->cond_exp)))
     return 0;
 
   /* Note that this checks the owner's type, not the location's.  In
@@ -5659,22 +5509,21 @@ adjust_breakpoint_address (struct gdbarch *gdbarch,
     }
 }
 
-/* Allocate a struct bp_location.  */
-
-static struct bp_location *
-allocate_bp_location (struct breakpoint *bpt)
+void
+init_bp_location (struct bp_location *loc, const struct bp_location_ops *ops,
+                 struct breakpoint *owner)
 {
-  struct bp_location *loc;
-
-  loc = xmalloc (sizeof (struct bp_location));
   memset (loc, 0, sizeof (*loc));
 
-  loc->owner = bpt;
+  gdb_assert (ops != NULL);
+
+  loc->ops = ops;
+  loc->owner = owner;
   loc->cond = NULL;
   loc->shlib_disabled = 0;
   loc->enabled = 1;
 
-  switch (bpt->type)
+  switch (owner->type)
     {
     case bp_breakpoint:
     case bp_until:
@@ -5684,6 +5533,7 @@ allocate_bp_location (struct breakpoint *bpt)
     case bp_exception:
     case bp_exception_resume:
     case bp_step_resume:
+    case bp_hp_step_resume:
     case bp_watchpoint_scope:
     case bp_call_dummy:
     case bp_std_terminate:
@@ -5718,18 +5568,20 @@ allocate_bp_location (struct breakpoint *bpt)
     }
 
   loc->refc = 1;
-  return loc;
+}
+
+/* Allocate a struct bp_location.  */
+
+static struct bp_location *
+allocate_bp_location (struct breakpoint *bpt)
+{
+  return bpt->ops->allocate_location (bpt);
 }
 
 static void
 free_bp_location (struct bp_location *loc)
 {
-  if (loc->cond)
-    xfree (loc->cond);
-
-  if (loc->function_name)
-    xfree (loc->function_name);
-
+  loc->ops->dtor (loc);
   xfree (loc);
 }
 
@@ -5754,20 +5606,40 @@ decref_bp_location (struct bp_location **blp)
   *blp = NULL;
 }
 
-/* Helper to set_raw_breakpoint below.  Creates a breakpoint that has
-   type BPTYPE and has no locations as yet.  */
-/* This function is used in gdbtk sources and thus can not be made
-   static.  */
+/* Add breakpoint B at the end of the global breakpoint chain.  */
 
-static struct breakpoint *
-set_raw_breakpoint_without_location (struct gdbarch *gdbarch,
-                                    enum bptype bptype)
+static void
+add_to_breakpoint_chain (struct breakpoint *b)
 {
-  struct breakpoint *b, *b1;
+  struct breakpoint *b1;
+
+  /* Add this breakpoint to the end of the chain so that a list of
+     breakpoints will come out in order of increasing numbers.  */
+
+  b1 = breakpoint_chain;
+  if (b1 == 0)
+    breakpoint_chain = b;
+  else
+    {
+      while (b1->next)
+       b1 = b1->next;
+      b1->next = b;
+    }
+}
 
-  b = (struct breakpoint *) xmalloc (sizeof (struct breakpoint));
+/* Initializes breakpoint B with type BPTYPE and no locations yet.  */
+
+static void
+init_raw_breakpoint_without_location (struct breakpoint *b,
+                                     struct gdbarch *gdbarch,
+                                     enum bptype bptype,
+                                     const struct breakpoint_ops *ops)
+{
   memset (b, 0, sizeof (*b));
 
+  gdb_assert (ops != NULL);
+
+  b->ops = ops;
   b->type = bptype;
   b->gdbarch = gdbarch;
   b->language = current_language->la_language;
@@ -5779,26 +5651,23 @@ set_raw_breakpoint_without_location (struct gdbarch *gdbarch,
   b->ignore_count = 0;
   b->commands = NULL;
   b->frame_id = null_frame_id;
-  b->forked_inferior_pid = null_ptid;
-  b->exec_pathname = NULL;
-  b->syscalls_to_be_caught = NULL;
-  b->ops = NULL;
   b->condition_not_parsed = 0;
   b->py_bp_object = NULL;
   b->related_breakpoint = b;
+}
 
-  /* Add this breakpoint to the end of the chain so that a list of
-     breakpoints will come out in order of increasing numbers.  */
+/* Helper to set_raw_breakpoint below.  Creates a breakpoint
+   that has type BPTYPE and has no locations as yet.  */
 
-  b1 = breakpoint_chain;
-  if (b1 == 0)
-    breakpoint_chain = b;
-  else
-    {
-      while (b1->next)
-       b1 = b1->next;
-      b1->next = b;
-    }
+static struct breakpoint *
+set_raw_breakpoint_without_location (struct gdbarch *gdbarch,
+                                    enum bptype bptype,
+                                    const struct breakpoint_ops *ops)
+{
+  struct breakpoint *b = XNEW (struct breakpoint);
+
+  init_raw_breakpoint_without_location (b, gdbarch, bptype, ops);
+  add_to_breakpoint_chain (b);
   return b;
 }
 
@@ -5859,30 +5728,24 @@ get_sal_arch (struct symtab_and_line sal)
   return NULL;
 }
 
-/* set_raw_breakpoint is a low level routine for allocating and
-   partially initializing a breakpoint of type BPTYPE.  The newly
-   created breakpoint's address, section, source file name, and line
-   number are provided by SAL.  The newly created and partially
-   initialized breakpoint is added to the breakpoint chain and
-   is also returned as the value of this function.
+/* Low level routine for partially initializing a breakpoint of type
+   BPTYPE.  The newly created breakpoint's address, section, source
+   file name, and line number are provided by SAL.
 
    It is expected that the caller will complete the initialization of
    the newly created breakpoint struct as well as output any status
-   information regarding the creation of a new breakpoint.  In
-   particular, set_raw_breakpoint does NOT set the breakpoint
-   number!  Care should be taken to not allow an error to occur
-   prior to completing the initialization of the breakpoint.  If this
-   should happen, a bogus breakpoint will be left on the chain.  */
+   information regarding the creation of a new breakpoint.  */
 
-struct breakpoint *
-set_raw_breakpoint (struct gdbarch *gdbarch,
-                   struct symtab_and_line sal, enum bptype bptype)
+static void
+init_raw_breakpoint (struct breakpoint *b, struct gdbarch *gdbarch,
+                    struct symtab_and_line sal, enum bptype bptype,
+                    const struct breakpoint_ops *ops)
 {
-  struct breakpoint *b = set_raw_breakpoint_without_location (gdbarch, 
-                                                             bptype);
   CORE_ADDR adjusted_address;
   struct gdbarch *loc_gdbarch;
 
+  init_raw_breakpoint_without_location (b, gdbarch, bptype, ops);
+
   loc_gdbarch = get_sal_arch (sal);
   if (!loc_gdbarch)
     loc_gdbarch = b->gdbarch;
@@ -5920,7 +5783,32 @@ set_raw_breakpoint (struct gdbarch *gdbarch,
                                    sal.explicit_pc || sal.explicit_line);
 
   breakpoints_changed ();
+}
+
+/* set_raw_breakpoint is a low level routine for allocating and
+   partially initializing a breakpoint of type BPTYPE.  The newly
+   created breakpoint's address, section, source file name, and line
+   number are provided by SAL.  The newly created and partially
+   initialized breakpoint is added to the breakpoint chain and
+   is also returned as the value of this function.
+
+   It is expected that the caller will complete the initialization of
+   the newly created breakpoint struct as well as output any status
+   information regarding the creation of a new breakpoint.  In
+   particular, set_raw_breakpoint does NOT set the breakpoint
+   number!  Care should be taken to not allow an error to occur
+   prior to completing the initialization of the breakpoint.  If this
+   should happen, a bogus breakpoint will be left on the chain.  */
+
+struct breakpoint *
+set_raw_breakpoint (struct gdbarch *gdbarch,
+                   struct symtab_and_line sal, enum bptype bptype,
+                   const struct breakpoint_ops *ops)
+{
+  struct breakpoint *b = XNEW (struct breakpoint);
 
+  init_raw_breakpoint (b, gdbarch, sal, bptype, ops);
+  add_to_breakpoint_chain (b);
   return b;
 }
 
@@ -5938,7 +5826,7 @@ make_breakpoint_permanent (struct breakpoint *b)
      code.  Mark all locations as inserted.  For now,
      make_breakpoint_permanent is called in just one place, so it's
      hard to say if it's reasonable to have permanent breakpoint with
-     multiple locations or not, but it's easy to implmement.  */
+     multiple locations or not, but it's easy to implement.  */
   for (bl = b->loc; bl; bl = bl->next)
     bl->inserted = 1;
 }
@@ -5962,9 +5850,11 @@ set_longjmp_breakpoint (struct thread_info *tp, struct frame_id frame)
        && (b->type == bp_longjmp_master
            || b->type == bp_exception_master))
       {
-       struct breakpoint *clone = clone_momentary_breakpoint (b);
+       enum bptype type = b->type == bp_longjmp_master ? bp_longjmp : bp_exception;
+       struct breakpoint *clone;
 
-       clone->type = b->type == bp_longjmp_master ? bp_longjmp : bp_exception;
+       clone = momentary_breakpoint_from_master (b, type,
+                                                 &momentary_breakpoint_ops);
        clone->thread = thread;
       }
 
@@ -6024,8 +5914,8 @@ set_std_terminate_breakpoint (void)
     if (b->pspace == current_program_space
        && b->type == bp_std_terminate_master)
       {
-       struct breakpoint *clone = clone_momentary_breakpoint (b);
-       clone->type = bp_std_terminate;
+       momentary_breakpoint_from_master (b, bp_std_terminate,
+                                         &momentary_breakpoint_ops);
       }
 }
 
@@ -6045,8 +5935,9 @@ create_thread_event_breakpoint (struct gdbarch *gdbarch, CORE_ADDR address)
 {
   struct breakpoint *b;
 
-  b = create_internal_breakpoint (gdbarch, address, bp_thread_event);
-  
+  b = create_internal_breakpoint (gdbarch, address, bp_thread_event,
+                                 &internal_breakpoint_ops);
+
   b->enable_state = bp_enabled;
   /* addr_string has to be used or breakpoint_re_set will delete me.  */
   b->addr_string
@@ -6081,7 +5972,8 @@ create_jit_event_breakpoint (struct gdbarch *gdbarch, CORE_ADDR address)
 {
   struct breakpoint *b;
 
-  b = create_internal_breakpoint (gdbarch, address, bp_jit_event);
+  b = create_internal_breakpoint (gdbarch, address, bp_jit_event,
+                                 &internal_breakpoint_ops);
   update_global_location_list_nothrow (1);
   return b;
 }
@@ -6115,7 +6007,8 @@ create_solib_event_breakpoint (struct gdbarch *gdbarch, CORE_ADDR address)
 {
   struct breakpoint *b;
 
-  b = create_internal_breakpoint (gdbarch, address, bp_shlib_event);
+  b = create_internal_breakpoint (gdbarch, address, bp_shlib_event,
+                                 &internal_breakpoint_ops);
   update_global_location_list_nothrow (1);
   return b;
 }
@@ -6211,6 +6104,23 @@ disable_breakpoints_in_unloaded_shlib (struct so_list *solib)
 
 /* FORK & VFORK catchpoints.  */
 
+/* An instance of this type is used to represent a fork or vfork
+   catchpoint.  It includes a "struct breakpoint" as a kind of base
+   class; users downcast to "struct breakpoint *" when needed.  A
+   breakpoint is really of this type iff its ops pointer points to
+   CATCH_FORK_BREAKPOINT_OPS.  */
+
+struct fork_catchpoint
+{
+  /* The base class.  */
+  struct breakpoint base;
+
+  /* Process id of a child process whose forking triggered this
+     catchpoint.  This field is only valid immediately after this
+     catchpoint has triggered.  */
+  ptid_t forked_inferior_pid;
+};
+
 /* Implement the "insert" breakpoint_ops method for fork
    catchpoints.  */
 
@@ -6236,18 +6146,23 @@ static int
 breakpoint_hit_catch_fork (const struct bp_location *bl,
                           struct address_space *aspace, CORE_ADDR bp_addr)
 {
-  return inferior_has_forked (inferior_ptid, &bl->owner->forked_inferior_pid);
+  struct fork_catchpoint *c = (struct fork_catchpoint *) bl->owner;
+
+  return inferior_has_forked (inferior_ptid, &c->forked_inferior_pid);
 }
 
 /* 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 (bpstat bs)
 {
+  struct breakpoint *b = bs->breakpoint_at;
+  struct fork_catchpoint *c = (struct fork_catchpoint *) bs->breakpoint_at;
+
   annotate_catchpoint (b->number);
   printf_filtered (_("\nCatchpoint %d (forked process %d), "),
-                  b->number, ptid_get_pid (b->forked_inferior_pid));
+                  b->number, ptid_get_pid (c->forked_inferior_pid));
   return PRINT_SRC_AND_LOC;
 }
 
@@ -6257,7 +6172,9 @@ print_it_catch_fork (struct breakpoint *b)
 static void
 print_one_catch_fork (struct breakpoint *b, struct bp_location **last_loc)
 {
+  struct fork_catchpoint *c = (struct fork_catchpoint *) b;
   struct value_print_options opts;
+  struct ui_out *uiout = current_uiout;
 
   get_user_print_options (&opts);
 
@@ -6268,11 +6185,11 @@ print_one_catch_fork (struct breakpoint *b, struct bp_location **last_loc)
     ui_out_field_skip (uiout, "addr");
   annotate_field (5);
   ui_out_text (uiout, "fork");
-  if (!ptid_equal (b->forked_inferior_pid, null_ptid))
+  if (!ptid_equal (c->forked_inferior_pid, null_ptid))
     {
       ui_out_text (uiout, ", process ");
       ui_out_field_int (uiout, "what",
-                        ptid_get_pid (b->forked_inferior_pid));
+                        ptid_get_pid (c->forked_inferior_pid));
       ui_out_spaces (uiout, 1);
     }
 }
@@ -6293,22 +6210,12 @@ static void
 print_recreate_catch_fork (struct breakpoint *b, struct ui_file *fp)
 {
   fprintf_unfiltered (fp, "catch fork");
+  print_recreate_thread (b, fp);
 }
 
 /* The breakpoint_ops structure to be used in fork catchpoints.  */
 
-static struct breakpoint_ops catch_fork_breakpoint_ops =
-{
-  insert_catch_fork,
-  remove_catch_fork,
-  breakpoint_hit_catch_fork,
-  NULL, /* resources_needed */
-  print_it_catch_fork,
-  print_one_catch_fork,
-  NULL, /* print_one_detail */
-  print_mention_catch_fork,
-  print_recreate_catch_fork
-};
+static struct breakpoint_ops catch_fork_breakpoint_ops;
 
 /* Implement the "insert" breakpoint_ops method for vfork
    catchpoints.  */
@@ -6335,18 +6242,23 @@ static int
 breakpoint_hit_catch_vfork (const struct bp_location *bl,
                            struct address_space *aspace, CORE_ADDR bp_addr)
 {
-  return inferior_has_vforked (inferior_ptid, &bl->owner->forked_inferior_pid);
+  struct fork_catchpoint *c = (struct fork_catchpoint *) bl->owner;
+
+  return inferior_has_vforked (inferior_ptid, &c->forked_inferior_pid);
 }
 
 /* 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 (bpstat bs)
 {
+  struct breakpoint *b = bs->breakpoint_at;
+  struct fork_catchpoint *c = (struct fork_catchpoint *) b;
+
   annotate_catchpoint (b->number);
   printf_filtered (_("\nCatchpoint %d (vforked process %d), "),
-                  b->number, ptid_get_pid (b->forked_inferior_pid));
+                  b->number, ptid_get_pid (c->forked_inferior_pid));
   return PRINT_SRC_AND_LOC;
 }
 
@@ -6356,7 +6268,9 @@ print_it_catch_vfork (struct breakpoint *b)
 static void
 print_one_catch_vfork (struct breakpoint *b, struct bp_location **last_loc)
 {
+  struct fork_catchpoint *c = (struct fork_catchpoint *) b;
   struct value_print_options opts;
+  struct ui_out *uiout = current_uiout;
 
   get_user_print_options (&opts);
   /* Field 4, the address, is omitted (which makes the columns not
@@ -6366,11 +6280,11 @@ print_one_catch_vfork (struct breakpoint *b, struct bp_location **last_loc)
     ui_out_field_skip (uiout, "addr");
   annotate_field (5);
   ui_out_text (uiout, "vfork");
-  if (!ptid_equal (b->forked_inferior_pid, null_ptid))
+  if (!ptid_equal (c->forked_inferior_pid, null_ptid))
     {
       ui_out_text (uiout, ", process ");
       ui_out_field_int (uiout, "what",
-                        ptid_get_pid (b->forked_inferior_pid));
+                        ptid_get_pid (c->forked_inferior_pid));
       ui_out_spaces (uiout, 1);
     }
 }
@@ -6391,40 +6305,62 @@ static void
 print_recreate_catch_vfork (struct breakpoint *b, struct ui_file *fp)
 {
   fprintf_unfiltered (fp, "catch vfork");
+  print_recreate_thread (b, fp);
 }
 
 /* The breakpoint_ops structure to be used in vfork catchpoints.  */
 
-static struct breakpoint_ops catch_vfork_breakpoint_ops =
-{
-  insert_catch_vfork,
-  remove_catch_vfork,
-  breakpoint_hit_catch_vfork,
-  NULL, /* resources_needed */
-  print_it_catch_vfork,
-  print_one_catch_vfork,
-  NULL, /* print_one_detail */
-  print_mention_catch_vfork,
-  print_recreate_catch_vfork
+static struct breakpoint_ops catch_vfork_breakpoint_ops;
+
+/* An instance of this type is used to represent a syscall catchpoint.
+   It includes a "struct breakpoint" as a kind of base class; users
+   downcast to "struct breakpoint *" when needed.  A breakpoint is
+   really of this type iff its ops pointer points to
+   CATCH_SYSCALL_BREAKPOINT_OPS.  */
+
+struct syscall_catchpoint
+{
+  /* The base class.  */
+  struct breakpoint base;
+
+  /* Syscall numbers used for the 'catch syscall' feature.  If no
+     syscall has been specified for filtering, its value is NULL.
+     Otherwise, it holds a list of all syscalls to be caught.  The
+     list elements are allocated with xmalloc.  */
+  VEC(int) *syscalls_to_be_caught;
 };
 
+/* Implement the "dtor" breakpoint_ops method for syscall
+   catchpoints.  */
+
+static void
+dtor_catch_syscall (struct breakpoint *b)
+{
+  struct syscall_catchpoint *c = (struct syscall_catchpoint *) b;
+
+  VEC_free (int, c->syscalls_to_be_caught);
+
+  base_breakpoint_ops.dtor (b);
+}
+
 /* Implement the "insert" breakpoint_ops method for syscall
    catchpoints.  */
 
 static int
 insert_catch_syscall (struct bp_location *bl)
 {
+  struct syscall_catchpoint *c = (struct syscall_catchpoint *) bl->owner;
   struct inferior *inf = current_inferior ();
 
   ++inf->total_syscalls_count;
-  if (!bl->owner->syscalls_to_be_caught)
+  if (!c->syscalls_to_be_caught)
     ++inf->any_syscall_count;
   else
     {
       int i, iter;
 
       for (i = 0;
-           VEC_iterate (int, bl->owner->syscalls_to_be_caught, i, iter);
+           VEC_iterate (int, c->syscalls_to_be_caught, i, iter);
            i++)
        {
           int elem;
@@ -6459,17 +6395,18 @@ insert_catch_syscall (struct bp_location *bl)
 static int
 remove_catch_syscall (struct bp_location *bl)
 {
+  struct syscall_catchpoint *c = (struct syscall_catchpoint *) bl->owner;
   struct inferior *inf = current_inferior ();
 
   --inf->total_syscalls_count;
-  if (!bl->owner->syscalls_to_be_caught)
+  if (!c->syscalls_to_be_caught)
     --inf->any_syscall_count;
   else
     {
       int i, iter;
 
       for (i = 0;
-           VEC_iterate (int, bl->owner->syscalls_to_be_caught, i, iter);
+           VEC_iterate (int, c->syscalls_to_be_caught, i, iter);
            i++)
        {
           int elem;
@@ -6500,18 +6437,19 @@ breakpoint_hit_catch_syscall (const struct bp_location *bl,
      breakpoint.  If we are, then we must guarantee that the called
      syscall is the same syscall we are catching.  */
   int syscall_number = 0;
-  const struct breakpoint *b = bl->owner;
+  const struct syscall_catchpoint *c
+    = (const struct syscall_catchpoint *) bl->owner;
 
   if (!inferior_has_called_syscall (inferior_ptid, &syscall_number))
     return 0;
 
   /* Now, checking if the syscall is the same.  */
-  if (b->syscalls_to_be_caught)
+  if (c->syscalls_to_be_caught)
     {
       int i, iter;
 
       for (i = 0;
-           VEC_iterate (int, b->syscalls_to_be_caught, i, iter);
+           VEC_iterate (int, c->syscalls_to_be_caught, i, iter);
            i++)
        if (syscall_number == iter)
          break;
@@ -6527,8 +6465,9 @@ breakpoint_hit_catch_syscall (const struct bp_location *bl,
    catchpoints.  */
 
 static enum print_stop_action
-print_it_catch_syscall (struct breakpoint *b)
+print_it_catch_syscall (bpstat bs)
 {
+  struct breakpoint *b = bs->breakpoint_at;
   /* These are needed because we want to know in which state a
      syscall is.  It can be in the TARGET_WAITKIND_SYSCALL_ENTRY
      or TARGET_WAITKIND_SYSCALL_RETURN, and depending on it we
@@ -6571,7 +6510,9 @@ static void
 print_one_catch_syscall (struct breakpoint *b,
                         struct bp_location **last_loc)
 {
+  struct syscall_catchpoint *c = (struct syscall_catchpoint *) b;
   struct value_print_options opts;
+  struct ui_out *uiout = current_uiout;
 
   get_user_print_options (&opts);
   /* Field 4, the address, is omitted (which makes the columns not
@@ -6581,19 +6522,19 @@ print_one_catch_syscall (struct breakpoint *b,
     ui_out_field_skip (uiout, "addr");
   annotate_field (5);
 
-  if (b->syscalls_to_be_caught
-      && VEC_length (int, b->syscalls_to_be_caught) > 1)
+  if (c->syscalls_to_be_caught
+      && VEC_length (int, c->syscalls_to_be_caught) > 1)
     ui_out_text (uiout, "syscalls \"");
   else
     ui_out_text (uiout, "syscall \"");
 
-  if (b->syscalls_to_be_caught)
+  if (c->syscalls_to_be_caught)
     {
       int i, iter;
       char *text = xstrprintf ("%s", "");
 
       for (i = 0;
-           VEC_iterate (int, b->syscalls_to_be_caught, i, iter);
+           VEC_iterate (int, c->syscalls_to_be_caught, i, iter);
            i++)
         {
           char *x = text;
@@ -6606,7 +6547,7 @@ print_one_catch_syscall (struct breakpoint *b,
             text = xstrprintf ("%s%d, ", text, iter);
 
           /* We have to xfree the last 'text' (now stored at 'x')
-             because xstrprintf dinamically allocates new space for it
+             because xstrprintf dynamically allocates new space for it
              on every call.  */
          xfree (x);
         }
@@ -6625,17 +6566,19 @@ print_one_catch_syscall (struct breakpoint *b,
 static void
 print_mention_catch_syscall (struct breakpoint *b)
 {
-  if (b->syscalls_to_be_caught)
+  struct syscall_catchpoint *c = (struct syscall_catchpoint *) b;
+
+  if (c->syscalls_to_be_caught)
     {
       int i, iter;
 
-      if (VEC_length (int, b->syscalls_to_be_caught) > 1)
+      if (VEC_length (int, c->syscalls_to_be_caught) > 1)
         printf_filtered (_("Catchpoint %d (syscalls"), b->number);
       else
         printf_filtered (_("Catchpoint %d (syscall"), b->number);
 
       for (i = 0;
-           VEC_iterate (int, b->syscalls_to_be_caught, i, iter);
+           VEC_iterate (int, c->syscalls_to_be_caught, i, iter);
            i++)
         {
           struct syscall s;
@@ -6659,14 +6602,16 @@ print_mention_catch_syscall (struct breakpoint *b)
 static void
 print_recreate_catch_syscall (struct breakpoint *b, struct ui_file *fp)
 {
+  struct syscall_catchpoint *c = (struct syscall_catchpoint *) b;
+
   fprintf_unfiltered (fp, "catch syscall");
 
-  if (b->syscalls_to_be_caught)
+  if (c->syscalls_to_be_caught)
     {
       int i, iter;
 
       for (i = 0;
-           VEC_iterate (int, b->syscalls_to_be_caught, i, iter);
+           VEC_iterate (int, c->syscalls_to_be_caught, i, iter);
            i++)
         {
           struct syscall s;
@@ -6678,22 +6623,12 @@ print_recreate_catch_syscall (struct breakpoint *b, struct ui_file *fp)
             fprintf_unfiltered (fp, " %d", s.number);
         }
     }
+  print_recreate_thread (b, fp);
 }
 
 /* The breakpoint_ops structure to be used in syscall catchpoints.  */
 
-static struct breakpoint_ops catch_syscall_breakpoint_ops =
-{
-  insert_catch_syscall,
-  remove_catch_syscall,
-  breakpoint_hit_catch_syscall,
-  NULL, /* resources_needed */
-  print_it_catch_syscall,
-  print_one_catch_syscall,
-  NULL, /* print_one_detail */
-  print_mention_catch_syscall,
-  print_recreate_catch_syscall
-};
+static struct breakpoint_ops catch_syscall_breakpoint_ops;
 
 /* Returns non-zero if 'b' is a syscall catchpoint.  */
 
@@ -6703,109 +6638,124 @@ syscall_catchpoint_p (struct breakpoint *b)
   return (b->ops == &catch_syscall_breakpoint_ops);
 }
 
-/* Create a new breakpoint of the bp_catchpoint kind and return it,
-   but does NOT mention it nor update the global location list.
-   This is useful if you need to fill more fields in the
-   struct breakpoint before calling mention.
-   If TEMPFLAG is non-zero, then make the breakpoint temporary.
-   If COND_STRING is not NULL, then store it in the breakpoint.
-   OPS, if not NULL, is the breakpoint_ops structure associated
-   to the catchpoint.  */
+/* Initialize a new breakpoint of the bp_catchpoint kind.  If TEMPFLAG
+   is non-zero, then make the breakpoint temporary.  If COND_STRING is
+   not NULL, then store it in the breakpoint.  OPS, if not NULL, is
+   the breakpoint_ops structure associated to the catchpoint.  */
 
-static struct breakpoint *
-create_catchpoint_without_mention (struct gdbarch *gdbarch, int tempflag,
-                                  char *cond_string,
-                                  struct breakpoint_ops *ops)
+static void
+init_catchpoint (struct breakpoint *b,
+                struct gdbarch *gdbarch, int tempflag,
+                char *cond_string,
+                const struct breakpoint_ops *ops)
 {
   struct symtab_and_line sal;
-  struct breakpoint *b;
 
   init_sal (&sal);
   sal.pspace = current_program_space;
 
-  b = set_raw_breakpoint (gdbarch, sal, bp_catchpoint);
-  set_breakpoint_count (breakpoint_count + 1);
-  b->number = breakpoint_count;
+  init_raw_breakpoint (b, gdbarch, sal, bp_catchpoint, ops);
 
   b->cond_string = (cond_string == NULL) ? NULL : xstrdup (cond_string);
-  b->thread = -1;
-  b->addr_string = NULL;
-  b->enable_state = bp_enabled;
   b->disposition = tempflag ? disp_del : disp_donttouch;
-  b->ops = ops;
-
-  return b;
 }
 
-/* Create a new breakpoint of the bp_catchpoint kind and return it.
-   If TEMPFLAG is non-zero, then make the breakpoint temporary.
-   If COND_STRING is not NULL, then store it in the breakpoint.
-   OPS, if not NULL, is the breakpoint_ops structure associated
-   to the catchpoint.  */
-
-static struct breakpoint *
-create_catchpoint (struct gdbarch *gdbarch, int tempflag,
-                  char *cond_string, struct breakpoint_ops *ops)
+void
+install_breakpoint (int internal, struct breakpoint *b)
 {
-  struct breakpoint *b =
-    create_catchpoint_without_mention (gdbarch, tempflag, cond_string, ops);
-
-  mention (b);
+  add_to_breakpoint_chain (b);
+  set_breakpoint_number (internal, b);
+  if (!internal)
+    mention (b);
   observer_notify_breakpoint_created (b);
   update_global_location_list (1);
-
-  return b;
 }
 
 static void
 create_fork_vfork_event_catchpoint (struct gdbarch *gdbarch,
                                    int tempflag, char *cond_string,
-                                    struct breakpoint_ops *ops)
+                                    const struct breakpoint_ops *ops)
 {
-  struct breakpoint *b
-    = create_catchpoint (gdbarch, tempflag, cond_string, ops);
+  struct fork_catchpoint *c = XNEW (struct fork_catchpoint);
+
+  init_catchpoint (&c->base, gdbarch, tempflag, cond_string, ops);
 
-  /* FIXME: We should put this information in a breakpoint private data
-     area.  */
-  b->forked_inferior_pid = null_ptid;
+  c->forked_inferior_pid = null_ptid;
+
+  install_breakpoint (0, &c->base);
 }
 
 /* Exec catchpoints.  */
 
-static int
-insert_catch_exec (struct bp_location *bl)
-{
-  return target_insert_exec_catchpoint (PIDGET (inferior_ptid));
-}
+/* An instance of this type is used to represent an exec catchpoint.
+   It includes a "struct breakpoint" as a kind of base class; users
+   downcast to "struct breakpoint *" when needed.  A breakpoint is
+   really of this type iff its ops pointer points to
+   CATCH_EXEC_BREAKPOINT_OPS.  */
 
-static int
-remove_catch_exec (struct bp_location *bl)
+struct exec_catchpoint
 {
-  return target_remove_exec_catchpoint (PIDGET (inferior_ptid));
-}
+  /* The base class.  */
+  struct breakpoint base;
 
-static int
-breakpoint_hit_catch_exec (const struct bp_location *bl,
+  /* Filename of a program whose exec triggered this catchpoint.
+     This field is only valid immediately after this catchpoint has
+     triggered.  */
+  char *exec_pathname;
+};
+
+/* Implement the "dtor" breakpoint_ops method for exec
+   catchpoints.  */
+
+static void
+dtor_catch_exec (struct breakpoint *b)
+{
+  struct exec_catchpoint *c = (struct exec_catchpoint *) b;
+
+  xfree (c->exec_pathname);
+
+  base_breakpoint_ops.dtor (b);
+}
+
+static int
+insert_catch_exec (struct bp_location *bl)
+{
+  return target_insert_exec_catchpoint (PIDGET (inferior_ptid));
+}
+
+static int
+remove_catch_exec (struct bp_location *bl)
+{
+  return target_remove_exec_catchpoint (PIDGET (inferior_ptid));
+}
+
+static int
+breakpoint_hit_catch_exec (const struct bp_location *bl,
                           struct address_space *aspace, CORE_ADDR bp_addr)
 {
-  return inferior_has_execd (inferior_ptid, &bl->owner->exec_pathname);
+  struct exec_catchpoint *c = (struct exec_catchpoint *) bl->owner;
+
+  return inferior_has_execd (inferior_ptid, &c->exec_pathname);
 }
 
 static enum print_stop_action
-print_it_catch_exec (struct breakpoint *b)
+print_it_catch_exec (bpstat bs)
 {
+  struct breakpoint *b = bs->breakpoint_at;
+  struct exec_catchpoint *c = (struct exec_catchpoint *) b;
+
   annotate_catchpoint (b->number);
   printf_filtered (_("\nCatchpoint %d (exec'd %s), "), b->number,
-                  b->exec_pathname);
+                  c->exec_pathname);
   return PRINT_SRC_AND_LOC;
 }
 
 static void
 print_one_catch_exec (struct breakpoint *b, struct bp_location **last_loc)
 {
+  struct exec_catchpoint *c = (struct exec_catchpoint *) b;
   struct value_print_options opts;
+  struct ui_out *uiout = current_uiout;
 
   get_user_print_options (&opts);
 
@@ -6816,10 +6766,10 @@ print_one_catch_exec (struct breakpoint *b, struct bp_location **last_loc)
     ui_out_field_skip (uiout, "addr");
   annotate_field (5);
   ui_out_text (uiout, "exec");
-  if (b->exec_pathname != NULL)
+  if (c->exec_pathname != NULL)
     {
       ui_out_text (uiout, ", program \"");
-      ui_out_field_string (uiout, "what", b->exec_pathname);
+      ui_out_field_string (uiout, "what", c->exec_pathname);
       ui_out_text (uiout, "\" ");
     }
 }
@@ -6837,36 +6787,23 @@ static void
 print_recreate_catch_exec (struct breakpoint *b, struct ui_file *fp)
 {
   fprintf_unfiltered (fp, "catch exec");
+  print_recreate_thread (b, fp);
 }
 
-static struct breakpoint_ops catch_exec_breakpoint_ops =
-{
-  insert_catch_exec,
-  remove_catch_exec,
-  breakpoint_hit_catch_exec,
-  NULL, /* resources_needed */
-  print_it_catch_exec,
-  print_one_catch_exec,
-  NULL, /* print_one_detail */
-  print_mention_catch_exec,
-  print_recreate_catch_exec
-};
+static struct breakpoint_ops catch_exec_breakpoint_ops;
 
 static void
 create_syscall_event_catchpoint (int tempflag, VEC(int) *filter,
-                                 struct breakpoint_ops *ops)
+                                 const struct breakpoint_ops *ops)
 {
+  struct syscall_catchpoint *c;
   struct gdbarch *gdbarch = get_current_arch ();
-  struct breakpoint *b =
-    create_catchpoint_without_mention (gdbarch, tempflag, NULL, ops);
 
-  b->syscalls_to_be_caught = filter;
+  c = XNEW (struct syscall_catchpoint);
+  init_catchpoint (&c->base, gdbarch, tempflag, NULL, ops);
+  c->syscalls_to_be_caught = filter;
 
-  /* Now, we have to mention the breakpoint and update the global
-     location list.  */
-  mention (b);
-  observer_notify_breakpoint_created (b);
-  update_global_location_list (1);
+  install_breakpoint (0, &c->base);
 }
 
 static int
@@ -6883,10 +6820,7 @@ hw_breakpoint_used_count (void)
        {
          /* Special types of hardware breakpoints may use more than
             one register.  */
-         if (b->ops && b->ops->resources_needed)
-           i += b->ops->resources_needed (bl);
-         else
-           i++;
+         i += b->ops->resources_needed (bl);
        }
   }
 
@@ -6911,10 +6845,7 @@ hw_watchpoint_used_count (enum bptype type, int *other_type_used)
            {
              /* Special types of hardware watchpoints may use more than
                 one register.  */
-             if (b->ops && b->ops->resources_needed)
-               i += b->ops->resources_needed (bl);
-             else
-               i++;
+             i += b->ops->resources_needed (bl);
            }
        else if (is_hardware_watchpoint (b))
          *other_type_used = 1;
@@ -7020,7 +6951,7 @@ set_momentary_breakpoint (struct gdbarch *gdbarch, struct symtab_and_line sal,
      one.  */
   gdb_assert (!frame_id_inlined_p (frame_id));
 
-  b = set_raw_breakpoint (gdbarch, sal, type);
+  b = set_raw_breakpoint (gdbarch, sal, type, &momentary_breakpoint_ops);
   b->enable_state = bp_enabled;
   b->disposition = disp_donttouch;
   b->frame_id = frame_id;
@@ -7036,19 +6967,18 @@ set_momentary_breakpoint (struct gdbarch *gdbarch, struct symtab_and_line sal,
   return b;
 }
 
-/* Make a deep copy of momentary breakpoint ORIG.  Returns NULL if
-   ORIG is NULL.  */
+/* Make a momentary breakpoint based on the master breakpoint ORIG.
+   The new breakpoint will have type TYPE, and use OPS as it
+   breakpoint_ops.  */
 
-struct breakpoint *
-clone_momentary_breakpoint (struct breakpoint *orig)
+static struct breakpoint *
+momentary_breakpoint_from_master (struct breakpoint *orig,
+                                 enum bptype type,
+                                 const struct breakpoint_ops *ops)
 {
   struct breakpoint *copy;
 
-  /* If there's nothing to clone, then return nothing.  */
-  if (orig == NULL)
-    return NULL;
-
-  copy = set_raw_breakpoint_without_location (orig->gdbarch, orig->type);
+  copy = set_raw_breakpoint_without_location (orig->gdbarch, type, ops);
   copy->loc = allocate_bp_location (copy);
   set_breakpoint_location_function (copy->loc, 1);
 
@@ -7076,6 +7006,19 @@ clone_momentary_breakpoint (struct breakpoint *orig)
   return copy;
 }
 
+/* Make a deep copy of momentary breakpoint ORIG.  Returns NULL if
+   ORIG is NULL.  */
+
+struct breakpoint *
+clone_momentary_breakpoint (struct breakpoint *orig)
+{
+  /* If there's nothing to clone, then return nothing.  */
+  if (orig == NULL)
+    return NULL;
+
+  return momentary_breakpoint_from_master (orig, orig->type, orig->ops);
+}
+
 struct breakpoint *
 set_momentary_breakpoint_at_pc (struct gdbarch *gdbarch, CORE_ADDR pc,
                                enum bptype type)
@@ -7096,162 +7039,8 @@ set_momentary_breakpoint_at_pc (struct gdbarch *gdbarch, CORE_ADDR pc,
 static void
 mention (struct breakpoint *b)
 {
-  int say_where = 0;
-  struct cleanup *ui_out_chain;
-  struct value_print_options opts;
-
-  get_user_print_options (&opts);
-
-  if (b->ops != NULL && b->ops->print_mention != NULL)
-    b->ops->print_mention (b);
-  else
-    switch (b->type)
-      {
-      case bp_none:
-       printf_filtered (_("(apparently deleted?) Eventpoint %d: "),
-                        b->number);
-       break;
-      case bp_watchpoint:
-       ui_out_text (uiout, "Watchpoint ");
-       ui_out_chain = make_cleanup_ui_out_tuple_begin_end (uiout, "wpt");
-       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);
-       break;
-      case bp_hardware_watchpoint:
-       ui_out_text (uiout, "Hardware watchpoint ");
-       ui_out_chain = make_cleanup_ui_out_tuple_begin_end (uiout, "wpt");
-       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);
-       break;
-      case bp_read_watchpoint:
-       ui_out_text (uiout, "Hardware read watchpoint ");
-       ui_out_chain = make_cleanup_ui_out_tuple_begin_end (uiout, "hw-rwpt");
-       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);
-       break;
-      case bp_access_watchpoint:
-       ui_out_text (uiout, "Hardware access (read/write) watchpoint ");
-       ui_out_chain = make_cleanup_ui_out_tuple_begin_end (uiout, "hw-awpt");
-       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);
-       break;
-      case bp_breakpoint:
-      case bp_gnu_ifunc_resolver:
-       if (ui_out_is_mi_like_p (uiout))
-         {
-           say_where = 0;
-           break;
-         }
-       if (b->disposition == disp_del)
-         printf_filtered (_("Temporary breakpoint"));
-       else
-         printf_filtered (_("Breakpoint"));
-       printf_filtered (_(" %d"), b->number);
-       if (b->type == bp_gnu_ifunc_resolver)
-         printf_filtered (_(" at gnu-indirect-function resolver"));
-       say_where = 1;
-       break;
-      case bp_hardware_breakpoint:
-       if (ui_out_is_mi_like_p (uiout))
-         {
-           say_where = 0;
-           break;
-         }
-       printf_filtered (_("Hardware assisted breakpoint %d"), b->number);
-       say_where = 1;
-       break;
-      case bp_tracepoint:
-       if (ui_out_is_mi_like_p (uiout))
-         {
-           say_where = 0;
-           break;
-         }
-       printf_filtered (_("Tracepoint"));
-       printf_filtered (_(" %d"), b->number);
-       say_where = 1;
-       break;
-      case bp_fast_tracepoint:
-       if (ui_out_is_mi_like_p (uiout))
-         {
-           say_where = 0;
-           break;
-         }
-       printf_filtered (_("Fast tracepoint"));
-       printf_filtered (_(" %d"), b->number);
-       say_where = 1;
-       break;
-      case bp_static_tracepoint:
-       if (ui_out_is_mi_like_p (uiout))
-         {
-           say_where = 0;
-           break;
-         }
-       printf_filtered (_("Static tracepoint"));
-       printf_filtered (_(" %d"), b->number);
-       say_where = 1;
-       break;
-
-      case bp_until:
-      case bp_finish:
-      case bp_longjmp:
-      case bp_longjmp_resume:
-      case bp_exception:
-      case bp_exception_resume:
-      case bp_step_resume:
-      case bp_call_dummy:
-      case bp_std_terminate:
-      case bp_watchpoint_scope:
-      case bp_shlib_event:
-      case bp_thread_event:
-      case bp_overlay_event:
-      case bp_jit_event:
-      case bp_longjmp_master:
-      case bp_std_terminate_master:
-      case bp_exception_master:
-      case bp_gnu_ifunc_resolver_return:
-       break;
-      }
-
-  if (say_where)
-    {
-      /* i18n: cagney/2005-02-11: Below needs to be merged into a
-        single string.  */
-      if (b->loc == NULL)
-       {
-         printf_filtered (_(" (%s) pending."), b->addr_string);
-       }
-      else
-       {
-         if (opts.addressprint || b->source_file == NULL)
-           {
-             printf_filtered (" at ");
-             fputs_filtered (paddress (b->loc->gdbarch, b->loc->address),
-                             gdb_stdout);
-           }
-         if (b->source_file)
-           printf_filtered (": file %s, line %d.",
-                            b->source_file, b->line_number);
-         
-         if (b->loc->next)
-           {
-             struct bp_location *loc = b->loc;
-             int n = 0;
-             for (; loc; loc = loc->next)
-               ++n;
-             printf_filtered (" (%d locations)", n);           
-           }
-
-       }
-    }
-  if (ui_out_is_mi_like_p (uiout))
+  b->ops->print_mention (b);
+  if (ui_out_is_mi_like_p (current_uiout))
     return;
   printf_filtered ("\n");
 }
@@ -7331,15 +7120,14 @@ bp_loc_is_permanent (struct bp_location *loc)
    as condition expression.  */
 
 static void
-create_breakpoint_sal (struct gdbarch *gdbarch,
-                      struct symtabs_and_lines sals, char *addr_string,
-                      char *cond_string,
-                      enum bptype type, enum bpdisp disposition,
-                      int thread, int task, int ignore_count,
-                      struct breakpoint_ops *ops, int from_tty,
-                      int enabled, int internal, int display_canonical)
+init_breakpoint_sal (struct breakpoint *b, struct gdbarch *gdbarch,
+                    struct symtabs_and_lines sals, char *addr_string,
+                    char *cond_string,
+                    enum bptype type, enum bpdisp disposition,
+                    int thread, int task, int ignore_count,
+                    const struct breakpoint_ops *ops, int from_tty,
+                    int enabled, int internal, int display_canonical)
 {
-  struct breakpoint *b = NULL;
   int i;
 
   if (type == bp_hardware_breakpoint)
@@ -7373,8 +7161,7 @@ create_breakpoint_sal (struct gdbarch *gdbarch,
 
       if (i == 0)
        {
-         b = set_raw_breakpoint (gdbarch, sal, type);
-         set_breakpoint_number (internal, b);
+         init_raw_breakpoint (b, gdbarch, sal, type, ops);
          b->thread = thread;
          b->task = task;
   
@@ -7386,6 +7173,7 @@ create_breakpoint_sal (struct gdbarch *gdbarch,
 
          if (type == bp_static_tracepoint)
            {
+             struct tracepoint *t = (struct tracepoint *) b;
              struct static_tracepoint_marker marker;
 
              if (is_marker_spec (addr_string))
@@ -7402,20 +7190,20 @@ create_breakpoint_sal (struct gdbarch *gdbarch,
                  endp = skip_to_space (p);
 
                  marker_str = savestring (p, endp - p);
-                 b->static_trace_marker_id = marker_str;
+                 t->static_trace_marker_id = marker_str;
 
                  printf_filtered (_("Probed static tracepoint "
                                     "marker \"%s\"\n"),
-                                  b->static_trace_marker_id);
+                                  t->static_trace_marker_id);
                }
              else if (target_static_tracepoint_marker_at (sal.pc, &marker))
                {
-                 b->static_trace_marker_id = xstrdup (marker.str_id);
+                 t->static_trace_marker_id = xstrdup (marker.str_id);
                  release_static_tracepoint_marker (&marker);
 
                  printf_filtered (_("Probed static tracepoint "
                                     "marker \"%s\"\n"),
-                                  b->static_trace_marker_id);
+                                  t->static_trace_marker_id);
                }
              else
                warning (_("Couldn't determine the static "
@@ -7454,13 +7242,42 @@ create_breakpoint_sal (struct gdbarch *gdbarch,
        me.  */
     b->addr_string
       = xstrprintf ("*%s", paddress (b->loc->gdbarch, b->loc->address));
+}
 
-  b->ops = ops;
-  /* Do not mention breakpoints with a negative number, but do
-     notify observers.  */
-  if (!internal)
-    mention (b);
-  observer_notify_breakpoint_created (b);
+static void
+create_breakpoint_sal (struct gdbarch *gdbarch,
+                      struct symtabs_and_lines sals, char *addr_string,
+                      char *cond_string,
+                      enum bptype type, enum bpdisp disposition,
+                      int thread, int task, int ignore_count,
+                      const struct breakpoint_ops *ops, int from_tty,
+                      int enabled, int internal, int display_canonical)
+{
+  struct breakpoint *b;
+  struct cleanup *old_chain;
+
+  if (is_tracepoint_type (type))
+    {
+      struct tracepoint *t;
+
+      t = XCNEW (struct tracepoint);
+      b = &t->base;
+    }
+  else
+    b = XNEW (struct breakpoint);
+
+  old_chain = make_cleanup (xfree, b);
+
+  init_breakpoint_sal (b, gdbarch,
+                      sals, addr_string,
+                      cond_string,
+                      type, disposition,
+                      thread, task, ignore_count,
+                      ops, from_tty,
+                      enabled, internal, display_canonical);
+  discard_cleanups (old_chain);
+
+  install_breakpoint (internal, b);
 }
 
 /* Remove element at INDEX_TO_REMOVE from SAL, shifting other
@@ -7568,7 +7385,7 @@ expand_line_sal_maybe (struct symtab_and_line sal)
 
   if (expanded.nelts <= 1)
     {
-      /* This is un ugly workaround.  If we get zero expanded sals
+      /* This is an ugly workaround.  If we get zero expanded sals
          then something is really wrong.  Fix that by returning the
          original sal.  */
 
@@ -7617,7 +7434,7 @@ create_breakpoints_sal (struct gdbarch *gdbarch,
                        char *cond_string,
                        enum bptype type, enum bpdisp disposition,
                        int thread, int task, int ignore_count,
-                       struct breakpoint_ops *ops, int from_tty,
+                       const struct breakpoint_ops *ops, int from_tty,
                        int enabled, int internal)
 {
   int i;
@@ -7897,7 +7714,7 @@ create_breakpoint (struct gdbarch *gdbarch,
                   int tempflag, enum bptype type_wanted,
                   int ignore_count,
                   enum auto_boolean pending_break_support,
-                  struct breakpoint_ops *ops,
+                  const struct breakpoint_ops *ops,
                   int from_tty, int enabled, int internal)
 {
   volatile struct gdb_exception e;
@@ -7913,6 +7730,8 @@ create_breakpoint (struct gdbarch *gdbarch,
   int task = 0;
   int prev_bkpt_count = breakpoint_count;
 
+  gdb_assert (ops != NULL);
+
   sals.sals = NULL;
   sals.nelts = 0;
   init_linespec_result (&canonical);
@@ -8059,7 +7878,7 @@ create_breakpoint (struct gdbarch *gdbarch,
          for (i = 0; i < sals.nelts; ++i)
            {
              struct symtabs_and_lines expanded;
-             struct breakpoint *tp;
+             struct tracepoint *tp;
              struct cleanup *old_chain;
 
              expanded.nelts = 1;
@@ -8067,22 +7886,14 @@ create_breakpoint (struct gdbarch *gdbarch,
              expanded.sals[0] = sals.sals[i];
              old_chain = make_cleanup (xfree, expanded.sals);
 
-             create_breakpoint_sal (gdbarch, expanded, canonical.canonical[i],
-                                    cond_string, type_wanted,
-                                    tempflag ? disp_del : disp_donttouch,
-                                    thread, task, ignore_count, ops,
-                                    from_tty, enabled, internal,
-                                    canonical.special_display);
-
-             do_cleanups (old_chain);
-
-             /* Get the tracepoint we just created.  */
-             if (internal)
-               tp = get_breakpoint (internal_breakpoint_number);
-             else
-               tp = get_breakpoint (breakpoint_count);
-             gdb_assert (tp != NULL);
-
+             tp = XCNEW (struct tracepoint);
+             init_breakpoint_sal (&tp->base, gdbarch, expanded,
+                                  canonical.canonical[i],
+                                  cond_string, type_wanted,
+                                  tempflag ? disp_del : disp_donttouch,
+                                  thread, task, ignore_count, ops,
+                                  from_tty, enabled, internal,
+                                  canonical.special_display);
              /* Given that its possible to have multiple markers with
                 the same string id, if the user is creating a static
                 tracepoint by marker id ("strace -m MARKER_ID"), then
@@ -8090,6 +7901,10 @@ create_breakpoint (struct gdbarch *gdbarch,
                 try to match up which of the newly found markers
                 corresponds to this one  */
              tp->static_trace_marker_id_idx = i;
+
+             install_breakpoint (internal, &tp->base);
+
+             do_cleanups (old_chain);
            }
        }
       else
@@ -8105,7 +7920,7 @@ create_breakpoint (struct gdbarch *gdbarch,
 
       make_cleanup (xfree, copy_arg);
 
-      b = set_raw_breakpoint_without_location (gdbarch, type_wanted);
+      b = set_raw_breakpoint_without_location (gdbarch, type_wanted, ops);
       set_breakpoint_number (internal, b);
       b->thread = -1;
       b->addr_string = canonical.canonical[0];
@@ -8113,7 +7928,6 @@ create_breakpoint (struct gdbarch *gdbarch,
       b->ignore_count = ignore_count;
       b->disposition = tempflag ? disp_del : disp_donttouch;
       b->condition_not_parsed = 1;
-      b->ops = ops;
       b->enable_state = enabled ? bp_enabled : bp_disabled;
       b->pspace = current_program_space;
       b->py_bp_object = NULL;
@@ -8149,13 +7963,13 @@ create_breakpoint (struct gdbarch *gdbarch,
   return 1;
 }
 
-/* Set a breakpoint. 
+/* Set a breakpoint.
    ARG is a string describing breakpoint address,
    condition, and thread.
    FLAG specifies if a breakpoint is hardware on,
    and if breakpoint is temporary, using BP_HARDWARE_FLAG
    and BP_TEMPFLAG.  */
-   
+
 static void
 break_command_1 (char *arg, int flag, int from_tty)
 {
@@ -8170,13 +7984,12 @@ break_command_1 (char *arg, int flag, int from_tty)
                     tempflag, type_wanted,
                     0 /* Ignore count */,
                     pending_break_support,
-                    NULL /* breakpoint_ops */,
+                    &bkpt_breakpoint_ops,
                     from_tty,
                     1 /* enabled */,
                     0 /* internal */);
 }
 
-
 /* Helper function for break_command_1 and disassemble_command.  */
 
 void
@@ -8356,9 +8169,11 @@ resources_needed_ranged_breakpoint (const struct bp_location *bl)
    ranged breakpoints.  */
 
 static enum print_stop_action
-print_it_ranged_breakpoint (struct breakpoint *b)
+print_it_ranged_breakpoint (bpstat bs)
 {
+  struct breakpoint *b = bs->breakpoint_at;
   struct bp_location *bl = b->loc;
+  struct ui_out *uiout = current_uiout;
 
   gdb_assert (b->type == bp_hardware_breakpoint);
 
@@ -8391,6 +8206,7 @@ print_one_ranged_breakpoint (struct breakpoint *b,
 {
   struct bp_location *bl = b->loc;
   struct value_print_options opts;
+  struct ui_out *uiout = current_uiout;
 
   /* Ranged breakpoints have only one location.  */
   gdb_assert (bl && bl->next == NULL);
@@ -8440,6 +8256,7 @@ static void
 print_mention_ranged_breakpoint (struct breakpoint *b)
 {
   struct bp_location *bl = b->loc;
+  struct ui_out *uiout = current_uiout;
 
   gdb_assert (bl);
   gdb_assert (b->type == bp_hardware_breakpoint);
@@ -8460,22 +8277,12 @@ print_recreate_ranged_breakpoint (struct breakpoint *b, struct ui_file *fp)
 {
   fprintf_unfiltered (fp, "break-range %s, %s", b->addr_string,
                      b->addr_string_range_end);
+  print_recreate_thread (b, fp);
 }
 
 /* The breakpoint_ops structure to be used in ranged breakpoints.  */
 
-static struct breakpoint_ops ranged_breakpoint_ops =
-{
-  NULL, /* insert */
-  NULL, /* remove */
-  breakpoint_hit_ranged_breakpoint,
-  resources_needed_ranged_breakpoint,
-  print_it_ranged_breakpoint,
-  print_one_ranged_breakpoint,
-  print_one_detail_ranged_breakpoint,
-  print_mention_ranged_breakpoint,
-  print_recreate_ranged_breakpoint
-};
+static struct breakpoint_ops ranged_breakpoint_ops;
 
 /* Find the address where the end of the breakpoint range should be
    placed, given the SAL of the end of the range.  This is so that if
@@ -8600,7 +8407,7 @@ break_range_command (char *arg, int from_tty)
 
   end = find_breakpoint_range_end (sal_end);
   if (sal_start.pc > end)
-    error (_("Invalid address range, end preceeds start."));
+    error (_("Invalid address range, end precedes start."));
 
   length = end - sal_start.pc + 1;
   if (length < 0)
@@ -8619,13 +8426,12 @@ break_range_command (char *arg, int from_tty)
 
   /* Now set up the breakpoint.  */
   b = set_raw_breakpoint (get_current_arch (), sal_start,
-                         bp_hardware_breakpoint);
+                         bp_hardware_breakpoint, &ranged_breakpoint_ops);
   set_breakpoint_count (breakpoint_count + 1);
   b->number = breakpoint_count;
   b->disposition = disp_donttouch;
   b->addr_string = addr_string_start;
   b->addr_string_range_end = addr_string_end;
-  b->ops = &ranged_breakpoint_ops;
   b->loc->length = length;
 
   discard_cleanups (cleanup_bkpt);
@@ -8744,15 +8550,67 @@ watchpoint_exp_is_const (const struct expression *exp)
   return 1;
 }
 
+/* Implement the "dtor" breakpoint_ops method for watchpoints.  */
+
+static void
+dtor_watchpoint (struct breakpoint *self)
+{
+  struct watchpoint *w = (struct watchpoint *) self;
+
+  xfree (w->cond_exp);
+  xfree (w->exp);
+  xfree (w->exp_string);
+  xfree (w->exp_string_reparse);
+  value_free (w->val);
+
+  base_breakpoint_ops.dtor (self);
+}
+
+/* Implement the "re_set" breakpoint_ops method for watchpoints.  */
+
+static void
+re_set_watchpoint (struct breakpoint *b)
+{
+  struct watchpoint *w = (struct watchpoint *) b;
+
+  /* Watchpoint can be either on expression using entirely global
+     variables, or it can be on local variables.
+
+     Watchpoints of the first kind are never auto-deleted, and even
+     persist across program restarts.  Since they can use variables
+     from shared libraries, we need to reparse expression as libraries
+     are loaded and unloaded.
+
+     Watchpoints on local variables can also change meaning as result
+     of solib event.  For example, if a watchpoint uses both a local
+     and a global variables in expression, it's a local watchpoint,
+     but unloading of a shared library will make the expression
+     invalid.  This is not a very common use case, but we still
+     re-evaluate expression, to avoid surprises to the user.
+
+     Note that for local watchpoints, we re-evaluate it only if
+     watchpoints frame id is still valid.  If it's not, it means the
+     watchpoint is out of scope and will be deleted soon.  In fact,
+     I'm not sure we'll ever be called in this case.
+
+     If a local watchpoint's frame id is still valid, then
+     w->exp_valid_block is likewise valid, and we can safely use it.
+
+     Don't do anything about disabled watchpoints, since they will be
+     reevaluated again when enabled.  */
+  update_watchpoint (w, 1 /* reparse */);
+}
+
 /* Implement the "insert" breakpoint_ops method for hardware watchpoints.  */
 
 static int
 insert_watchpoint (struct bp_location *bl)
 {
-  int length = bl->owner->exact? 1 : bl->length;
+  struct watchpoint *w = (struct watchpoint *) bl->owner;
+  int length = w->exact ? 1 : bl->length;
 
   return target_insert_watchpoint (bl->address, length, bl->watchpoint_type,
-                                  bl->owner->cond_exp);
+                                  w->cond_exp);
 }
 
 /* Implement the "remove" breakpoint_ops method for hardware watchpoints.  */
@@ -8760,10 +8618,39 @@ insert_watchpoint (struct bp_location *bl)
 static int
 remove_watchpoint (struct bp_location *bl)
 {
-  int length = bl->owner->exact? 1 : bl->length;
+  struct watchpoint *w = (struct watchpoint *) bl->owner;
+  int length = w->exact ? 1 : bl->length;
 
   return target_remove_watchpoint (bl->address, length, bl->watchpoint_type,
-                                  bl->owner->cond_exp);
+                                  w->cond_exp);
+}
+
+static int
+breakpoint_hit_watchpoint (const struct bp_location *bl,
+                          struct address_space *aspace, CORE_ADDR bp_addr)
+{
+  struct breakpoint *b = bl->owner;
+  struct watchpoint *w = (struct watchpoint *) b;
+
+  /* Continuable hardware watchpoints are treated as non-existent if the
+     reason we stopped wasn't a hardware watchpoint (we didn't stop on
+     some data address).  Otherwise gdb won't stop on a break instruction
+     in the code (not from a breakpoint) when a hardware watchpoint has
+     been defined.  Also skip watchpoints which we know did not trigger
+     (did not match the data address).  */
+  if (is_hardware_watchpoint (b)
+      && w->watchpoint_triggered == watch_triggered_no)
+    return 0;
+
+  return 1;
+}
+
+static void
+check_status_watchpoint (bpstat bs)
+{
+  gdb_assert (is_watchpoint (bs->breakpoint_at));
+
+  bpstat_check_watchpoint (bs);
 }
 
 /* Implement the "resources_needed" breakpoint_ops method for
@@ -8772,1664 +8659,2557 @@ remove_watchpoint (struct bp_location *bl)
 static int
 resources_needed_watchpoint (const struct bp_location *bl)
 {
-  int length = bl->owner->exact? 1 : bl->length;
+  struct watchpoint *w = (struct watchpoint *) bl->owner;
+  int length = w->exact? 1 : bl->length;
 
   return target_region_ok_for_hw_watchpoint (bl->address, length);
 }
 
-/* The breakpoint_ops structure to be used in hardware watchpoints.  */
+/* Implement the "works_in_software_mode" breakpoint_ops method for
+   hardware watchpoints.  */
 
-static struct breakpoint_ops watchpoint_breakpoint_ops =
-{
-  insert_watchpoint,
-  remove_watchpoint,
-  NULL, /* breakpoint_hit */
-  resources_needed_watchpoint,
-  NULL, /* print_it */
-  NULL, /* print_one */
-  NULL, /* print_one_detail */
-  NULL, /* print_mention */
-  NULL  /* print_recreate */
-};
+static int
+works_in_software_mode_watchpoint (const struct breakpoint *b)
+{
+  /* Read and access watchpoints only work with hardware support.  */
+  return b->type == bp_watchpoint || b->type == bp_hardware_watchpoint;
+}
 
-/* accessflag:  hw_write:  watch write, 
-                hw_read:   watch read, 
-               hw_access: watch access (read or write) */
-static void
-watch_command_1 (char *arg, int accessflag, int from_tty,
-                int just_location, int internal)
+static enum print_stop_action
+print_it_watchpoint (bpstat bs)
 {
-  volatile struct gdb_exception e;
-  struct breakpoint *b, *scope_breakpoint = NULL;
-  struct expression *exp;
-  struct block *exp_valid_block = NULL, *cond_exp_valid_block = NULL;
-  struct value *val, *mark, *result;
-  struct frame_info *frame;
-  char *exp_start = NULL;
-  char *exp_end = NULL;
-  char *tok, *id_tok_start, *end_tok;
-  int toklen;
-  char *cond_start = NULL;
-  char *cond_end = NULL;
-  enum bptype bp_type;
-  int thread = -1;
-  int pc = 0;
+  struct cleanup *old_chain;
+  struct breakpoint *b;
+  const struct bp_location *bl;
+  struct ui_stream *stb;
+  enum print_stop_action result;
+  struct watchpoint *w;
+  struct ui_out *uiout = current_uiout;
 
-  /* Make sure that we actually have parameters to parse.  */
-  if (arg != NULL && arg[0] != '\0')
-    {
-      toklen = strlen (arg); /* Size of argument list.  */
+  gdb_assert (bs->bp_location_at != NULL);
 
-      /* 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.  */
-      while (tok > arg && (*tok == ' ' || *tok == '\t'))
-        tok--;
-      while (tok > arg && (*tok != ' ' && *tok != '\t'))
-        tok--;
+  bl = bs->bp_location_at;
+  b = bs->breakpoint_at;
+  w = (struct watchpoint *) b;
 
-      /* Points end_tok to the beginning of the last token.  */
-      id_tok_start = tok + 1;
+  stb = ui_out_stream_new (uiout);
+  old_chain = make_cleanup_ui_out_stream_delete (stb);
 
-      /* 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--;
+  switch (b->type)
+    {
+    case bp_watchpoint:
+    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));
+      mention (b);
+      make_cleanup_ui_out_tuple_begin_end (uiout, "value");
+      ui_out_text (uiout, "\nOld value = ");
+      watchpoint_value_print (bs->old_val, stb->stream);
+      ui_out_field_stream (uiout, "old", stb);
+      ui_out_text (uiout, "\nNew value = ");
+      watchpoint_value_print (w->val, stb->stream);
+      ui_out_field_stream (uiout, "new", stb);
+      ui_out_text (uiout, "\n");
+      /* More than one watchpoint may have been triggered.  */
+      result = PRINT_UNKNOWN;
+      break;
 
-      end_tok = tok;
+    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));
+      mention (b);
+      make_cleanup_ui_out_tuple_begin_end (uiout, "value");
+      ui_out_text (uiout, "\nValue = ");
+      watchpoint_value_print (w->val, stb->stream);
+      ui_out_field_stream (uiout, "value", stb);
+      ui_out_text (uiout, "\n");
+      result = PRINT_UNKNOWN;
+      break;
 
-      while (tok > arg && (*tok != ' ' && *tok != '\t'))
-        tok--;
+    case bp_access_watchpoint:
+      if (bs->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));
+         mention (b);
+         make_cleanup_ui_out_tuple_begin_end (uiout, "value");
+         ui_out_text (uiout, "\nOld value = ");
+         watchpoint_value_print (bs->old_val, stb->stream);
+         ui_out_field_stream (uiout, "old", stb);
+         ui_out_text (uiout, "\nNew value = ");
+       }
+      else
+       {
+         mention (b);
+         if (ui_out_is_mi_like_p (uiout))
+           ui_out_field_string
+             (uiout, "reason",
+              async_reason_lookup (EXEC_ASYNC_ACCESS_WATCHPOINT_TRIGGER));
+         make_cleanup_ui_out_tuple_begin_end (uiout, "value");
+         ui_out_text (uiout, "\nValue = ");
+       }
+      watchpoint_value_print (w->val, stb->stream);
+      ui_out_field_stream (uiout, "new", stb);
+      ui_out_text (uiout, "\n");
+      result = PRINT_UNKNOWN;
+      break;
+    default:
+      result = PRINT_UNKNOWN;
+    }
 
-      /* Move the pointer forward to skip the whitespace and
-         calculate the length of the token.  */
-      tok++;
-      toklen = end_tok - tok;
+  do_cleanups (old_chain);
+  return result;
+}
 
-      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';
-        }
-    }
+/* Implement the "print_mention" breakpoint_ops method for hardware
+   watchpoints.  */
 
-  /* Parse the rest of the arguments.  */
-  innermost_block = NULL;
-  exp_start = arg;
-  exp = parse_exp_1 (&arg, 0, 0);
-  exp_end = arg;
-  /* Remove trailing whitespace from the expression before saving it.
-     This makes the eventual display of the expression string a bit
-     prettier.  */
-  while (exp_end > exp_start && (exp_end[-1] == ' ' || exp_end[-1] == '\t'))
-    --exp_end;
+static void
+print_mention_watchpoint (struct breakpoint *b)
+{
+  struct cleanup *ui_out_chain;
+  struct watchpoint *w = (struct watchpoint *) b;
+  struct ui_out *uiout = current_uiout;
 
-  /* Checking if the expression is not constant.  */
-  if (watchpoint_exp_is_const (exp))
+  switch (b->type)
     {
-      int len;
-
-      len = exp_end - exp_start;
-      while (len > 0 && isspace (exp_start[len - 1]))
-       len--;
-      error (_("Cannot watch constant value `%.*s'."), len, exp_start);
+    case bp_watchpoint:
+      ui_out_text (uiout, "Watchpoint ");
+      ui_out_chain = make_cleanup_ui_out_tuple_begin_end (uiout, "wpt");
+      break;
+    case bp_hardware_watchpoint:
+      ui_out_text (uiout, "Hardware watchpoint ");
+      ui_out_chain = make_cleanup_ui_out_tuple_begin_end (uiout, "wpt");
+      break;
+    case bp_read_watchpoint:
+      ui_out_text (uiout, "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, "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."));
     }
 
-  exp_valid_block = innermost_block;
-  mark = value_mark ();
-  fetch_subexp_value (exp, &pc, &val, &result, NULL);
+  ui_out_field_int (uiout, "number", b->number);
+  ui_out_text (uiout, ": ");
+  ui_out_field_string (uiout, "exp", w->exp_string);
+  do_cleanups (ui_out_chain);
+}
 
-  if (just_location)
-    {
-      exp_valid_block = NULL;
-      val = value_addr (result);
-      release_value (val);
-      value_free_to_mark (mark);
-    }
-  else if (val != NULL)
-    release_value (val);
+/* Implement the "print_recreate" breakpoint_ops method for
+   watchpoints.  */
 
-  tok = skip_spaces (arg);
-  end_tok = skip_to_space (tok);
+static void
+print_recreate_watchpoint (struct breakpoint *b, struct ui_file *fp)
+{
+  struct watchpoint *w = (struct watchpoint *) b;
 
-  toklen = end_tok - tok;
-  if (toklen >= 1 && strncmp (tok, "if", toklen) == 0)
+  switch (b->type)
     {
-      struct expression *cond;
+    case bp_watchpoint:
+    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 watchpoint type."));
+    }
 
-      innermost_block = NULL;
-      tok = cond_start = end_tok + 1;
-      cond = parse_exp_1 (&tok, 0, 0);
+  fprintf_unfiltered (fp, " %s", w->exp_string);
+  print_recreate_thread (b, fp);
+}
 
-      /* The watchpoint expression may not be local, but the condition
-        may still be.  E.g.: `watch global if local > 0'.  */
-      cond_exp_valid_block = innermost_block;
+/* The breakpoint_ops structure to be used in hardware watchpoints.  */
 
-      xfree (cond);
-      cond_end = tok;
-    }
-  if (*tok)
-    error (_("Junk at end of command."));
+static struct breakpoint_ops watchpoint_breakpoint_ops;
 
-  if (accessflag == hw_read)
-    bp_type = bp_read_watchpoint;
-  else if (accessflag == hw_access)
-    bp_type = bp_access_watchpoint;
-  else
-    bp_type = bp_hardware_watchpoint;
+/* Implement the "insert" breakpoint_ops method for
+   masked hardware watchpoints.  */
 
-  frame = block_innermost_frame (exp_valid_block);
+static int
+insert_masked_watchpoint (struct bp_location *bl)
+{
+  struct watchpoint *w = (struct watchpoint *) bl->owner;
 
-  /* If the expression is "local", then set up a "watchpoint scope"
-     breakpoint at the point where we've left the scope of the watchpoint
-     expression.  Create the scope breakpoint before the watchpoint, so
-     that we will encounter it first in bpstat_stop_status.  */
-  if (exp_valid_block && frame)
-    {
-      if (frame_id_p (frame_unwind_caller_id (frame)))
-       {
-         scope_breakpoint
-           = create_internal_breakpoint (frame_unwind_caller_arch (frame),
-                                         frame_unwind_caller_pc (frame),
-                                         bp_watchpoint_scope);
+  return target_insert_mask_watchpoint (bl->address, w->hw_wp_mask,
+                                       bl->watchpoint_type);
+}
 
-         scope_breakpoint->enable_state = bp_enabled;
+/* Implement the "remove" breakpoint_ops method for
+   masked hardware watchpoints.  */
 
-         /* Automatically delete the breakpoint when it hits.  */
-         scope_breakpoint->disposition = disp_del;
+static int
+remove_masked_watchpoint (struct bp_location *bl)
+{
+  struct watchpoint *w = (struct watchpoint *) bl->owner;
 
-         /* Only break in the proper frame (help with recursion).  */
-         scope_breakpoint->frame_id = frame_unwind_caller_id (frame);
+  return target_remove_mask_watchpoint (bl->address, w->hw_wp_mask,
+                                       bl->watchpoint_type);
+}
 
-         /* Set the address at which we will stop.  */
-         scope_breakpoint->loc->gdbarch
-           = frame_unwind_caller_arch (frame);
-         scope_breakpoint->loc->requested_address
-           = frame_unwind_caller_pc (frame);
-         scope_breakpoint->loc->address
-           = adjust_breakpoint_address (scope_breakpoint->loc->gdbarch,
-                                        scope_breakpoint->loc->requested_address,
-                                        scope_breakpoint->type);
-       }
-    }
+/* Implement the "resources_needed" breakpoint_ops method for
+   masked hardware watchpoints.  */
 
-  /* Now set up the breakpoint.  */
-  b = set_raw_breakpoint_without_location (NULL, bp_type);
-  b->thread = thread;
-  b->disposition = disp_donttouch;
-  b->exp = exp;
-  b->exp_valid_block = exp_valid_block;
-  b->cond_exp_valid_block = cond_exp_valid_block;
-  if (just_location)
-    {
-      struct type *t = value_type (val);
-      CORE_ADDR addr = value_as_address (val);
-      char *name;
+static int
+resources_needed_masked_watchpoint (const struct bp_location *bl)
+{
+  struct watchpoint *w = (struct watchpoint *) bl->owner;
 
-      t = check_typedef (TYPE_TARGET_TYPE (check_typedef (t)));
-      name = type_to_string (t);
+  return target_masked_watch_num_registers (bl->address, w->hw_wp_mask);
+}
 
-      b->exp_string_reparse = xstrprintf ("* (%s *) %s", name,
-                                         core_addr_to_string (addr));
-      xfree (name);
+/* Implement the "works_in_software_mode" breakpoint_ops method for
+   masked hardware watchpoints.  */
 
-      b->exp_string = xstrprintf ("-location %.*s",
-                                 (int) (exp_end - exp_start), exp_start);
+static int
+works_in_software_mode_masked_watchpoint (const struct breakpoint *b)
+{
+  return 0;
+}
 
-      /* The above expression is in C.  */
-      b->language = language_c;
-    }
-  else
-    b->exp_string = savestring (exp_start, exp_end - exp_start);
-  b->val = val;
-  b->val_valid = 1;
-  b->ops = &watchpoint_breakpoint_ops;
+/* Implement the "print_it" breakpoint_ops method for
+   masked hardware watchpoints.  */
 
-  if (cond_start)
-    b->cond_string = savestring (cond_start, cond_end - cond_start);
-  else
-    b->cond_string = 0;
+static enum print_stop_action
+print_it_masked_watchpoint (bpstat bs)
+{
+  struct breakpoint *b = bs->breakpoint_at;
+  struct ui_out *uiout = current_uiout;
 
-  if (frame)
-    {
-      b->watchpoint_frame = get_frame_id (frame);
-      b->watchpoint_thread = inferior_ptid;
-    }
-  else
-    {
-      b->watchpoint_frame = null_frame_id;
-      b->watchpoint_thread = null_ptid;
-    }
+  /* Masked watchpoints have only one location.  */
+  gdb_assert (b->loc && b->loc->next == NULL);
 
-  if (scope_breakpoint != NULL)
+  switch (b->type)
     {
-      /* The scope breakpoint is related to the watchpoint.  We will
-        need to act on them together.  */
-      b->related_breakpoint = scope_breakpoint;
-      scope_breakpoint->related_breakpoint = b;
-    }
+    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;
 
-  if (!just_location)
-    value_free_to_mark (mark);
+    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;
 
-  TRY_CATCH (e, RETURN_MASK_ALL)
-    {
-      /* Finally update the new watchpoint.  This creates the locations
-        that should be inserted.  */
-      update_watchpoint (b, 1);
-    }
-  if (e.reason < 0)
-    {
-      delete_breakpoint (b);
-      throw_exception (e);
+    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."));
     }
 
-  set_breakpoint_number (internal, b);
-
-  /* Do not mention breakpoints with a negative number, but do
-     notify observers.  */
-  if (!internal)
-    mention (b);
-  observer_notify_breakpoint_created (b);
+  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");
 
-  update_global_location_list (1);
+  /* More than one watchpoint may have been triggered.  */
+  return PRINT_UNKNOWN;
 }
 
-/* Return count of debug registers needed to watch the given expression.
-   If the watchpoint cannot be handled in hardware return zero.  */
+/* Implement the "print_one_detail" breakpoint_ops method for
+   masked hardware watchpoints.  */
 
-static int
-can_use_hardware_watchpoint (struct value *v)
+static void
+print_one_detail_masked_watchpoint (const struct breakpoint *b,
+                                   struct ui_out *uiout)
 {
-  int found_memory_cnt = 0;
-  struct value *head = v;
-
-  /* Did the user specifically forbid us to use hardware watchpoints? */
-  if (!can_use_hw_watchpoints)
-    return 0;
-
-  /* Make sure that the value of the expression depends only upon
-     memory contents, and values computed from them within GDB.  If we
-     find any register references or function calls, we can't use a
-     hardware watchpoint.
-
-     The idea here is that evaluating an expression generates a series
-     of values, one holding the value of every subexpression.  (The
-     expression a*b+c has five subexpressions: a, b, a*b, c, and
-     a*b+c.)  GDB's values hold almost enough information to establish
-     the criteria given above --- they identify memory lvalues,
-     register lvalues, computed values, etcetera.  So we can evaluate
-     the expression, and then scan the chain of values that leaves
-     behind to decide whether we can detect any possible change to the
-     expression's final value using only hardware watchpoints.
-
-     However, I don't think that the values returned by inferior
-     function calls are special in any way.  So this function may not
-     notice that an expression involving an inferior function call
-     can't be watched with hardware watchpoints.  FIXME.  */
-  for (; v; v = value_next (v))
-    {
-      if (VALUE_LVAL (v) == lval_memory)
-       {
-         if (v != head && value_lazy (v))
-           /* A lazy memory lvalue in the chain is one that GDB never
-              needed to fetch; we either just used its address (e.g.,
-              `a' in `a.b') or we never needed it at all (e.g., `a'
-              in `a,b').  This doesn't apply to HEAD; if that is
-              lazy then it was not readable, but watch it anyway.  */
-           ;
-         else
-           {
-             /* Ahh, memory we actually used!  Check if we can cover
-                 it with hardware watchpoints.  */
-             struct type *vtype = check_typedef (value_type (v));
-
-             /* We only watch structs and arrays if user asked for it
-                explicitly, never if they just happen to appear in a
-                middle of some value chain.  */
-             if (v == head
-                 || (TYPE_CODE (vtype) != TYPE_CODE_STRUCT
-                     && TYPE_CODE (vtype) != TYPE_CODE_ARRAY))
-               {
-                 CORE_ADDR vaddr = value_address (v);
-                 int len;
-                 int num_regs;
-
-                 len = (target_exact_watchpoints
-                        && is_scalar_type_recursive (vtype))?
-                   1 : TYPE_LENGTH (value_type (v));
-
-                 num_regs = target_region_ok_for_hw_watchpoint (vaddr, len);
-                 if (!num_regs)
-                   return 0;
-                 else
-                   found_memory_cnt += num_regs;
-               }
-           }
-       }
-      else if (VALUE_LVAL (v) != not_lval
-              && deprecated_value_modifiable (v) == 0)
-       return 0;       /* These are values from the history (e.g., $1).  */
-      else if (VALUE_LVAL (v) == lval_register)
-       return 0;       /* Cannot watch a register with a HW watchpoint.  */
-    }
+  struct watchpoint *w = (struct watchpoint *) b;
 
-  /* The expression itself looks suitable for using a hardware
-     watchpoint, but give the target machine a chance to reject it.  */
-  return found_memory_cnt;
-}
+  /* Masked watchpoints have only one location.  */
+  gdb_assert (b->loc && b->loc->next == NULL);
 
-void
-watch_command_wrapper (char *arg, int from_tty, int internal)
-{
-  watch_command_1 (arg, hw_write, from_tty, 0, internal);
+  ui_out_text (uiout, "\tmask ");
+  ui_out_field_core_addr (uiout, "mask", b->loc->gdbarch, w->hw_wp_mask);
+  ui_out_text (uiout, "\n");
 }
 
-/* A helper function that looks for an argument at the start of a
-   string.  The argument must also either be at the end of the string,
-   or be followed by whitespace.  Returns 1 if it finds the argument,
-   0 otherwise.  If the argument is found, it updates *STR.  */
+/* Implement the "print_mention" breakpoint_ops method for
+   masked hardware watchpoints.  */
 
-static int
-check_for_argument (char **str, char *arg, int arg_len)
+static void
+print_mention_masked_watchpoint (struct breakpoint *b)
 {
-  if (strncmp (*str, arg, arg_len) == 0
-      && ((*str)[arg_len] == '\0' || isspace ((*str)[arg_len])))
+  struct watchpoint *w = (struct watchpoint *) b;
+  struct ui_out *uiout = current_uiout;
+  struct cleanup *ui_out_chain;
+
+  switch (b->type)
     {
-      *str += arg_len;
-      return 1;
+    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."));
     }
-  return 0;
+
+  ui_out_field_int (uiout, "number", b->number);
+  ui_out_text (uiout, ": ");
+  ui_out_field_string (uiout, "exp", w->exp_string);
+  do_cleanups (ui_out_chain);
 }
 
-/* A helper function that looks for the "-location" argument and then
-   calls watch_command_1.  */
+/* Implement the "print_recreate" breakpoint_ops method for
+   masked hardware watchpoints.  */
 
 static void
-watch_maybe_just_location (char *arg, int accessflag, int from_tty)
+print_recreate_masked_watchpoint (struct breakpoint *b, struct ui_file *fp)
 {
-  int just_location = 0;
+  struct watchpoint *w = (struct watchpoint *) b;
+  char tmp[40];
 
-  if (arg
-      && (check_for_argument (&arg, "-location", sizeof ("-location") - 1)
-         || check_for_argument (&arg, "-l", sizeof ("-l") - 1)))
+  switch (b->type)
     {
-      arg = skip_spaces (arg);
-      just_location = 1;
+    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."));
     }
 
-  watch_command_1 (arg, accessflag, from_tty, just_location, 0);
+  sprintf_vma (tmp, w->hw_wp_mask);
+  fprintf_unfiltered (fp, " %s mask 0x%s", w->exp_string, tmp);
+  print_recreate_thread (b, fp);
 }
 
-static void
-watch_command (char *arg, int from_tty)
-{
-  watch_maybe_just_location (arg, hw_write, from_tty);
-}
+/* The breakpoint_ops structure to be used in masked hardware watchpoints.  */
 
-void
-rwatch_command_wrapper (char *arg, int from_tty, int internal)
-{
-  watch_command_1 (arg, hw_read, from_tty, 0, internal);
-}
+static struct breakpoint_ops masked_watchpoint_breakpoint_ops;
 
-static void
-rwatch_command (char *arg, int from_tty)
-{
-  watch_maybe_just_location (arg, hw_read, from_tty);
-}
+/* Tell whether the given watchpoint is a masked hardware watchpoint.  */
 
-void
-awatch_command_wrapper (char *arg, int from_tty, int internal)
+static int
+is_masked_watchpoint (const struct breakpoint *b)
 {
-  watch_command_1 (arg, hw_access, from_tty, 0, internal);
+  return b->ops == &masked_watchpoint_breakpoint_ops;
 }
 
+/* accessflag:  hw_write:  watch write, 
+                hw_read:   watch read, 
+               hw_access: watch access (read or write) */
 static void
-awatch_command (char *arg, int from_tty)
+watch_command_1 (char *arg, int accessflag, int from_tty,
+                int just_location, int internal)
 {
-  watch_maybe_just_location (arg, hw_access, from_tty);
-}
-\f
-
-/* Helper routines for the until_command routine in infcmd.c.  Here
-   because it uses the mechanisms of breakpoints.  */
+  volatile struct gdb_exception e;
+  struct breakpoint *b, *scope_breakpoint = NULL;
+  struct expression *exp;
+  struct block *exp_valid_block = NULL, *cond_exp_valid_block = NULL;
+  struct value *val, *mark, *result;
+  struct frame_info *frame;
+  char *exp_start = NULL;
+  char *exp_end = NULL;
+  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;
+  struct watchpoint *w;
 
-struct until_break_command_continuation_args
-{
-  struct breakpoint *breakpoint;
-  struct breakpoint *breakpoint2;
-  int thread_num;
-};
+  /* Make sure that we actually have parameters to parse.  */
+  if (arg != NULL && arg[0] != '\0')
+    {
+      char *value_start;
 
-/* This function is called by fetch_inferior_event via the
-   cmd_continuation pointer, to complete the until command.  It takes
-   care of cleaning up the temporary breakpoints set up by the until
-   command.  */
-static void
-until_break_command_continuation (void *arg)
-{
-  struct until_break_command_continuation_args *a = arg;
+      /* 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;
 
-  delete_breakpoint (a->breakpoint);
-  if (a->breakpoint2)
-    delete_breakpoint (a->breakpoint2);
-  delete_longjmp_breakpoint (a->thread_num);
-}
+             if (thread != -1)
+               error(_("You can specify only one thread."));
 
-void
-until_break_command (char *arg, int from_tty, int anywhere)
-{
-  struct symtabs_and_lines sals;
-  struct symtab_and_line sal;
-  struct frame_info *frame = get_selected_frame (NULL);
-  struct breakpoint *breakpoint;
-  struct breakpoint *breakpoint2 = NULL;
-  struct cleanup *old_chain;
-  int thread;
-  struct thread_info *tp;
+             /* Extract the thread ID from the next token.  */
+             thread = strtol (value_start, &endp, 0);
 
-  clear_proceed_status ();
+             /* 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);
 
-  /* Set a breakpoint where the user wants it and at return from
-     this function.  */
+             /* 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;
 
-  if (default_breakpoint_valid)
-    sals = decode_line_1 (&arg, 1, default_breakpoint_symtab,
-                         default_breakpoint_line, NULL);
-  else
-    sals = decode_line_1 (&arg, 1, (struct symtab *) NULL, 0, NULL);
+             if (use_mask)
+               error(_("You can specify only one mask."));
 
-  if (sals.nelts != 1)
-    error (_("Couldn't get information on specified line."));
+             use_mask = just_location = 1;
 
-  sal = sals.sals[0];
-  xfree (sals.sals);   /* malloc'd, so freed.  */
+             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;
 
-  if (*arg)
-    error (_("Junk at end of arguments."));
+         /* 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';
+       }
+    }
 
-  resolve_sal_pc (&sal);
-
-  if (anywhere)
-    /* If the user told us to continue until a specified location,
-       we don't specify a frame at which we need to stop.  */
-    breakpoint = set_momentary_breakpoint (get_frame_arch (frame), sal,
-                                          null_frame_id, bp_until);
-  else
-    /* Otherwise, specify the selected frame, because we want to stop
-       only at the very same frame.  */
-    breakpoint = set_momentary_breakpoint (get_frame_arch (frame), sal,
-                                          get_stack_frame_id (frame),
-                                          bp_until);
+  /* Parse the rest of the arguments.  */
+  innermost_block = NULL;
+  exp_start = arg;
+  exp = parse_exp_1 (&arg, 0, 0);
+  exp_end = arg;
+  /* Remove trailing whitespace from the expression before saving it.
+     This makes the eventual display of the expression string a bit
+     prettier.  */
+  while (exp_end > exp_start && (exp_end[-1] == ' ' || exp_end[-1] == '\t'))
+    --exp_end;
 
-  old_chain = make_cleanup_delete_breakpoint (breakpoint);
+  /* Checking if the expression is not constant.  */
+  if (watchpoint_exp_is_const (exp))
+    {
+      int len;
 
-  tp = inferior_thread ();
-  thread = tp->num;
+      len = exp_end - exp_start;
+      while (len > 0 && isspace (exp_start[len - 1]))
+       len--;
+      error (_("Cannot watch constant value `%.*s'."), len, exp_start);
+    }
 
-  /* Keep within the current frame, or in frames called by the current
-     one.  */
+  exp_valid_block = innermost_block;
+  mark = value_mark ();
+  fetch_subexp_value (exp, &pc, &val, &result, NULL);
 
-  if (frame_id_p (frame_unwind_caller_id (frame)))
+  if (just_location)
     {
-      sal = find_pc_line (frame_unwind_caller_pc (frame), 0);
-      sal.pc = frame_unwind_caller_pc (frame);
-      breakpoint2 = set_momentary_breakpoint (frame_unwind_caller_arch (frame),
-                                             sal,
-                                             frame_unwind_caller_id (frame),
-                                             bp_until);
-      make_cleanup_delete_breakpoint (breakpoint2);
+      int ret;
 
-      set_longjmp_breakpoint (tp, frame_unwind_caller_id (frame));
-      make_cleanup (delete_longjmp_breakpoint_cleanup, &thread);
-    }
+      exp_valid_block = NULL;
+      val = value_addr (result);
+      release_value (val);
+      value_free_to_mark (mark);
 
-  proceed (-1, TARGET_SIGNAL_DEFAULT, 0);
+      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);
 
-  /* If we are running asynchronously, and proceed call above has
-     actually managed to start the target, arrange for breakpoints to
-     be deleted when the target stops.  Otherwise, we're already
-     stopped and delete breakpoints via cleanup chain.  */
+  tok = skip_spaces (arg);
+  end_tok = skip_to_space (tok);
 
-  if (target_can_async_p () && is_running (inferior_ptid))
+  toklen = end_tok - tok;
+  if (toklen >= 1 && strncmp (tok, "if", toklen) == 0)
     {
-      struct until_break_command_continuation_args *args;
-      args = xmalloc (sizeof (*args));
+      struct expression *cond;
 
-      args->breakpoint = breakpoint;
-      args->breakpoint2 = breakpoint2;
-      args->thread_num = thread;
+      innermost_block = NULL;
+      tok = cond_start = end_tok + 1;
+      cond = parse_exp_1 (&tok, 0, 0);
 
-      discard_cleanups (old_chain);
-      add_continuation (inferior_thread (),
-                       until_break_command_continuation, args,
-                       xfree);
+      /* The watchpoint expression may not be local, but the condition
+        may still be.  E.g.: `watch global if local > 0'.  */
+      cond_exp_valid_block = innermost_block;
+
+      xfree (cond);
+      cond_end = tok;
     }
+  if (*tok)
+    error (_("Junk at end of command."));
+
+  if (accessflag == hw_read)
+    bp_type = bp_read_watchpoint;
+  else if (accessflag == hw_access)
+    bp_type = bp_access_watchpoint;
   else
-    do_cleanups (old_chain);
-}
+    bp_type = bp_hardware_watchpoint;
 
-/* This function attempts to parse an optional "if <cond>" clause
-   from the arg string.  If one is not found, it returns NULL.
+  frame = block_innermost_frame (exp_valid_block);
 
-   Else, it returns a pointer to the condition string.  (It does not
-   attempt to evaluate the string against a particular block.)  And,
-   it updates arg to point to the first character following the parsed
-   if clause in the arg string.  */
+  /* If the expression is "local", then set up a "watchpoint scope"
+     breakpoint at the point where we've left the scope of the watchpoint
+     expression.  Create the scope breakpoint before the watchpoint, so
+     that we will encounter it first in bpstat_stop_status.  */
+  if (exp_valid_block && frame)
+    {
+      if (frame_id_p (frame_unwind_caller_id (frame)))
+       {
+         scope_breakpoint
+           = create_internal_breakpoint (frame_unwind_caller_arch (frame),
+                                         frame_unwind_caller_pc (frame),
+                                         bp_watchpoint_scope,
+                                         &momentary_breakpoint_ops);
 
-static char *
-ep_parse_optional_if_clause (char **arg)
-{
-  char *cond_string;
+         scope_breakpoint->enable_state = bp_enabled;
 
-  if (((*arg)[0] != 'i') || ((*arg)[1] != 'f') || !isspace ((*arg)[2]))
-    return NULL;
+         /* Automatically delete the breakpoint when it hits.  */
+         scope_breakpoint->disposition = disp_del;
 
-  /* Skip the "if" keyword.  */
-  (*arg) += 2;
+         /* Only break in the proper frame (help with recursion).  */
+         scope_breakpoint->frame_id = frame_unwind_caller_id (frame);
 
-  /* Skip any extra leading whitespace, and record the start of the
-     condition string.  */
-  *arg = skip_spaces (*arg);
-  cond_string = *arg;
+         /* Set the address at which we will stop.  */
+         scope_breakpoint->loc->gdbarch
+           = frame_unwind_caller_arch (frame);
+         scope_breakpoint->loc->requested_address
+           = frame_unwind_caller_pc (frame);
+         scope_breakpoint->loc->address
+           = adjust_breakpoint_address (scope_breakpoint->loc->gdbarch,
+                                        scope_breakpoint->loc->requested_address,
+                                        scope_breakpoint->type);
+       }
+    }
 
-  /* Assume that the condition occupies the remainder of the arg
-     string.  */
-  (*arg) += strlen (cond_string);
+  /* Now set up the breakpoint.  */
 
-  return cond_string;
-}
+  w = XCNEW (struct watchpoint);
+  b = &w->base;
+  if (use_mask)
+    init_raw_breakpoint_without_location (b, NULL, bp_type,
+                                         &masked_watchpoint_breakpoint_ops);
+  else
+    init_raw_breakpoint_without_location (b, NULL, bp_type,
+                                         &watchpoint_breakpoint_ops);
+  b->thread = thread;
+  b->disposition = disp_donttouch;
+  b->pspace = current_program_space;
+  w->exp = exp;
+  w->exp_valid_block = exp_valid_block;
+  w->cond_exp_valid_block = cond_exp_valid_block;
+  if (just_location)
+    {
+      struct type *t = value_type (val);
+      CORE_ADDR addr = value_as_address (val);
+      char *name;
 
-/* Commands to deal with catching events, such as signals, exceptions,
-   process start/exit, etc.  */
+      t = check_typedef (TYPE_TARGET_TYPE (check_typedef (t)));
+      name = type_to_string (t);
 
-typedef enum
-{
-  catch_fork_temporary, catch_vfork_temporary,
-  catch_fork_permanent, catch_vfork_permanent
-}
-catch_fork_kind;
+      w->exp_string_reparse = xstrprintf ("* (%s *) %s", name,
+                                         core_addr_to_string (addr));
+      xfree (name);
 
-static void
-catch_fork_command_1 (char *arg, int from_tty, 
-                     struct cmd_list_element *command)
-{
-  struct gdbarch *gdbarch = get_current_arch ();
-  char *cond_string = NULL;
-  catch_fork_kind fork_kind;
-  int tempflag;
+      w->exp_string = xstrprintf ("-location %.*s",
+                                 (int) (exp_end - exp_start), exp_start);
 
-  fork_kind = (catch_fork_kind) (uintptr_t) get_cmd_context (command);
-  tempflag = (fork_kind == catch_fork_temporary
-             || fork_kind == catch_vfork_temporary);
+      /* The above expression is in C.  */
+      b->language = language_c;
+    }
+  else
+    w->exp_string = savestring (exp_start, exp_end - exp_start);
 
-  if (!arg)
-    arg = "";
-  arg = skip_spaces (arg);
+  if (use_mask)
+    {
+      w->hw_wp_mask = mask;
+    }
+  else
+    {
+      w->val = val;
+      w->val_valid = 1;
+    }
 
-  /* The allowed syntax is:
-     catch [v]fork
-     catch [v]fork if <cond>
+  if (cond_start)
+    b->cond_string = savestring (cond_start, cond_end - cond_start);
+  else
+    b->cond_string = 0;
 
-     First, check if there's an if clause.  */
-  cond_string = ep_parse_optional_if_clause (&arg);
+  if (frame)
+    {
+      w->watchpoint_frame = get_frame_id (frame);
+      w->watchpoint_thread = inferior_ptid;
+    }
+  else
+    {
+      w->watchpoint_frame = null_frame_id;
+      w->watchpoint_thread = null_ptid;
+    }
 
-  if ((*arg != '\0') && !isspace (*arg))
-    error (_("Junk at end of arguments."));
+  if (scope_breakpoint != NULL)
+    {
+      /* The scope breakpoint is related to the watchpoint.  We will
+        need to act on them together.  */
+      b->related_breakpoint = scope_breakpoint;
+      scope_breakpoint->related_breakpoint = b;
+    }
 
-  /* If this target supports it, create a fork or vfork catchpoint
-     and enable reporting of such events.  */
-  switch (fork_kind)
+  if (!just_location)
+    value_free_to_mark (mark);
+
+  TRY_CATCH (e, RETURN_MASK_ALL)
     {
-    case catch_fork_temporary:
-    case catch_fork_permanent:
-      create_fork_vfork_event_catchpoint (gdbarch, tempflag, cond_string,
-                                          &catch_fork_breakpoint_ops);
-      break;
-    case catch_vfork_temporary:
-    case catch_vfork_permanent:
-      create_fork_vfork_event_catchpoint (gdbarch, tempflag, cond_string,
-                                          &catch_vfork_breakpoint_ops);
-      break;
-    default:
-      error (_("unsupported or unknown fork kind; cannot catch it"));
-      break;
+      /* Finally update the new watchpoint.  This creates the locations
+        that should be inserted.  */
+      update_watchpoint (w, 1);
+    }
+  if (e.reason < 0)
+    {
+      delete_breakpoint (b);
+      throw_exception (e);
     }
+
+  install_breakpoint (internal, b);
 }
 
-static void
-catch_exec_command_1 (char *arg, int from_tty, 
-                     struct cmd_list_element *command)
+/* Return count of debug registers needed to watch the given expression.
+   If the watchpoint cannot be handled in hardware return zero.  */
+
+static int
+can_use_hardware_watchpoint (struct value *v)
 {
-  struct gdbarch *gdbarch = get_current_arch ();
-  int tempflag;
-  char *cond_string = NULL;
+  int found_memory_cnt = 0;
+  struct value *head = v;
 
-  tempflag = get_cmd_context (command) == CATCH_TEMPORARY;
+  /* Did the user specifically forbid us to use hardware watchpoints? */
+  if (!can_use_hw_watchpoints)
+    return 0;
 
-  if (!arg)
-    arg = "";
-  arg = skip_spaces (arg);
+  /* Make sure that the value of the expression depends only upon
+     memory contents, and values computed from them within GDB.  If we
+     find any register references or function calls, we can't use a
+     hardware watchpoint.
 
-  /* The allowed syntax is:
-     catch exec
-     catch exec if <cond>
+     The idea here is that evaluating an expression generates a series
+     of values, one holding the value of every subexpression.  (The
+     expression a*b+c has five subexpressions: a, b, a*b, c, and
+     a*b+c.)  GDB's values hold almost enough information to establish
+     the criteria given above --- they identify memory lvalues,
+     register lvalues, computed values, etcetera.  So we can evaluate
+     the expression, and then scan the chain of values that leaves
+     behind to decide whether we can detect any possible change to the
+     expression's final value using only hardware watchpoints.
 
-     First, check if there's an if clause.  */
-  cond_string = ep_parse_optional_if_clause (&arg);
+     However, I don't think that the values returned by inferior
+     function calls are special in any way.  So this function may not
+     notice that an expression involving an inferior function call
+     can't be watched with hardware watchpoints.  FIXME.  */
+  for (; v; v = value_next (v))
+    {
+      if (VALUE_LVAL (v) == lval_memory)
+       {
+         if (v != head && value_lazy (v))
+           /* A lazy memory lvalue in the chain is one that GDB never
+              needed to fetch; we either just used its address (e.g.,
+              `a' in `a.b') or we never needed it at all (e.g., `a'
+              in `a,b').  This doesn't apply to HEAD; if that is
+              lazy then it was not readable, but watch it anyway.  */
+           ;
+         else
+           {
+             /* Ahh, memory we actually used!  Check if we can cover
+                 it with hardware watchpoints.  */
+             struct type *vtype = check_typedef (value_type (v));
 
-  if ((*arg != '\0') && !isspace (*arg))
-    error (_("Junk at end of arguments."));
+             /* We only watch structs and arrays if user asked for it
+                explicitly, never if they just happen to appear in a
+                middle of some value chain.  */
+             if (v == head
+                 || (TYPE_CODE (vtype) != TYPE_CODE_STRUCT
+                     && TYPE_CODE (vtype) != TYPE_CODE_ARRAY))
+               {
+                 CORE_ADDR vaddr = value_address (v);
+                 int len;
+                 int num_regs;
 
-  /* If this target supports it, create an exec catchpoint
-     and enable reporting of such events.  */
-  create_catchpoint (gdbarch, tempflag, cond_string,
-                    &catch_exec_breakpoint_ops);
+                 len = (target_exact_watchpoints
+                        && is_scalar_type_recursive (vtype))?
+                   1 : TYPE_LENGTH (value_type (v));
+
+                 num_regs = target_region_ok_for_hw_watchpoint (vaddr, len);
+                 if (!num_regs)
+                   return 0;
+                 else
+                   found_memory_cnt += num_regs;
+               }
+           }
+       }
+      else if (VALUE_LVAL (v) != not_lval
+              && deprecated_value_modifiable (v) == 0)
+       return 0;       /* These are values from the history (e.g., $1).  */
+      else if (VALUE_LVAL (v) == lval_register)
+       return 0;       /* Cannot watch a register with a HW watchpoint.  */
+    }
+
+  /* The expression itself looks suitable for using a hardware
+     watchpoint, but give the target machine a chance to reject it.  */
+  return found_memory_cnt;
 }
 
-static enum print_stop_action
-print_it_exception_catchpoint (struct breakpoint *b)
+void
+watch_command_wrapper (char *arg, int from_tty, int internal)
 {
-  int bp_temp, bp_throw;
+  watch_command_1 (arg, hw_write, from_tty, 0, internal);
+}
 
-  annotate_catchpoint (b->number);
+/* A helper function that looks for an argument at the start of a
+   string.  The argument must also either be at the end of the string,
+   or be followed by whitespace.  Returns 1 if it finds the argument,
+   0 otherwise.  If the argument is found, it updates *STR.  */
 
-  bp_throw = strstr (b->addr_string, "throw") != NULL;
-  if (b->loc->address != b->loc->requested_address)
-    breakpoint_adjustment_warning (b->loc->requested_address,
-                                  b->loc->address,
-                                  b->number, 1);
-  bp_temp = b->disposition == disp_del;
-  ui_out_text (uiout, 
-              bp_temp ? "Temporary catchpoint "
-                      : "Catchpoint ");
-  if (!ui_out_is_mi_like_p (uiout))
-    ui_out_field_int (uiout, "bkptno", b->number);
-  ui_out_text (uiout,
-              bp_throw ? " (exception thrown), "
-                       : " (exception caught), ");
-  if (ui_out_is_mi_like_p (uiout))
+static int
+check_for_argument (char **str, char *arg, int arg_len)
+{
+  if (strncmp (*str, arg, arg_len) == 0
+      && ((*str)[arg_len] == '\0' || isspace ((*str)[arg_len])))
     {
-      ui_out_field_string (uiout, "reason", 
-                          async_reason_lookup (EXEC_ASYNC_BREAKPOINT_HIT));
-      ui_out_field_string (uiout, "disp", bpdisp_text (b->disposition));
-      ui_out_field_int (uiout, "bkptno", b->number);
+      *str += arg_len;
+      return 1;
     }
-  return PRINT_SRC_AND_LOC;
+  return 0;
 }
 
+/* A helper function that looks for the "-location" argument and then
+   calls watch_command_1.  */
+
 static void
-print_one_exception_catchpoint (struct breakpoint *b, 
-                               struct bp_location **last_loc)
+watch_maybe_just_location (char *arg, int accessflag, int from_tty)
 {
-  struct value_print_options opts;
+  int just_location = 0;
 
-  get_user_print_options (&opts);
-  if (opts.addressprint)
+  if (arg
+      && (check_for_argument (&arg, "-location", sizeof ("-location") - 1)
+         || check_for_argument (&arg, "-l", sizeof ("-l") - 1)))
     {
-      annotate_field (4);
-      if (b->loc == NULL || b->loc->shlib_disabled)
-       ui_out_field_string (uiout, "addr", "<PENDING>");
-      else
-       ui_out_field_core_addr (uiout, "addr",
-                               b->loc->gdbarch, b->loc->address);
+      arg = skip_spaces (arg);
+      just_location = 1;
     }
-  annotate_field (5);
-  if (b->loc)
-    *last_loc = b->loc;
-  if (strstr (b->addr_string, "throw") != NULL)
-    ui_out_field_string (uiout, "what", "exception throw");
-  else
-    ui_out_field_string (uiout, "what", "exception catch");
-}
-
-static void
-print_mention_exception_catchpoint (struct breakpoint *b)
-{
-  int bp_temp;
-  int bp_throw;
 
-  bp_temp = b->disposition == disp_del;
-  bp_throw = strstr (b->addr_string, "throw") != NULL;
-  ui_out_text (uiout, bp_temp ? _("Temporary catchpoint ")
-                             : _("Catchpoint "));
-  ui_out_field_int (uiout, "bkptno", b->number);
-  ui_out_text (uiout, bp_throw ? _(" (throw)")
-                              : _(" (catch)"));
+  watch_command_1 (arg, accessflag, from_tty, just_location, 0);
 }
 
-/* Implement the "print_recreate" breakpoint_ops method for throw and
-   catch catchpoints.  */
-
 static void
-print_recreate_exception_catchpoint (struct breakpoint *b, 
-                                    struct ui_file *fp)
+watch_command (char *arg, int from_tty)
 {
-  int bp_temp;
-  int bp_throw;
-
-  bp_temp = b->disposition == disp_del;
-  bp_throw = strstr (b->addr_string, "throw") != NULL;
-  fprintf_unfiltered (fp, bp_temp ? "tcatch " : "catch ");
-  fprintf_unfiltered (fp, bp_throw ? "throw" : "catch");
+  watch_maybe_just_location (arg, hw_write, from_tty);
 }
 
-static struct breakpoint_ops gnu_v3_exception_catchpoint_ops = {
-  NULL, /* insert */
-  NULL, /* remove */
-  NULL, /* breakpoint_hit */
-  NULL, /* resources_needed */
-  print_it_exception_catchpoint,
-  print_one_exception_catchpoint,
-  NULL, /* print_one_detail */
-  print_mention_exception_catchpoint,
-  print_recreate_exception_catchpoint
-};
-
-static int
-handle_gnu_v3_exceptions (int tempflag, char *cond_string,
-                         enum exception_event_kind ex_event, int from_tty)
+void
+rwatch_command_wrapper (char *arg, int from_tty, int internal)
 {
-  char *trigger_func_name;
-  if (ex_event == EX_EVENT_CATCH)
-    trigger_func_name = "__cxa_begin_catch";
-  else
-    trigger_func_name = "__cxa_throw";
-
-  create_breakpoint (get_current_arch (),
-                    trigger_func_name, cond_string, -1,
-                    0 /* condition and thread are valid.  */,
-                    tempflag, bp_breakpoint,
-                    0,
-                    AUTO_BOOLEAN_TRUE /* pending */,
-                    &gnu_v3_exception_catchpoint_ops, from_tty,
-                    1 /* enabled */,
-                    0 /* internal */);
-
-  return 1;
+  watch_command_1 (arg, hw_read, from_tty, 0, internal);
 }
 
-/* Deal with "catch catch" and "catch throw" commands.  */
-
 static void
-catch_exception_command_1 (enum exception_event_kind ex_event, char *arg,
-                          int tempflag, int from_tty)
+rwatch_command (char *arg, int from_tty)
 {
-  char *cond_string = NULL;
-
-  if (!arg)
-    arg = "";
-  arg = skip_spaces (arg);
-
-  cond_string = ep_parse_optional_if_clause (&arg);
-
-  if ((*arg != '\0') && !isspace (*arg))
-    error (_("Junk at end of arguments."));
-
-  if (ex_event != EX_EVENT_THROW
-      && ex_event != EX_EVENT_CATCH)
-    error (_("Unsupported or unknown exception event; cannot catch it"));
-
-  if (handle_gnu_v3_exceptions (tempflag, cond_string, ex_event, from_tty))
-    return;
-
-  warning (_("Unsupported with this platform/compiler combination."));
+  watch_maybe_just_location (arg, hw_read, from_tty);
 }
 
-/* Implementation of "catch catch" command.  */
-
-static void
-catch_catch_command (char *arg, int from_tty, struct cmd_list_element *command)
+void
+awatch_command_wrapper (char *arg, int from_tty, int internal)
 {
-  int tempflag = get_cmd_context (command) == CATCH_TEMPORARY;
-
-  catch_exception_command_1 (EX_EVENT_CATCH, arg, tempflag, from_tty);
+  watch_command_1 (arg, hw_access, from_tty, 0, internal);
 }
 
-/* Implementation of "catch throw" command.  */
-
 static void
-catch_throw_command (char *arg, int from_tty, struct cmd_list_element *command)
+awatch_command (char *arg, int from_tty)
 {
-  int tempflag = get_cmd_context (command) == CATCH_TEMPORARY;
-
-  catch_exception_command_1 (EX_EVENT_THROW, arg, tempflag, from_tty);
+  watch_maybe_just_location (arg, hw_access, from_tty);
 }
+\f
 
-/* Create a breakpoint struct for Ada exception catchpoints.  */
+/* Helper routines for the until_command routine in infcmd.c.  Here
+   because it uses the mechanisms of breakpoints.  */
 
-static void
-create_ada_exception_breakpoint (struct gdbarch *gdbarch,
-                                struct symtab_and_line sal,
-                                 char *addr_string,
-                                 char *exp_string,
-                                 char *cond_string,
-                                 struct expression *cond,
-                                 struct breakpoint_ops *ops,
-                                 int tempflag,
-                                 int from_tty)
+struct until_break_command_continuation_args
 {
-  struct breakpoint *b;
+  struct breakpoint *breakpoint;
+  struct breakpoint *breakpoint2;
+  int thread_num;
+};
 
-  if (from_tty)
-    {
-      struct gdbarch *loc_gdbarch = get_sal_arch (sal);
-      if (!loc_gdbarch)
-       loc_gdbarch = gdbarch;
+/* This function is called by fetch_inferior_event via the
+   cmd_continuation pointer, to complete the until command.  It takes
+   care of cleaning up the temporary breakpoints set up by the until
+   command.  */
+static void
+until_break_command_continuation (void *arg, int err)
+{
+  struct until_break_command_continuation_args *a = arg;
 
-      describe_other_breakpoints (loc_gdbarch,
-                                 sal.pspace, sal.pc, sal.section, -1);
-      /* FIXME: brobecker/2006-12-28: Actually, re-implement a special
-         version for exception catchpoints, because two catchpoints
-         used for different exception names will use the same address.
-         In this case, a "breakpoint ... also set at..." warning is
-         unproductive.  Besides, the warning phrasing is also a bit
-         inapropriate, we should use the word catchpoint, and tell
-         the user what type of catchpoint it is.  The above is good
-         enough for now, though.  */
-    }
+  delete_breakpoint (a->breakpoint);
+  if (a->breakpoint2)
+    delete_breakpoint (a->breakpoint2);
+  delete_longjmp_breakpoint (a->thread_num);
+}
 
-  b = set_raw_breakpoint (gdbarch, sal, bp_breakpoint);
-  set_breakpoint_count (breakpoint_count + 1);
+void
+until_break_command (char *arg, int from_tty, int anywhere)
+{
+  struct symtabs_and_lines sals;
+  struct symtab_and_line sal;
+  struct frame_info *frame = get_selected_frame (NULL);
+  struct breakpoint *breakpoint;
+  struct breakpoint *breakpoint2 = NULL;
+  struct cleanup *old_chain;
+  int thread;
+  struct thread_info *tp;
 
-  b->enable_state = bp_enabled;
-  b->disposition = tempflag ? disp_del : disp_donttouch;
-  b->number = breakpoint_count;
-  b->ignore_count = 0;
-  b->loc->cond = cond;
-  b->addr_string = addr_string;
-  b->language = language_ada;
-  b->cond_string = cond_string;
-  b->exp_string = exp_string;
-  b->thread = -1;
-  b->ops = ops;
+  clear_proceed_status ();
 
-  mention (b);
-  observer_notify_breakpoint_created (b);
-  update_global_location_list (1);
-}
+  /* Set a breakpoint where the user wants it and at return from
+     this function.  */
 
-/* Implement the "catch exception" command.  */
+  if (default_breakpoint_valid)
+    sals = decode_line_1 (&arg, 1, default_breakpoint_symtab,
+                         default_breakpoint_line, NULL);
+  else
+    sals = decode_line_1 (&arg, 1, (struct symtab *) NULL, 0, NULL);
 
-static void
-catch_ada_exception_command (char *arg, int from_tty,
-                            struct cmd_list_element *command)
-{
-  struct gdbarch *gdbarch = get_current_arch ();
-  int tempflag;
-  struct symtab_and_line sal;
-  char *addr_string = NULL;
-  char *exp_string = NULL;
-  char *cond_string = NULL;
-  struct expression *cond = NULL;
-  struct breakpoint_ops *ops = NULL;
+  if (sals.nelts != 1)
+    error (_("Couldn't get information on specified line."));
 
-  tempflag = get_cmd_context (command) == CATCH_TEMPORARY;
+  sal = sals.sals[0];
+  xfree (sals.sals);   /* malloc'd, so freed.  */
 
-  if (!arg)
-    arg = "";
-  sal = ada_decode_exception_location (arg, &addr_string, &exp_string,
-                                       &cond_string, &cond, &ops);
-  create_ada_exception_breakpoint (gdbarch, sal, addr_string, exp_string,
-                                   cond_string, cond, ops, tempflag,
-                                   from_tty);
-}
+  if (*arg)
+    error (_("Junk at end of arguments."));
 
-/* Cleanup function for a syscall filter list.  */
-static void
-clean_up_filters (void *arg)
-{
-  VEC(int) *iter = *(VEC(int) **) arg;
-  VEC_free (int, iter);
-}
+  resolve_sal_pc (&sal);
 
-/* Splits the argument using space as delimiter.  Returns an xmalloc'd
-   filter list, or NULL if no filtering is required.  */
-static VEC(int) *
-catch_syscall_split_args (char *arg)
-{
-  VEC(int) *result = NULL;
-  struct cleanup *cleanup = make_cleanup (clean_up_filters, &result);
+  if (anywhere)
+    /* If the user told us to continue until a specified location,
+       we don't specify a frame at which we need to stop.  */
+    breakpoint = set_momentary_breakpoint (get_frame_arch (frame), sal,
+                                          null_frame_id, bp_until);
+  else
+    /* Otherwise, specify the selected frame, because we want to stop
+       only at the very same frame.  */
+    breakpoint = set_momentary_breakpoint (get_frame_arch (frame), sal,
+                                          get_stack_frame_id (frame),
+                                          bp_until);
 
-  while (*arg != '\0')
+  old_chain = make_cleanup_delete_breakpoint (breakpoint);
+
+  tp = inferior_thread ();
+  thread = tp->num;
+
+  /* Keep within the current frame, or in frames called by the current
+     one.  */
+
+  if (frame_id_p (frame_unwind_caller_id (frame)))
     {
-      int i, syscall_number;
-      char *endptr;
-      char cur_name[128];
-      struct syscall s;
+      sal = find_pc_line (frame_unwind_caller_pc (frame), 0);
+      sal.pc = frame_unwind_caller_pc (frame);
+      breakpoint2 = set_momentary_breakpoint (frame_unwind_caller_arch (frame),
+                                             sal,
+                                             frame_unwind_caller_id (frame),
+                                             bp_until);
+      make_cleanup_delete_breakpoint (breakpoint2);
 
-      /* Skip whitespace.  */
-      while (isspace (*arg))
-       arg++;
+      set_longjmp_breakpoint (tp, frame_unwind_caller_id (frame));
+      make_cleanup (delete_longjmp_breakpoint_cleanup, &thread);
+    }
 
-      for (i = 0; i < 127 && arg[i] && !isspace (arg[i]); ++i)
-       cur_name[i] = arg[i];
-      cur_name[i] = '\0';
-      arg += i;
+  proceed (-1, TARGET_SIGNAL_DEFAULT, 0);
 
-      /* Check if the user provided a syscall name or a number.  */
-      syscall_number = (int) strtol (cur_name, &endptr, 0);
-      if (*endptr == '\0')
-       get_syscall_by_number (syscall_number, &s);
-      else
-       {
-         /* We have a name.  Let's check if it's valid and convert it
-            to a number.  */
-         get_syscall_by_name (cur_name, &s);
+  /* If we are running asynchronously, and proceed call above has
+     actually managed to start the target, arrange for breakpoints to
+     be deleted when the target stops.  Otherwise, we're already
+     stopped and delete breakpoints via cleanup chain.  */
 
-         if (s.number == UNKNOWN_SYSCALL)
-           /* Here we have to issue an error instead of a warning,
-              because GDB cannot do anything useful if there's no
-              syscall number to be caught.  */
-           error (_("Unknown syscall name '%s'."), cur_name);
-       }
+  if (target_can_async_p () && is_running (inferior_ptid))
+    {
+      struct until_break_command_continuation_args *args;
+      args = xmalloc (sizeof (*args));
 
-      /* Ok, it's valid.  */
-      VEC_safe_push (int, result, s.number);
-    }
+      args->breakpoint = breakpoint;
+      args->breakpoint2 = breakpoint2;
+      args->thread_num = thread;
 
-  discard_cleanups (cleanup);
-  return result;
+      discard_cleanups (old_chain);
+      add_continuation (inferior_thread (),
+                       until_break_command_continuation, args,
+                       xfree);
+    }
+  else
+    do_cleanups (old_chain);
 }
 
-/* Implement the "catch syscall" command.  */
+/* This function attempts to parse an optional "if <cond>" clause
+   from the arg string.  If one is not found, it returns NULL.
 
-static void
-catch_syscall_command_1 (char *arg, int from_tty, 
-                        struct cmd_list_element *command)
-{
-  int tempflag;
-  VEC(int) *filter;
-  struct syscall s;
-  struct gdbarch *gdbarch = get_current_arch ();
+   Else, it returns a pointer to the condition string.  (It does not
+   attempt to evaluate the string against a particular block.)  And,
+   it updates arg to point to the first character following the parsed
+   if clause in the arg string.  */
 
-  /* Checking if the feature if supported.  */
-  if (gdbarch_get_syscall_number_p (gdbarch) == 0)
-    error (_("The feature 'catch syscall' is not supported on \
-this architecture yet."));
+static char *
+ep_parse_optional_if_clause (char **arg)
+{
+  char *cond_string;
 
-  tempflag = get_cmd_context (command) == CATCH_TEMPORARY;
+  if (((*arg)[0] != 'i') || ((*arg)[1] != 'f') || !isspace ((*arg)[2]))
+    return NULL;
 
-  arg = skip_spaces (arg);
+  /* Skip the "if" keyword.  */
+  (*arg) += 2;
 
-  /* We need to do this first "dummy" translation in order
-     to get the syscall XML file loaded or, most important,
-     to display a warning to the user if there's no XML file
-     for his/her architecture.  */
-  get_syscall_by_number (0, &s);
+  /* Skip any extra leading whitespace, and record the start of the
+     condition string.  */
+  *arg = skip_spaces (*arg);
+  cond_string = *arg;
 
-  /* The allowed syntax is:
-     catch syscall
-     catch syscall <name | number> [<name | number> ... <name | number>]
+  /* Assume that the condition occupies the remainder of the arg
+     string.  */
+  (*arg) += strlen (cond_string);
 
-     Let's check if there's a syscall name.  */
+  return cond_string;
+}
 
-  if (arg != NULL)
-    filter = catch_syscall_split_args (arg);
-  else
-    filter = NULL;
+/* Commands to deal with catching events, such as signals, exceptions,
+   process start/exit, etc.  */
 
-  create_syscall_event_catchpoint (tempflag, filter,
-                                  &catch_syscall_breakpoint_ops);
+typedef enum
+{
+  catch_fork_temporary, catch_vfork_temporary,
+  catch_fork_permanent, catch_vfork_permanent
 }
-
-/* Implement the "catch assert" command.  */
+catch_fork_kind;
 
 static void
-catch_assert_command (char *arg, int from_tty,
+catch_fork_command_1 (char *arg, int from_tty, 
                      struct cmd_list_element *command)
 {
   struct gdbarch *gdbarch = get_current_arch ();
+  char *cond_string = NULL;
+  catch_fork_kind fork_kind;
   int tempflag;
-  struct symtab_and_line sal;
-  char *addr_string = NULL;
-  struct breakpoint_ops *ops = NULL;
 
-  tempflag = get_cmd_context (command) == CATCH_TEMPORARY;
+  fork_kind = (catch_fork_kind) (uintptr_t) get_cmd_context (command);
+  tempflag = (fork_kind == catch_fork_temporary
+             || fork_kind == catch_vfork_temporary);
 
   if (!arg)
     arg = "";
-  sal = ada_decode_assert_location (arg, &addr_string, &ops);
-  create_ada_exception_breakpoint (gdbarch, sal, addr_string, NULL, NULL, NULL,
-                                  ops, tempflag, from_tty);
-}
+  arg = skip_spaces (arg);
 
-static void
-catch_command (char *arg, int from_tty)
-{
-  error (_("Catch requires an event name."));
-}
-\f
+  /* The allowed syntax is:
+     catch [v]fork
+     catch [v]fork if <cond>
 
-static void
-tcatch_command (char *arg, int from_tty)
-{
-  error (_("Catch requires an event name."));
-}
-
-/* Delete breakpoints by address or line.  */
+     First, check if there's an if clause.  */
+  cond_string = ep_parse_optional_if_clause (&arg);
 
-static void
-clear_command (char *arg, int from_tty)
-{
-  struct breakpoint *b;
-  VEC(breakpoint_p) *found = 0;
-  int ix;
-  int default_match;
-  struct symtabs_and_lines sals;
-  struct symtab_and_line sal;
-  int i;
+  if ((*arg != '\0') && !isspace (*arg))
+    error (_("Junk at end of arguments."));
 
-  if (arg)
+  /* If this target supports it, create a fork or vfork catchpoint
+     and enable reporting of such events.  */
+  switch (fork_kind)
     {
-      sals = decode_line_spec (arg, 1);
-      default_match = 0;
+    case catch_fork_temporary:
+    case catch_fork_permanent:
+      create_fork_vfork_event_catchpoint (gdbarch, tempflag, cond_string,
+                                          &catch_fork_breakpoint_ops);
+      break;
+    case catch_vfork_temporary:
+    case catch_vfork_permanent:
+      create_fork_vfork_event_catchpoint (gdbarch, tempflag, cond_string,
+                                          &catch_vfork_breakpoint_ops);
+      break;
+    default:
+      error (_("unsupported or unknown fork kind; cannot catch it"));
+      break;
     }
-  else
-    {
-      sals.sals = (struct symtab_and_line *)
-       xmalloc (sizeof (struct symtab_and_line));
-      make_cleanup (xfree, sals.sals);
-      init_sal (&sal);         /* Initialize to zeroes.  */
-      sal.line = default_breakpoint_line;
-      sal.symtab = default_breakpoint_symtab;
-      sal.pc = default_breakpoint_address;
-      sal.pspace = default_breakpoint_pspace;
-      if (sal.symtab == 0)
-       error (_("No source file specified."));
-
-      sals.sals[0] = sal;
-      sals.nelts = 1;
+}
 
-      default_match = 1;
-    }
+static void
+catch_exec_command_1 (char *arg, int from_tty, 
+                     struct cmd_list_element *command)
+{
+  struct exec_catchpoint *c;
+  struct gdbarch *gdbarch = get_current_arch ();
+  int tempflag;
+  char *cond_string = NULL;
 
-  /* We don't call resolve_sal_pc here.  That's not as bad as it
-     seems, because all existing breakpoints typically have both
-     file/line and pc set.  So, if clear is given file/line, we can
-     match this to existing breakpoint without obtaining pc at all.
+  tempflag = get_cmd_context (command) == CATCH_TEMPORARY;
 
-     We only support clearing given the address explicitly 
-     present in breakpoint table.  Say, we've set breakpoint 
-     at file:line.  There were several PC values for that file:line,
-     due to optimization, all in one block.
+  if (!arg)
+    arg = "";
+  arg = skip_spaces (arg);
 
-     We've picked one PC value.  If "clear" is issued with another
-     PC corresponding to the same file:line, the breakpoint won't
-     be cleared.  We probably can still clear the breakpoint, but 
-     since the other PC value is never presented to user, user
-     can only find it by guessing, and it does not seem important
-     to support that.  */
+  /* The allowed syntax is:
+     catch exec
+     catch exec if <cond>
 
-  /* For each line spec given, delete bps which correspond to it.  Do
-     it in two passes, solely to preserve the current behavior that
-     from_tty is forced true if we delete more than one
-     breakpoint.  */
+     First, check if there's an if clause.  */
+  cond_string = ep_parse_optional_if_clause (&arg);
 
-  found = NULL;
-  for (i = 0; i < sals.nelts; i++)
-    {
-      /* If exact pc given, clear bpts at that pc.
-         If line given (pc == 0), clear all bpts on specified line.
-         If defaulting, clear all bpts on default line
-         or at default pc.
+  if ((*arg != '\0') && !isspace (*arg))
+    error (_("Junk at end of arguments."));
 
-         defaulting    sal.pc != 0    tests to do
+  c = XNEW (struct exec_catchpoint);
+  init_catchpoint (&c->base, gdbarch, tempflag, cond_string,
+                  &catch_exec_breakpoint_ops);
+  c->exec_pathname = NULL;
 
-         0              1             pc
-         1              1             pc _and_ line
-         0              0             line
-         1              0             <can't happen> */
+  install_breakpoint (0, &c->base);
+}
 
-      sal = sals.sals[i];
+static enum print_stop_action
+print_it_exception_catchpoint (bpstat bs)
+{
+  struct ui_out *uiout = current_uiout;
+  struct breakpoint *b = bs->breakpoint_at;
+  int bp_temp, bp_throw;
 
-      /* Find all matching breakpoints and add them to 'found'.  */
-      ALL_BREAKPOINTS (b)
-       {
-         int match = 0;
-         /* Are we going to delete b?  */
-         if (b->type != bp_none && !is_watchpoint (b))
-           {
-             struct bp_location *loc = b->loc;
-             for (; loc; loc = loc->next)
-               {
-                 int pc_match = sal.pc
-                   && (loc->pspace == sal.pspace)
-                   && (loc->address == sal.pc)
-                   && (!section_is_overlay (loc->section)
-                       || loc->section == sal.section);
-                 int line_match = ((default_match || (0 == sal.pc))
-                                   && b->source_file != NULL
-                                   && sal.symtab != NULL
-                                   && sal.pspace == loc->pspace
-                                   && filename_cmp (b->source_file,
-                                                    sal.symtab->filename) == 0
-                                   && b->line_number == sal.line);
-                 if (pc_match || line_match)
-                   {
-                     match = 1;
-                     break;
-                   }
-               }
-           }
+  annotate_catchpoint (b->number);
 
-         if (match)
-           VEC_safe_push(breakpoint_p, found, b);
-       }
-    }
-  /* Now go thru the 'found' chain and delete them.  */
-  if (VEC_empty(breakpoint_p, found))
+  bp_throw = strstr (b->addr_string, "throw") != NULL;
+  if (b->loc->address != b->loc->requested_address)
+    breakpoint_adjustment_warning (b->loc->requested_address,
+                                  b->loc->address,
+                                  b->number, 1);
+  bp_temp = b->disposition == disp_del;
+  ui_out_text (uiout, 
+              bp_temp ? "Temporary catchpoint "
+                      : "Catchpoint ");
+  if (!ui_out_is_mi_like_p (uiout))
+    ui_out_field_int (uiout, "bkptno", b->number);
+  ui_out_text (uiout,
+              bp_throw ? " (exception thrown), "
+                       : " (exception caught), ");
+  if (ui_out_is_mi_like_p (uiout))
     {
-      if (arg)
-       error (_("No breakpoint at %s."), arg);
-      else
-       error (_("No breakpoint at this line."));
+      ui_out_field_string (uiout, "reason", 
+                          async_reason_lookup (EXEC_ASYNC_BREAKPOINT_HIT));
+      ui_out_field_string (uiout, "disp", bpdisp_text (b->disposition));
+      ui_out_field_int (uiout, "bkptno", b->number);
     }
+  return PRINT_SRC_AND_LOC;
+}
 
-  if (VEC_length(breakpoint_p, found) > 1)
-    from_tty = 1;      /* Always report if deleted more than one.  */
-  if (from_tty)
-    {
-      if (VEC_length(breakpoint_p, found) == 1)
-       printf_unfiltered (_("Deleted breakpoint "));
-      else
-       printf_unfiltered (_("Deleted breakpoints "));
-    }
-  breakpoints_changed ();
+static void
+print_one_exception_catchpoint (struct breakpoint *b, 
+                               struct bp_location **last_loc)
+{
+  struct value_print_options opts;
+  struct ui_out *uiout = current_uiout;
 
-  for (ix = 0; VEC_iterate(breakpoint_p, found, ix, b); ix++)
+  get_user_print_options (&opts);
+  if (opts.addressprint)
     {
-      if (from_tty)
-       printf_unfiltered ("%d ", b->number);
-      delete_breakpoint (b);
+      annotate_field (4);
+      if (b->loc == NULL || b->loc->shlib_disabled)
+       ui_out_field_string (uiout, "addr", "<PENDING>");
+      else
+       ui_out_field_core_addr (uiout, "addr",
+                               b->loc->gdbarch, b->loc->address);
     }
-  if (from_tty)
-    putchar_unfiltered ('\n');
+  annotate_field (5);
+  if (b->loc)
+    *last_loc = b->loc;
+  if (strstr (b->addr_string, "throw") != NULL)
+    ui_out_field_string (uiout, "what", "exception throw");
+  else
+    ui_out_field_string (uiout, "what", "exception catch");
 }
-\f
-/* Delete breakpoint in BS if they are `delete' breakpoints and
-   all breakpoints that are marked for deletion, whether hit or not.
-   This is called after any breakpoint is hit, or after errors.  */
 
-void
-breakpoint_auto_delete (bpstat bs)
+static void
+print_mention_exception_catchpoint (struct breakpoint *b)
 {
-  struct breakpoint *b, *b_tmp;
-
-  for (; bs; bs = bs->next)
-    if (bs->breakpoint_at
-       && bs->breakpoint_at->disposition == disp_del
-       && bs->stop)
-      delete_breakpoint (bs->breakpoint_at);
+  struct ui_out *uiout = current_uiout;
+  int bp_temp;
+  int bp_throw;
 
-  ALL_BREAKPOINTS_SAFE (b, b_tmp)
-  {
-    if (b->disposition == disp_del_at_next_stop)
-      delete_breakpoint (b);
-  }
+  bp_temp = b->disposition == disp_del;
+  bp_throw = strstr (b->addr_string, "throw") != NULL;
+  ui_out_text (uiout, bp_temp ? _("Temporary catchpoint ")
+                             : _("Catchpoint "));
+  ui_out_field_int (uiout, "bkptno", b->number);
+  ui_out_text (uiout, bp_throw ? _(" (throw)")
+                              : _(" (catch)"));
 }
 
-/* A comparison function for bp_location AP and BP being interfaced to
-   qsort.  Sort elements primarily by their ADDRESS (no matter what
-   does breakpoint_address_is_meaningful say for its OWNER),
-   secondarily by ordering first bp_permanent OWNERed elements and
-   terciarily just ensuring the array is sorted stable way despite
-   qsort being an instable algorithm.  */
+/* Implement the "print_recreate" breakpoint_ops method for throw and
+   catch catchpoints.  */
 
-static int
-bp_location_compare (const void *ap, const void *bp)
+static void
+print_recreate_exception_catchpoint (struct breakpoint *b, 
+                                    struct ui_file *fp)
 {
-  struct bp_location *a = *(void **) ap;
-  struct bp_location *b = *(void **) bp;
-  /* A and B come from existing breakpoints having non-NULL OWNER.  */
-  int a_perm = a->owner->enable_state == bp_permanent;
-  int b_perm = b->owner->enable_state == bp_permanent;
+  int bp_temp;
+  int bp_throw;
 
-  if (a->address != b->address)
-    return (a->address > b->address) - (a->address < b->address);
+  bp_temp = b->disposition == disp_del;
+  bp_throw = strstr (b->addr_string, "throw") != NULL;
+  fprintf_unfiltered (fp, bp_temp ? "tcatch " : "catch ");
+  fprintf_unfiltered (fp, bp_throw ? "throw" : "catch");
+  print_recreate_thread (b, fp);
+}
 
-  /* Sort permanent breakpoints first.  */
-  if (a_perm != b_perm)
-    return (a_perm < b_perm) - (a_perm > b_perm);
+static struct breakpoint_ops gnu_v3_exception_catchpoint_ops;
 
-  /* Make the user-visible order stable across GDB runs.  Locations of
-     the same breakpoint can be sorted in arbitrary order.  */
+static int
+handle_gnu_v3_exceptions (int tempflag, char *cond_string,
+                         enum exception_event_kind ex_event, int from_tty)
+{
+  char *trigger_func_name;
+  if (ex_event == EX_EVENT_CATCH)
+    trigger_func_name = "__cxa_begin_catch";
+  else
+    trigger_func_name = "__cxa_throw";
 
-  if (a->owner->number != b->owner->number)
-    return (a->owner->number > b->owner->number)
-           - (a->owner->number < b->owner->number);
+  create_breakpoint (get_current_arch (),
+                    trigger_func_name, cond_string, -1,
+                    0 /* condition and thread are valid.  */,
+                    tempflag, bp_breakpoint,
+                    0,
+                    AUTO_BOOLEAN_TRUE /* pending */,
+                    &gnu_v3_exception_catchpoint_ops, from_tty,
+                    1 /* enabled */,
+                    0 /* internal */);
 
-  return (a > b) - (a < b);
+  return 1;
 }
 
-/* Set bp_location_placed_address_before_address_max and
-   bp_location_shadow_len_after_address_max according to the current
-   content of the bp_location array.  */
+/* Deal with "catch catch" and "catch throw" commands.  */
 
 static void
-bp_location_target_extensions_update (void)
+catch_exception_command_1 (enum exception_event_kind ex_event, char *arg,
+                          int tempflag, int from_tty)
 {
-  struct bp_location *bl, **blp_tmp;
-
-  bp_location_placed_address_before_address_max = 0;
-  bp_location_shadow_len_after_address_max = 0;
+  char *cond_string = NULL;
 
-  ALL_BP_LOCATIONS (bl, blp_tmp)
-    {
-      CORE_ADDR start, end, addr;
+  if (!arg)
+    arg = "";
+  arg = skip_spaces (arg);
 
-      if (!bp_location_has_shadow (bl))
-       continue;
+  cond_string = ep_parse_optional_if_clause (&arg);
 
-      start = bl->target_info.placed_address;
-      end = start + bl->target_info.shadow_len;
+  if ((*arg != '\0') && !isspace (*arg))
+    error (_("Junk at end of arguments."));
 
-      gdb_assert (bl->address >= start);
-      addr = bl->address - start;
-      if (addr > bp_location_placed_address_before_address_max)
-       bp_location_placed_address_before_address_max = addr;
+  if (ex_event != EX_EVENT_THROW
+      && ex_event != EX_EVENT_CATCH)
+    error (_("Unsupported or unknown exception event; cannot catch it"));
 
-      /* Zero SHADOW_LEN would not pass bp_location_has_shadow.  */
+  if (handle_gnu_v3_exceptions (tempflag, cond_string, ex_event, from_tty))
+    return;
 
-      gdb_assert (bl->address < end);
-      addr = end - bl->address;
-      if (addr > bp_location_shadow_len_after_address_max)
-       bp_location_shadow_len_after_address_max = addr;
-    }
+  warning (_("Unsupported with this platform/compiler combination."));
 }
 
-/* If SHOULD_INSERT is false, do not insert any breakpoint locations
-   into the inferior, only remove already-inserted locations that no
-   longer should be inserted.  Functions that delete a breakpoint or
-   breakpoints should pass false, so that deleting a breakpoint
-   doesn't have the side effect of inserting the locations of other
-   breakpoints that are marked not-inserted, but should_be_inserted
-   returns true on them.
+/* Implementation of "catch catch" command.  */
 
-   This behaviour is useful is situations close to tear-down -- e.g.,
-   after an exec, while the target still has execution, but breakpoint
-   shadows of the previous executable image should *NOT* be restored
-   to the new image; or before detaching, where the target still has
-   execution and wants to delete breakpoints from GDB's lists, and all
-   breakpoints had already been removed from the inferior.  */
+static void
+catch_catch_command (char *arg, int from_tty, struct cmd_list_element *command)
+{
+  int tempflag = get_cmd_context (command) == CATCH_TEMPORARY;
+
+  catch_exception_command_1 (EX_EVENT_CATCH, arg, tempflag, from_tty);
+}
+
+/* Implementation of "catch throw" command.  */
 
 static void
-update_global_location_list (int should_insert)
+catch_throw_command (char *arg, int from_tty, struct cmd_list_element *command)
 {
-  struct breakpoint *b;
-  struct bp_location **locp, *loc;
-  struct cleanup *cleanups;
+  int tempflag = get_cmd_context (command) == CATCH_TEMPORARY;
 
-  /* Used in the duplicates detection below.  When iterating over all
-     bp_locations, points to the first bp_location of a given address.
-     Breakpoints and watchpoints of different types are never
-     duplicates of each other.  Keep one pointer for each type of
-     breakpoint/watchpoint, so we only need to loop over all locations
-     once.  */
-  struct bp_location *bp_loc_first;  /* breakpoint */
-  struct bp_location *wp_loc_first;  /* hardware watchpoint */
-  struct bp_location *awp_loc_first; /* access watchpoint */
-  struct bp_location *rwp_loc_first; /* read watchpoint */
+  catch_exception_command_1 (EX_EVENT_THROW, arg, tempflag, from_tty);
+}
 
-  /* Saved former bp_location array which we compare against the newly
-     built bp_location from the current state of ALL_BREAKPOINTS.  */
-  struct bp_location **old_location, **old_locp;
-  unsigned old_location_count;
+void
+init_ada_exception_breakpoint (struct breakpoint *b,
+                              struct gdbarch *gdbarch,
+                              struct symtab_and_line sal,
+                              char *addr_string,
+                              const struct breakpoint_ops *ops,
+                              int tempflag,
+                              int from_tty)
+{
+  if (from_tty)
+    {
+      struct gdbarch *loc_gdbarch = get_sal_arch (sal);
+      if (!loc_gdbarch)
+       loc_gdbarch = gdbarch;
 
-  old_location = bp_location;
-  old_location_count = bp_location_count;
-  bp_location = NULL;
-  bp_location_count = 0;
-  cleanups = make_cleanup (xfree, old_location);
+      describe_other_breakpoints (loc_gdbarch,
+                                 sal.pspace, sal.pc, sal.section, -1);
+      /* FIXME: brobecker/2006-12-28: Actually, re-implement a special
+         version for exception catchpoints, because two catchpoints
+         used for different exception names will use the same address.
+         In this case, a "breakpoint ... also set at..." warning is
+         unproductive.  Besides, the warning phrasing is also a bit
+         inappropriate, we should use the word catchpoint, and tell
+         the user what type of catchpoint it is.  The above is good
+         enough for now, though.  */
+    }
 
-  ALL_BREAKPOINTS (b)
-    for (loc = b->loc; loc; loc = loc->next)
-      bp_location_count++;
+  init_raw_breakpoint (b, gdbarch, sal, bp_breakpoint, ops);
 
-  bp_location = xmalloc (sizeof (*bp_location) * bp_location_count);
-  locp = bp_location;
-  ALL_BREAKPOINTS (b)
-    for (loc = b->loc; loc; loc = loc->next)
-      *locp++ = loc;
-  qsort (bp_location, bp_location_count, sizeof (*bp_location),
-        bp_location_compare);
+  b->enable_state = bp_enabled;
+  b->disposition = tempflag ? disp_del : disp_donttouch;
+  b->addr_string = addr_string;
+  b->language = language_ada;
+}
 
-  bp_location_target_extensions_update ();
+/* Cleanup function for a syscall filter list.  */
+static void
+clean_up_filters (void *arg)
+{
+  VEC(int) *iter = *(VEC(int) **) arg;
+  VEC_free (int, iter);
+}
 
-  /* Identify bp_location instances that are no longer present in the
-     new list, and therefore should be freed.  Note that it's not
-     necessary that those locations should be removed from inferior --
-     if there's another location at the same address (previously
-     marked as duplicate), we don't need to remove/insert the
-     location.
-     
-     LOCP is kept in sync with OLD_LOCP, each pointing to the current
-     and former bp_location array state respectively.  */
+/* Splits the argument using space as delimiter.  Returns an xmalloc'd
+   filter list, or NULL if no filtering is required.  */
+static VEC(int) *
+catch_syscall_split_args (char *arg)
+{
+  VEC(int) *result = NULL;
+  struct cleanup *cleanup = make_cleanup (clean_up_filters, &result);
 
-  locp = bp_location;
-  for (old_locp = old_location; old_locp < old_location + old_location_count;
-       old_locp++)
+  while (*arg != '\0')
     {
-      struct bp_location *old_loc = *old_locp;
-      struct bp_location **loc2p;
+      int i, syscall_number;
+      char *endptr;
+      char cur_name[128];
+      struct syscall s;
 
-      /* Tells if 'old_loc' is found amoung the new locations.  If
-        not, we have to free it.  */
-      int found_object = 0;
-      /* Tells if the location should remain inserted in the target.  */
-      int keep_in_target = 0;
-      int removed = 0;
+      /* Skip whitespace.  */
+      while (isspace (*arg))
+       arg++;
 
-      /* Skip LOCP entries which will definitely never be needed.
-        Stop either at or being the one matching OLD_LOC.  */
-      while (locp < bp_location + bp_location_count
-            && (*locp)->address < old_loc->address)
-       locp++;
+      for (i = 0; i < 127 && arg[i] && !isspace (arg[i]); ++i)
+       cur_name[i] = arg[i];
+      cur_name[i] = '\0';
+      arg += i;
 
-      for (loc2p = locp;
-          (loc2p < bp_location + bp_location_count
-           && (*loc2p)->address == old_loc->address);
-          loc2p++)
+      /* Check if the user provided a syscall name or a number.  */
+      syscall_number = (int) strtol (cur_name, &endptr, 0);
+      if (*endptr == '\0')
+       get_syscall_by_number (syscall_number, &s);
+      else
        {
-         if (*loc2p == old_loc)
-           {
-             found_object = 1;
-             break;
-           }
+         /* We have a name.  Let's check if it's valid and convert it
+            to a number.  */
+         get_syscall_by_name (cur_name, &s);
+
+         if (s.number == UNKNOWN_SYSCALL)
+           /* Here we have to issue an error instead of a warning,
+              because GDB cannot do anything useful if there's no
+              syscall number to be caught.  */
+           error (_("Unknown syscall name '%s'."), cur_name);
        }
 
-      /* If this location is no longer present, and inserted, look if
-        there's maybe a new location at the same address.  If so,
-        mark that one inserted, and don't remove this one.  This is
-        needed so that we don't have a time window where a breakpoint
-        at certain location is not inserted.  */
+      /* Ok, it's valid.  */
+      VEC_safe_push (int, result, s.number);
+    }
 
-      if (old_loc->inserted)
-       {
-         /* If the location is inserted now, we might have to remove
-            it.  */
+  discard_cleanups (cleanup);
+  return result;
+}
 
-         if (found_object && should_be_inserted (old_loc))
-           {
-             /* The location is still present in the location list,
-                and still should be inserted.  Don't do anything.  */
-             keep_in_target = 1;
-           }
-         else
-           {
-             /* The location is either no longer present, or got
+/* Implement the "catch syscall" command.  */
+
+static void
+catch_syscall_command_1 (char *arg, int from_tty, 
+                        struct cmd_list_element *command)
+{
+  int tempflag;
+  VEC(int) *filter;
+  struct syscall s;
+  struct gdbarch *gdbarch = get_current_arch ();
+
+  /* Checking if the feature if supported.  */
+  if (gdbarch_get_syscall_number_p (gdbarch) == 0)
+    error (_("The feature 'catch syscall' is not supported on \
+this architecture yet."));
+
+  tempflag = get_cmd_context (command) == CATCH_TEMPORARY;
+
+  arg = skip_spaces (arg);
+
+  /* We need to do this first "dummy" translation in order
+     to get the syscall XML file loaded or, most important,
+     to display a warning to the user if there's no XML file
+     for his/her architecture.  */
+  get_syscall_by_number (0, &s);
+
+  /* The allowed syntax is:
+     catch syscall
+     catch syscall <name | number> [<name | number> ... <name | number>]
+
+     Let's check if there's a syscall name.  */
+
+  if (arg != NULL)
+    filter = catch_syscall_split_args (arg);
+  else
+    filter = NULL;
+
+  create_syscall_event_catchpoint (tempflag, filter,
+                                  &catch_syscall_breakpoint_ops);
+}
+
+static void
+catch_command (char *arg, int from_tty)
+{
+  error (_("Catch requires an event name."));
+}
+\f
+
+static void
+tcatch_command (char *arg, int from_tty)
+{
+  error (_("Catch requires an event name."));
+}
+
+/* Delete breakpoints by address or line.  */
+
+static void
+clear_command (char *arg, int from_tty)
+{
+  struct breakpoint *b;
+  VEC(breakpoint_p) *found = 0;
+  int ix;
+  int default_match;
+  struct symtabs_and_lines sals;
+  struct symtab_and_line sal;
+  int i;
+
+  if (arg)
+    {
+      sals = decode_line_spec (arg, 1);
+      default_match = 0;
+    }
+  else
+    {
+      sals.sals = (struct symtab_and_line *)
+       xmalloc (sizeof (struct symtab_and_line));
+      make_cleanup (xfree, sals.sals);
+      init_sal (&sal);         /* Initialize to zeroes.  */
+      sal.line = default_breakpoint_line;
+      sal.symtab = default_breakpoint_symtab;
+      sal.pc = default_breakpoint_address;
+      sal.pspace = default_breakpoint_pspace;
+      if (sal.symtab == 0)
+       error (_("No source file specified."));
+
+      sals.sals[0] = sal;
+      sals.nelts = 1;
+
+      default_match = 1;
+    }
+
+  /* We don't call resolve_sal_pc here.  That's not as bad as it
+     seems, because all existing breakpoints typically have both
+     file/line and pc set.  So, if clear is given file/line, we can
+     match this to existing breakpoint without obtaining pc at all.
+
+     We only support clearing given the address explicitly 
+     present in breakpoint table.  Say, we've set breakpoint 
+     at file:line.  There were several PC values for that file:line,
+     due to optimization, all in one block.
+
+     We've picked one PC value.  If "clear" is issued with another
+     PC corresponding to the same file:line, the breakpoint won't
+     be cleared.  We probably can still clear the breakpoint, but 
+     since the other PC value is never presented to user, user
+     can only find it by guessing, and it does not seem important
+     to support that.  */
+
+  /* For each line spec given, delete bps which correspond to it.  Do
+     it in two passes, solely to preserve the current behavior that
+     from_tty is forced true if we delete more than one
+     breakpoint.  */
+
+  found = NULL;
+  for (i = 0; i < sals.nelts; i++)
+    {
+      /* If exact pc given, clear bpts at that pc.
+         If line given (pc == 0), clear all bpts on specified line.
+         If defaulting, clear all bpts on default line
+         or at default pc.
+
+         defaulting    sal.pc != 0    tests to do
+
+         0              1             pc
+         1              1             pc _and_ line
+         0              0             line
+         1              0             <can't happen> */
+
+      sal = sals.sals[i];
+
+      /* Find all matching breakpoints and add them to 'found'.  */
+      ALL_BREAKPOINTS (b)
+       {
+         int match = 0;
+         /* Are we going to delete b?  */
+         if (b->type != bp_none && !is_watchpoint (b))
+           {
+             struct bp_location *loc = b->loc;
+             for (; loc; loc = loc->next)
+               {
+                 int pc_match = sal.pc
+                   && (loc->pspace == sal.pspace)
+                   && (loc->address == sal.pc)
+                   && (!section_is_overlay (loc->section)
+                       || loc->section == sal.section);
+                 int line_match = ((default_match || (0 == sal.pc))
+                                   && b->source_file != NULL
+                                   && sal.symtab != NULL
+                                   && sal.pspace == loc->pspace
+                                   && filename_cmp (b->source_file,
+                                                    sal.symtab->filename) == 0
+                                   && b->line_number == sal.line);
+                 if (pc_match || line_match)
+                   {
+                     match = 1;
+                     break;
+                   }
+               }
+           }
+
+         if (match)
+           VEC_safe_push(breakpoint_p, found, b);
+       }
+    }
+  /* Now go thru the 'found' chain and delete them.  */
+  if (VEC_empty(breakpoint_p, found))
+    {
+      if (arg)
+       error (_("No breakpoint at %s."), arg);
+      else
+       error (_("No breakpoint at this line."));
+    }
+
+  if (VEC_length(breakpoint_p, found) > 1)
+    from_tty = 1;      /* Always report if deleted more than one.  */
+  if (from_tty)
+    {
+      if (VEC_length(breakpoint_p, found) == 1)
+       printf_unfiltered (_("Deleted breakpoint "));
+      else
+       printf_unfiltered (_("Deleted breakpoints "));
+    }
+  breakpoints_changed ();
+
+  for (ix = 0; VEC_iterate(breakpoint_p, found, ix, b); ix++)
+    {
+      if (from_tty)
+       printf_unfiltered ("%d ", b->number);
+      delete_breakpoint (b);
+    }
+  if (from_tty)
+    putchar_unfiltered ('\n');
+}
+\f
+/* Delete breakpoint in BS if they are `delete' breakpoints and
+   all breakpoints that are marked for deletion, whether hit or not.
+   This is called after any breakpoint is hit, or after errors.  */
+
+void
+breakpoint_auto_delete (bpstat bs)
+{
+  struct breakpoint *b, *b_tmp;
+
+  for (; bs; bs = bs->next)
+    if (bs->breakpoint_at
+       && bs->breakpoint_at->disposition == disp_del
+       && bs->stop)
+      delete_breakpoint (bs->breakpoint_at);
+
+  ALL_BREAKPOINTS_SAFE (b, b_tmp)
+  {
+    if (b->disposition == disp_del_at_next_stop)
+      delete_breakpoint (b);
+  }
+}
+
+/* A comparison function for bp_location AP and BP being interfaced to
+   qsort.  Sort elements primarily by their ADDRESS (no matter what
+   does breakpoint_address_is_meaningful say for its OWNER),
+   secondarily by ordering first bp_permanent OWNERed elements and
+   terciarily just ensuring the array is sorted stable way despite
+   qsort being an unstable algorithm.  */
+
+static int
+bp_location_compare (const void *ap, const void *bp)
+{
+  struct bp_location *a = *(void **) ap;
+  struct bp_location *b = *(void **) bp;
+  /* A and B come from existing breakpoints having non-NULL OWNER.  */
+  int a_perm = a->owner->enable_state == bp_permanent;
+  int b_perm = b->owner->enable_state == bp_permanent;
+
+  if (a->address != b->address)
+    return (a->address > b->address) - (a->address < b->address);
+
+  /* Sort permanent breakpoints first.  */
+  if (a_perm != b_perm)
+    return (a_perm < b_perm) - (a_perm > b_perm);
+
+  /* Make the user-visible order stable across GDB runs.  Locations of
+     the same breakpoint can be sorted in arbitrary order.  */
+
+  if (a->owner->number != b->owner->number)
+    return (a->owner->number > b->owner->number)
+           - (a->owner->number < b->owner->number);
+
+  return (a > b) - (a < b);
+}
+
+/* Set bp_location_placed_address_before_address_max and
+   bp_location_shadow_len_after_address_max according to the current
+   content of the bp_location array.  */
+
+static void
+bp_location_target_extensions_update (void)
+{
+  struct bp_location *bl, **blp_tmp;
+
+  bp_location_placed_address_before_address_max = 0;
+  bp_location_shadow_len_after_address_max = 0;
+
+  ALL_BP_LOCATIONS (bl, blp_tmp)
+    {
+      CORE_ADDR start, end, addr;
+
+      if (!bp_location_has_shadow (bl))
+       continue;
+
+      start = bl->target_info.placed_address;
+      end = start + bl->target_info.shadow_len;
+
+      gdb_assert (bl->address >= start);
+      addr = bl->address - start;
+      if (addr > bp_location_placed_address_before_address_max)
+       bp_location_placed_address_before_address_max = addr;
+
+      /* Zero SHADOW_LEN would not pass bp_location_has_shadow.  */
+
+      gdb_assert (bl->address < end);
+      addr = end - bl->address;
+      if (addr > bp_location_shadow_len_after_address_max)
+       bp_location_shadow_len_after_address_max = addr;
+    }
+}
+
+/* Swap the insertion/duplication state between two locations.  */
+
+static void
+swap_insertion (struct bp_location *left, struct bp_location *right)
+{
+  const int left_inserted = left->inserted;
+  const int left_duplicate = left->duplicate;
+  const struct bp_target_info left_target_info = left->target_info;
+
+  left->inserted = right->inserted;
+  left->duplicate = right->duplicate;
+  left->target_info = right->target_info;
+  right->inserted = left_inserted;
+  right->duplicate = left_duplicate;
+  right->target_info = left_target_info;
+}
+
+/* If SHOULD_INSERT is false, do not insert any breakpoint locations
+   into the inferior, only remove already-inserted locations that no
+   longer should be inserted.  Functions that delete a breakpoint or
+   breakpoints should pass false, so that deleting a breakpoint
+   doesn't have the side effect of inserting the locations of other
+   breakpoints that are marked not-inserted, but should_be_inserted
+   returns true on them.
+
+   This behaviour is useful is situations close to tear-down -- e.g.,
+   after an exec, while the target still has execution, but breakpoint
+   shadows of the previous executable image should *NOT* be restored
+   to the new image; or before detaching, where the target still has
+   execution and wants to delete breakpoints from GDB's lists, and all
+   breakpoints had already been removed from the inferior.  */
+
+static void
+update_global_location_list (int should_insert)
+{
+  struct breakpoint *b;
+  struct bp_location **locp, *loc;
+  struct cleanup *cleanups;
+
+  /* Used in the duplicates detection below.  When iterating over all
+     bp_locations, points to the first bp_location of a given address.
+     Breakpoints and watchpoints of different types are never
+     duplicates of each other.  Keep one pointer for each type of
+     breakpoint/watchpoint, so we only need to loop over all locations
+     once.  */
+  struct bp_location *bp_loc_first;  /* breakpoint */
+  struct bp_location *wp_loc_first;  /* hardware watchpoint */
+  struct bp_location *awp_loc_first; /* access watchpoint */
+  struct bp_location *rwp_loc_first; /* read watchpoint */
+
+  /* Saved former bp_location array which we compare against the newly
+     built bp_location from the current state of ALL_BREAKPOINTS.  */
+  struct bp_location **old_location, **old_locp;
+  unsigned old_location_count;
+
+  old_location = bp_location;
+  old_location_count = bp_location_count;
+  bp_location = NULL;
+  bp_location_count = 0;
+  cleanups = make_cleanup (xfree, old_location);
+
+  ALL_BREAKPOINTS (b)
+    for (loc = b->loc; loc; loc = loc->next)
+      bp_location_count++;
+
+  bp_location = xmalloc (sizeof (*bp_location) * bp_location_count);
+  locp = bp_location;
+  ALL_BREAKPOINTS (b)
+    for (loc = b->loc; loc; loc = loc->next)
+      *locp++ = loc;
+  qsort (bp_location, bp_location_count, sizeof (*bp_location),
+        bp_location_compare);
+
+  bp_location_target_extensions_update ();
+
+  /* Identify bp_location instances that are no longer present in the
+     new list, and therefore should be freed.  Note that it's not
+     necessary that those locations should be removed from inferior --
+     if there's another location at the same address (previously
+     marked as duplicate), we don't need to remove/insert the
+     location.
+     
+     LOCP is kept in sync with OLD_LOCP, each pointing to the current
+     and former bp_location array state respectively.  */
+
+  locp = bp_location;
+  for (old_locp = old_location; old_locp < old_location + old_location_count;
+       old_locp++)
+    {
+      struct bp_location *old_loc = *old_locp;
+      struct bp_location **loc2p;
+
+      /* Tells if 'old_loc' is found among the new locations.  If
+        not, we have to free it.  */
+      int found_object = 0;
+      /* Tells if the location should remain inserted in the target.  */
+      int keep_in_target = 0;
+      int removed = 0;
+
+      /* Skip LOCP entries which will definitely never be needed.
+        Stop either at or being the one matching OLD_LOC.  */
+      while (locp < bp_location + bp_location_count
+            && (*locp)->address < old_loc->address)
+       locp++;
+
+      for (loc2p = locp;
+          (loc2p < bp_location + bp_location_count
+           && (*loc2p)->address == old_loc->address);
+          loc2p++)
+       {
+         if (*loc2p == old_loc)
+           {
+             found_object = 1;
+             break;
+           }
+       }
+
+      /* If this location is no longer present, and inserted, look if
+        there's maybe a new location at the same address.  If so,
+        mark that one inserted, and don't remove this one.  This is
+        needed so that we don't have a time window where a breakpoint
+        at certain location is not inserted.  */
+
+      if (old_loc->inserted)
+       {
+         /* If the location is inserted now, we might have to remove
+            it.  */
+
+         if (found_object && should_be_inserted (old_loc))
+           {
+             /* The location is still present in the location list,
+                and still should be inserted.  Don't do anything.  */
+             keep_in_target = 1;
+           }
+         else
+           {
+             /* The location is either no longer present, or got
                 disabled.  See if there's another location at the
                 same address, in which case we don't need to remove
                 this one from the target.  */
 
-             /* OLD_LOC comes from existing struct breakpoint.  */
-             if (breakpoint_address_is_meaningful (old_loc->owner))
-               {
-                 for (loc2p = locp;
-                      (loc2p < bp_location + bp_location_count
-                       && (*loc2p)->address == old_loc->address);
-                      loc2p++)
-                   {
-                     struct bp_location *loc2 = *loc2p;
+             /* OLD_LOC comes from existing struct breakpoint.  */
+             if (breakpoint_address_is_meaningful (old_loc->owner))
+               {
+                 for (loc2p = locp;
+                      (loc2p < bp_location + bp_location_count
+                       && (*loc2p)->address == old_loc->address);
+                      loc2p++)
+                   {
+                     struct bp_location *loc2 = *loc2p;
+
+                     if (breakpoint_locations_match (loc2, old_loc))
+                       {
+                         /* Read watchpoint locations are switched to
+                            access watchpoints, if the former are not
+                            supported, but the latter are.  */
+                         if (is_hardware_watchpoint (old_loc->owner))
+                           {
+                             gdb_assert (is_hardware_watchpoint (loc2->owner));
+                             loc2->watchpoint_type = old_loc->watchpoint_type;
+                           }
+
+                         /* loc2 is a duplicated location. We need to check
+                            if it should be inserted in case it will be
+                            unduplicated.  */
+                         if (loc2 != old_loc
+                             && unduplicated_should_be_inserted (loc2))
+                           {
+                             swap_insertion (old_loc, loc2);
+                             keep_in_target = 1;
+                             break;
+                           }
+                       }
+                   }
+               }
+           }
+
+         if (!keep_in_target)
+           {
+             if (remove_breakpoint (old_loc, mark_uninserted))
+               {
+                 /* This is just about all we can do.  We could keep
+                    this location on the global list, and try to
+                    remove it next time, but there's no particular
+                    reason why we will succeed next time.
+                    
+                    Note that at this point, old_loc->owner is still
+                    valid, as delete_breakpoint frees the breakpoint
+                    only after calling us.  */
+                 printf_filtered (_("warning: Error removing "
+                                    "breakpoint %d\n"), 
+                                  old_loc->owner->number);
+               }
+             removed = 1;
+           }
+       }
+
+      if (!found_object)
+       {
+         if (removed && non_stop
+             && breakpoint_address_is_meaningful (old_loc->owner)
+             && !is_hardware_watchpoint (old_loc->owner))
+           {
+             /* This location was removed from the target.  In
+                non-stop mode, a race condition is possible where
+                we've removed a breakpoint, but stop events for that
+                breakpoint are already queued and will arrive later.
+                We apply an heuristic to be able to distinguish such
+                SIGTRAPs from other random SIGTRAPs: we keep this
+                breakpoint location for a bit, and will retire it
+                after we see some number of events.  The theory here
+                is that reporting of events should, "on the average",
+                be fair, so after a while we'll see events from all
+                threads that have anything of interest, and no longer
+                need to keep this breakpoint location around.  We
+                don't hold locations forever so to reduce chances of
+                mistaking a non-breakpoint SIGTRAP for a breakpoint
+                SIGTRAP.
+
+                The heuristic failing can be disastrous on
+                decr_pc_after_break targets.
+
+                On decr_pc_after_break targets, like e.g., x86-linux,
+                if we fail to recognize a late breakpoint SIGTRAP,
+                because events_till_retirement has reached 0 too
+                soon, we'll fail to do the PC adjustment, and report
+                a random SIGTRAP to the user.  When the user resumes
+                the inferior, it will most likely immediately crash
+                with SIGILL/SIGBUS/SIGSEGV, or worse, get silently
+                corrupted, because of being resumed e.g., in the
+                middle of a multi-byte instruction, or skipped a
+                one-byte instruction.  This was actually seen happen
+                on native x86-linux, and should be less rare on
+                targets that do not support new thread events, like
+                remote, due to the heuristic depending on
+                thread_count.
+
+                Mistaking a random SIGTRAP for a breakpoint trap
+                causes similar symptoms (PC adjustment applied when
+                it shouldn't), but then again, playing with SIGTRAPs
+                behind the debugger's back is asking for trouble.
+
+                Since hardware watchpoint traps are always
+                distinguishable from other traps, so we don't need to
+                apply keep hardware watchpoint moribund locations
+                around.  We simply always ignore hardware watchpoint
+                traps we can no longer explain.  */
+
+             old_loc->events_till_retirement = 3 * (thread_count () + 1);
+             old_loc->owner = NULL;
+
+             VEC_safe_push (bp_location_p, moribund_locations, old_loc);
+           }
+         else
+           {
+             old_loc->owner = NULL;
+             decref_bp_location (&old_loc);
+           }
+       }
+    }
+
+  /* Rescan breakpoints at the same address and section, marking the
+     first one as "first" and any others as "duplicates".  This is so
+     that the bpt instruction is only inserted once.  If we have a
+     permanent breakpoint at the same place as BPT, make that one the
+     official one, and the rest as duplicates.  Permanent breakpoints
+     are sorted first for the same address.
+
+     Do the same for hardware watchpoints, but also considering the
+     watchpoint's type (regular/access/read) and length.  */
+
+  bp_loc_first = NULL;
+  wp_loc_first = NULL;
+  awp_loc_first = NULL;
+  rwp_loc_first = NULL;
+  ALL_BP_LOCATIONS (loc, locp)
+    {
+      /* ALL_BP_LOCATIONS bp_location has LOC->OWNER always
+        non-NULL.  */
+      struct breakpoint *b = loc->owner;
+      struct bp_location **loc_first_p;
+
+      if (b->enable_state == bp_disabled
+         || b->enable_state == bp_call_disabled
+         || b->enable_state == bp_startup_disabled
+         || !loc->enabled
+         || loc->shlib_disabled
+         || !breakpoint_address_is_meaningful (b)
+         || is_tracepoint (b))
+       continue;
+
+      /* Permanent breakpoint should always be inserted.  */
+      if (b->enable_state == bp_permanent && ! loc->inserted)
+       internal_error (__FILE__, __LINE__,
+                       _("allegedly permanent breakpoint is not "
+                       "actually inserted"));
+
+      if (b->type == bp_hardware_watchpoint)
+       loc_first_p = &wp_loc_first;
+      else if (b->type == bp_read_watchpoint)
+       loc_first_p = &rwp_loc_first;
+      else if (b->type == bp_access_watchpoint)
+       loc_first_p = &awp_loc_first;
+      else
+       loc_first_p = &bp_loc_first;
+
+      if (*loc_first_p == NULL
+         || (overlay_debugging && loc->section != (*loc_first_p)->section)
+         || !breakpoint_locations_match (loc, *loc_first_p))
+       {
+         *loc_first_p = loc;
+         loc->duplicate = 0;
+         continue;
+       }
+
+
+      /* This and the above ensure the invariant that the first location
+        is not duplicated, and is the inserted one.
+        All following are marked as duplicated, and are not inserted.  */
+      if (loc->inserted)
+       swap_insertion (loc, *loc_first_p);
+      loc->duplicate = 1;
+
+      if ((*loc_first_p)->owner->enable_state == bp_permanent && loc->inserted
+         && b->enable_state != bp_permanent)
+       internal_error (__FILE__, __LINE__,
+                       _("another breakpoint was inserted on top of "
+                       "a permanent breakpoint"));
+    }
+
+  if (breakpoints_always_inserted_mode () && should_insert
+      && (have_live_inferiors ()
+         || (gdbarch_has_global_breakpoints (target_gdbarch))))
+    insert_breakpoint_locations ();
+
+  do_cleanups (cleanups);
+}
+
+void
+breakpoint_retire_moribund (void)
+{
+  struct bp_location *loc;
+  int ix;
+
+  for (ix = 0; VEC_iterate (bp_location_p, moribund_locations, ix, loc); ++ix)
+    if (--(loc->events_till_retirement) == 0)
+      {
+       decref_bp_location (&loc);
+       VEC_unordered_remove (bp_location_p, moribund_locations, ix);
+       --ix;
+      }
+}
+
+static void
+update_global_location_list_nothrow (int inserting)
+{
+  struct gdb_exception e;
+
+  TRY_CATCH (e, RETURN_MASK_ERROR)
+    update_global_location_list (inserting);
+}
+
+/* Clear BKP from a BPS.  */
+
+static void
+bpstat_remove_bp_location (bpstat bps, struct breakpoint *bpt)
+{
+  bpstat bs;
+
+  for (bs = bps; bs; bs = bs->next)
+    if (bs->breakpoint_at == bpt)
+      {
+       bs->breakpoint_at = NULL;
+       bs->old_val = NULL;
+       /* bs->commands will be freed later.  */
+      }
+}
+
+/* Callback for iterate_over_threads.  */
+static int
+bpstat_remove_breakpoint_callback (struct thread_info *th, void *data)
+{
+  struct breakpoint *bpt = data;
+
+  bpstat_remove_bp_location (th->control.stop_bpstat, bpt);
+  return 0;
+}
+
+/* Helper for breakpoint and tracepoint breakpoint_ops->mention
+   callbacks.  */
+
+static void
+say_where (struct breakpoint *b)
+{
+  struct ui_out *uiout = current_uiout;
+  struct value_print_options opts;
+
+  get_user_print_options (&opts);
+
+  /* i18n: cagney/2005-02-11: Below needs to be merged into a
+     single string.  */
+  if (b->loc == NULL)
+    {
+      printf_filtered (_(" (%s) pending."), b->addr_string);
+    }
+  else
+    {
+      if (opts.addressprint || b->source_file == NULL)
+       {
+         printf_filtered (" at ");
+         fputs_filtered (paddress (b->loc->gdbarch, b->loc->address),
+                         gdb_stdout);
+       }
+      if (b->source_file)
+       printf_filtered (": file %s, line %d.",
+                        b->source_file, b->line_number);
+
+      if (b->loc->next)
+       {
+         struct bp_location *loc = b->loc;
+         int n = 0;
+         for (; loc; loc = loc->next)
+           ++n;
+         printf_filtered (" (%d locations)", n);
+       }
+    }
+}
+
+/* Default bp_location_ops methods.  */
+
+static void
+bp_location_dtor (struct bp_location *self)
+{
+  xfree (self->cond);
+  xfree (self->function_name);
+}
+
+static const struct bp_location_ops bp_location_ops =
+{
+  bp_location_dtor
+};
+
+/* Default breakpoint_ops methods all breakpoint_ops ultimately
+   inherit from.  */
+
+static void
+base_breakpoint_dtor (struct breakpoint *self)
+{
+  decref_counted_command_line (&self->commands);
+  xfree (self->cond_string);
+  xfree (self->addr_string);
+  xfree (self->addr_string_range_end);
+  xfree (self->source_file);
+}
+
+static struct bp_location *
+base_breakpoint_allocate_location (struct breakpoint *self)
+{
+  struct bp_location *loc;
+
+  loc = XNEW (struct bp_location);
+  init_bp_location (loc, &bp_location_ops, self);
+  return loc;
+}
+
+static void
+base_breakpoint_re_set (struct breakpoint *b)
+{
+  /* Nothing to re-set. */
+}
+
+#define internal_error_pure_virtual_called() \
+  gdb_assert_not_reached ("pure virtual function called")
+
+static int
+base_breakpoint_insert_location (struct bp_location *bl)
+{
+  internal_error_pure_virtual_called ();
+}
+
+static int
+base_breakpoint_remove_location (struct bp_location *bl)
+{
+  internal_error_pure_virtual_called ();
+}
+
+static int
+base_breakpoint_breakpoint_hit (const struct bp_location *bl,
+                               struct address_space *aspace,
+                               CORE_ADDR bp_addr)
+{
+  internal_error_pure_virtual_called ();
+}
+
+static void
+base_breakpoint_check_status (bpstat bs)
+{
+  /* Always stop.   */
+}
+
+/* A "works_in_software_mode" breakpoint_ops method that just internal
+   errors.  */
+
+static int
+base_breakpoint_works_in_software_mode (const struct breakpoint *b)
+{
+  internal_error_pure_virtual_called ();
+}
+
+/* A "resources_needed" breakpoint_ops method that just internal
+   errors.  */
+
+static int
+base_breakpoint_resources_needed (const struct bp_location *bl)
+{
+  internal_error_pure_virtual_called ();
+}
+
+static enum print_stop_action
+base_breakpoint_print_it (bpstat bs)
+{
+  internal_error_pure_virtual_called ();
+}
+
+static void
+base_breakpoint_print_one_detail (const struct breakpoint *self,
+                                 struct ui_out *uiout)
+{
+  /* nothing */
+}
+
+static void
+base_breakpoint_print_mention (struct breakpoint *b)
+{
+  internal_error_pure_virtual_called ();
+}
+
+static void
+base_breakpoint_print_recreate (struct breakpoint *b, struct ui_file *fp)
+{
+  internal_error_pure_virtual_called ();
+}
+
+static struct breakpoint_ops base_breakpoint_ops =
+{
+  base_breakpoint_dtor,
+  base_breakpoint_allocate_location,
+  base_breakpoint_re_set,
+  base_breakpoint_insert_location,
+  base_breakpoint_remove_location,
+  base_breakpoint_breakpoint_hit,
+  base_breakpoint_check_status,
+  base_breakpoint_resources_needed,
+  base_breakpoint_works_in_software_mode,
+  base_breakpoint_print_it,
+  NULL,
+  base_breakpoint_print_one_detail,
+  base_breakpoint_print_mention,
+  base_breakpoint_print_recreate
+};
+
+/* Default breakpoint_ops methods.  */
+
+static void
+bkpt_re_set (struct breakpoint *b)
+{
+  /* Do not attempt to re-set breakpoints disabled during startup.  */
+  if (b->enable_state == bp_startup_disabled)
+    return;
+
+  /* FIXME: is this still reachable?  */
+  if (b->addr_string == NULL)
+    {
+      /* Anything without a string can't be re-set.  */
+      delete_breakpoint (b);
+      return;
+    }
+
+  breakpoint_re_set_default (b);
+}
+
+static int
+bkpt_insert_location (struct bp_location *bl)
+{
+  if (bl->loc_type == bp_loc_hardware_breakpoint)
+    return target_insert_hw_breakpoint (bl->gdbarch,
+                                       &bl->target_info);
+  else
+    return target_insert_breakpoint (bl->gdbarch,
+                                    &bl->target_info);
+}
+
+static int
+bkpt_remove_location (struct bp_location *bl)
+{
+  if (bl->loc_type == bp_loc_hardware_breakpoint)
+    return target_remove_hw_breakpoint (bl->gdbarch, &bl->target_info);
+  else
+    return target_remove_breakpoint (bl->gdbarch, &bl->target_info);
+}
+
+static int
+bkpt_breakpoint_hit (const struct bp_location *bl,
+                    struct address_space *aspace, CORE_ADDR bp_addr)
+{
+  struct breakpoint *b = bl->owner;
+
+  if (!breakpoint_address_match (bl->pspace->aspace, bl->address,
+                                aspace, bp_addr))
+    return 0;
+
+  if (overlay_debugging                /* unmapped overlay section */
+      && section_is_overlay (bl->section)
+      && !section_is_mapped (bl->section))
+    return 0;
+
+  return 1;
+}
+
+static int
+bkpt_resources_needed (const struct bp_location *bl)
+{
+  gdb_assert (bl->owner->type == bp_hardware_breakpoint);
+
+  return 1;
+}
+
+static enum print_stop_action
+bkpt_print_it (bpstat bs)
+{
+  struct breakpoint *b;
+  const struct bp_location *bl;
+  int bp_temp;
+  struct ui_out *uiout = current_uiout;
+
+  gdb_assert (bs->bp_location_at != NULL);
+
+  bl = bs->bp_location_at;
+  b = bs->breakpoint_at;
+
+  bp_temp = b->disposition == disp_del;
+  if (bl->address != bl->requested_address)
+    breakpoint_adjustment_warning (bl->requested_address,
+                                  bl->address,
+                                  b->number, 1);
+  annotate_breakpoint (b->number);
+  if (bp_temp)
+    ui_out_text (uiout, "\nTemporary breakpoint ");
+  else
+    ui_out_text (uiout, "\nBreakpoint ");
+  if (ui_out_is_mi_like_p (uiout))
+    {
+      ui_out_field_string (uiout, "reason",
+                          async_reason_lookup (EXEC_ASYNC_BREAKPOINT_HIT));
+      ui_out_field_string (uiout, "disp", bpdisp_text (b->disposition));
+    }
+  ui_out_field_int (uiout, "bkptno", b->number);
+  ui_out_text (uiout, ", ");
+
+  return PRINT_SRC_AND_LOC;
+}
+
+static void
+bkpt_print_mention (struct breakpoint *b)
+{
+  if (ui_out_is_mi_like_p (current_uiout))
+    return;
+
+  switch (b->type)
+    {
+    case bp_breakpoint:
+    case bp_gnu_ifunc_resolver:
+      if (b->disposition == disp_del)
+       printf_filtered (_("Temporary breakpoint"));
+      else
+       printf_filtered (_("Breakpoint"));
+      printf_filtered (_(" %d"), b->number);
+      if (b->type == bp_gnu_ifunc_resolver)
+       printf_filtered (_(" at gnu-indirect-function resolver"));
+      break;
+    case bp_hardware_breakpoint:
+      printf_filtered (_("Hardware assisted breakpoint %d"), b->number);
+      break;
+    }
+
+  say_where (b);
+}
+
+static void
+bkpt_print_recreate (struct breakpoint *tp, struct ui_file *fp)
+{
+  if (tp->type == bp_breakpoint && tp->disposition == disp_del)
+    fprintf_unfiltered (fp, "tbreak");
+  else if (tp->type == bp_breakpoint)
+    fprintf_unfiltered (fp, "break");
+  else if (tp->type == bp_hardware_breakpoint
+          && tp->disposition == disp_del)
+    fprintf_unfiltered (fp, "thbreak");
+  else if (tp->type == bp_hardware_breakpoint)
+    fprintf_unfiltered (fp, "hbreak");
+  else
+    internal_error (__FILE__, __LINE__,
+                   _("unhandled breakpoint type %d"), (int) tp->type);
+
+  fprintf_unfiltered (fp, " %s", tp->addr_string);
+}
+
+/* Virtual table for internal breakpoints.  */
+
+static void
+internal_bkpt_re_set (struct breakpoint *b)
+{
+  switch (b->type)
+    {
+      /* Delete overlay event and longjmp master breakpoints; they
+        will be reset later by breakpoint_re_set.  */
+    case bp_overlay_event:
+    case bp_longjmp_master:
+    case bp_std_terminate_master:
+    case bp_exception_master:
+      delete_breakpoint (b);
+      break;
 
-                     if (breakpoint_locations_match (loc2, old_loc))
-                       {
-                         /* For the sake of should_be_inserted.
-                            Duplicates check below will fix up this
-                            later.  */
-                         loc2->duplicate = 0;
+      /* This breakpoint is special, it's set up when the inferior
+         starts and we really don't want to touch it.  */
+    case bp_shlib_event:
 
-                         /* Read watchpoint locations are switched to
-                            access watchpoints, if the former are not
-                            supported, but the latter are.  */
-                         if (is_hardware_watchpoint (old_loc->owner))
-                           {
-                             gdb_assert (is_hardware_watchpoint (loc2->owner));
-                             loc2->watchpoint_type = old_loc->watchpoint_type;
-                           }
+      /* Like bp_shlib_event, this breakpoint type is special.  Once
+        it is set up, we do not want to touch it.  */
+    case bp_thread_event:
+      break;
+    }
+}
 
-                         if (loc2 != old_loc && should_be_inserted (loc2))
-                           {
-                             loc2->inserted = 1;
-                             loc2->target_info = old_loc->target_info;
-                             keep_in_target = 1;
-                             break;
-                           }
-                       }
-                   }
-               }
-           }
+static void
+internal_bkpt_check_status (bpstat bs)
+{
+  /* We do not stop for these.  */
+  bs->stop = 0;
+}
 
-         if (!keep_in_target)
-           {
-             if (remove_breakpoint (old_loc, mark_uninserted))
-               {
-                 /* This is just about all we can do.  We could keep
-                    this location on the global list, and try to
-                    remove it next time, but there's no particular
-                    reason why we will succeed next time.
-                    
-                    Note that at this point, old_loc->owner is still
-                    valid, as delete_breakpoint frees the breakpoint
-                    only after calling us.  */
-                 printf_filtered (_("warning: Error removing "
-                                    "breakpoint %d\n"), 
-                                  old_loc->owner->number);
-               }
-             removed = 1;
-           }
-       }
+static enum print_stop_action
+internal_bkpt_print_it (bpstat bs)
+{
+  struct breakpoint *b;
 
-      if (!found_object)
-       {
-         if (removed && non_stop
-             && breakpoint_address_is_meaningful (old_loc->owner)
-             && !is_hardware_watchpoint (old_loc->owner))
-           {
-             /* This location was removed from the target.  In
-                non-stop mode, a race condition is possible where
-                we've removed a breakpoint, but stop events for that
-                breakpoint are already queued and will arrive later.
-                We apply an heuristic to be able to distinguish such
-                SIGTRAPs from other random SIGTRAPs: we keep this
-                breakpoint location for a bit, and will retire it
-                after we see some number of events.  The theory here
-                is that reporting of events should, "on the average",
-                be fair, so after a while we'll see events from all
-                threads that have anything of interest, and no longer
-                need to keep this breakpoint location around.  We
-                don't hold locations forever so to reduce chances of
-                mistaking a non-breakpoint SIGTRAP for a breakpoint
-                SIGTRAP.
+  b = bs->breakpoint_at;
 
-                The heuristic failing can be disastrous on
-                decr_pc_after_break targets.
+  switch (b->type)
+    {
+    case bp_shlib_event:
+      /* Did we stop because the user set the stop_on_solib_events
+        variable?  (If so, we report this as a generic, "Stopped due
+        to shlib event" message.) */
+      printf_filtered (_("Stopped due to shared library event\n"));
+      break;
 
-                On decr_pc_after_break targets, like e.g., x86-linux,
-                if we fail to recognize a late breakpoint SIGTRAP,
-                because events_till_retirement has reached 0 too
-                soon, we'll fail to do the PC adjustment, and report
-                a random SIGTRAP to the user.  When the user resumes
-                the inferior, it will most likely immediately crash
-                with SIGILL/SIGBUS/SIGSEGV, or worse, get silently
-                corrupted, because of being resumed e.g., in the
-                middle of a multi-byte instruction, or skipped a
-                one-byte instruction.  This was actually seen happen
-                on native x86-linux, and should be less rare on
-                targets that do not support new thread events, like
-                remote, due to the heuristic depending on
-                thread_count.
+    case bp_thread_event:
+      /* Not sure how we will get here.
+        GDB should not stop for these breakpoints.  */
+      printf_filtered (_("Thread Event Breakpoint: gdb should not stop!\n"));
+      break;
 
-                Mistaking a random SIGTRAP for a breakpoint trap
-                causes similar symptoms (PC adjustment applied when
-                it shouldn't), but then again, playing with SIGTRAPs
-                behind the debugger's back is asking for trouble.
+    case bp_overlay_event:
+      /* By analogy with the thread event, GDB should not stop for these.  */
+      printf_filtered (_("Overlay Event Breakpoint: gdb should not stop!\n"));
+      break;
 
-                Since hardware watchpoint traps are always
-                distinguishable from other traps, so we don't need to
-                apply keep hardware watchpoint moribund locations
-                around.  We simply always ignore hardware watchpoint
-                traps we can no longer explain.  */
+    case bp_longjmp_master:
+      /* These should never be enabled.  */
+      printf_filtered (_("Longjmp Master Breakpoint: gdb should not stop!\n"));
+      break;
 
-             old_loc->events_till_retirement = 3 * (thread_count () + 1);
-             old_loc->owner = NULL;
+    case bp_std_terminate_master:
+      /* These should never be enabled.  */
+      printf_filtered (_("std::terminate Master Breakpoint: "
+                        "gdb should not stop!\n"));
+      break;
 
-             VEC_safe_push (bp_location_p, moribund_locations, old_loc);
-           }
-         else
-           {
-             old_loc->owner = NULL;
-             decref_bp_location (&old_loc);
-           }
-       }
+    case bp_exception_master:
+      /* These should never be enabled.  */
+      printf_filtered (_("Exception Master Breakpoint: "
+                        "gdb should not stop!\n"));
+      break;
     }
 
-  /* Rescan breakpoints at the same address and section, marking the
-     first one as "first" and any others as "duplicates".  This is so
-     that the bpt instruction is only inserted once.  If we have a
-     permanent breakpoint at the same place as BPT, make that one the
-     official one, and the rest as duplicates.  Permanent breakpoints
-     are sorted first for the same address.
+  return PRINT_NOTHING;
+}
 
-     Do the same for hardware watchpoints, but also considering the
-     watchpoint's type (regular/access/read) and length.  */
+static void
+internal_bkpt_print_mention (struct breakpoint *b)
+{
+  /* Nothing to mention.  These breakpoints are internal.  */
+}
 
-  bp_loc_first = NULL;
-  wp_loc_first = NULL;
-  awp_loc_first = NULL;
-  rwp_loc_first = NULL;
-  ALL_BP_LOCATIONS (loc, locp)
-    {
-      /* ALL_BP_LOCATIONS bp_location has LOC->OWNER always
-        non-NULL.  */
-      struct breakpoint *b = loc->owner;
-      struct bp_location **loc_first_p;
+/* Virtual table for momentary breakpoints  */
 
-      if (b->enable_state == bp_disabled
-         || b->enable_state == bp_call_disabled
-         || b->enable_state == bp_startup_disabled
-         || !loc->enabled
-         || loc->shlib_disabled
-         || !breakpoint_address_is_meaningful (b)
-         || is_tracepoint (b))
-       continue;
+static void
+momentary_bkpt_re_set (struct breakpoint *b)
+{
+  /* Keep temporary breakpoints, which can be encountered when we step
+     over a dlopen call and SOLIB_ADD is resetting the breakpoints.
+     Otherwise these should have been blown away via the cleanup chain
+     or by breakpoint_init_inferior when we rerun the executable.  */
+}
 
-      /* Permanent breakpoint should always be inserted.  */
-      if (b->enable_state == bp_permanent && ! loc->inserted)
-       internal_error (__FILE__, __LINE__,
-                       _("allegedly permanent breakpoint is not "
-                       "actually inserted"));
+static void
+momentary_bkpt_check_status (bpstat bs)
+{
+  /* Nothing.  The point of these breakpoints is causing a stop.  */
+}
 
-      if (b->type == bp_hardware_watchpoint)
-       loc_first_p = &wp_loc_first;
-      else if (b->type == bp_read_watchpoint)
-       loc_first_p = &rwp_loc_first;
-      else if (b->type == bp_access_watchpoint)
-       loc_first_p = &awp_loc_first;
-      else
-       loc_first_p = &bp_loc_first;
+static enum print_stop_action
+momentary_bkpt_print_it (bpstat bs)
+{
+  struct ui_out *uiout = current_uiout;
 
-      if (*loc_first_p == NULL
-         || (overlay_debugging && loc->section != (*loc_first_p)->section)
-         || !breakpoint_locations_match (loc, *loc_first_p))
-       {
-         *loc_first_p = loc;
-         loc->duplicate = 0;
-         continue;
-       }
+  if (ui_out_is_mi_like_p (uiout))
+    {
+      struct breakpoint *b = bs->breakpoint_at;
 
-      loc->duplicate = 1;
+      switch (b->type)
+       {
+       case bp_finish:
+         ui_out_field_string
+           (uiout, "reason",
+            async_reason_lookup (EXEC_ASYNC_FUNCTION_FINISHED));
+         break;
 
-      if ((*loc_first_p)->owner->enable_state == bp_permanent && loc->inserted
-         && b->enable_state != bp_permanent)
-       internal_error (__FILE__, __LINE__,
-                       _("another breakpoint was inserted on top of "
-                       "a permanent breakpoint"));
+       case bp_until:
+         ui_out_field_string
+           (uiout, "reason",
+            async_reason_lookup (EXEC_ASYNC_LOCATION_REACHED));
+         break;
+       }
     }
 
-  if (breakpoints_always_inserted_mode () && should_insert
-      && (have_live_inferiors ()
-         || (gdbarch_has_global_breakpoints (target_gdbarch))))
-    insert_breakpoint_locations ();
+  return PRINT_UNKNOWN;
+}
 
-  do_cleanups (cleanups);
+static void
+momentary_bkpt_print_mention (struct breakpoint *b)
+{
+  /* Nothing to mention.  These breakpoints are internal.  */
 }
 
-void
-breakpoint_retire_moribund (void)
+/* The breakpoint_ops structure to be used in tracepoints.  */
+
+static void
+tracepoint_re_set (struct breakpoint *b)
 {
-  struct bp_location *loc;
-  int ix;
+  breakpoint_re_set_default (b);
+}
 
-  for (ix = 0; VEC_iterate (bp_location_p, moribund_locations, ix, loc); ++ix)
-    if (--(loc->events_till_retirement) == 0)
-      {
-       decref_bp_location (&loc);
-       VEC_unordered_remove (bp_location_p, moribund_locations, ix);
-       --ix;
-      }
+static int
+tracepoint_breakpoint_hit (const struct bp_location *bl,
+                          struct address_space *aspace, CORE_ADDR bp_addr)
+{
+  /* By definition, the inferior does not report stops at
+     tracepoints.  */
+  return 0;
 }
 
 static void
-update_global_location_list_nothrow (int inserting)
+tracepoint_print_one_detail (const struct breakpoint *self,
+                            struct ui_out *uiout)
 {
-  struct gdb_exception e;
+  struct tracepoint *tp = (struct tracepoint *) self;
+  if (tp->static_trace_marker_id)
+    {
+      gdb_assert (self->type == bp_static_tracepoint);
 
-  TRY_CATCH (e, RETURN_MASK_ERROR)
-    update_global_location_list (inserting);
+      ui_out_text (uiout, "\tmarker id is ");
+      ui_out_field_string (uiout, "static-tracepoint-marker-string-id",
+                          tp->static_trace_marker_id);
+      ui_out_text (uiout, "\n");
+    }
 }
 
-/* Clear BKP from a BPS.  */
-
 static void
-bpstat_remove_bp_location (bpstat bps, struct breakpoint *bpt)
+tracepoint_print_mention (struct breakpoint *b)
 {
-  bpstat bs;
+  if (ui_out_is_mi_like_p (current_uiout))
+    return;
 
-  for (bs = bps; bs; bs = bs->next)
-    if (bs->breakpoint_at == bpt)
-      {
-       bs->breakpoint_at = NULL;
-       bs->old_val = NULL;
-       /* bs->commands will be freed later.  */
-      }
+  switch (b->type)
+    {
+    case bp_tracepoint:
+      printf_filtered (_("Tracepoint"));
+      printf_filtered (_(" %d"), b->number);
+      break;
+    case bp_fast_tracepoint:
+      printf_filtered (_("Fast tracepoint"));
+      printf_filtered (_(" %d"), b->number);
+      break;
+    case bp_static_tracepoint:
+      printf_filtered (_("Static tracepoint"));
+      printf_filtered (_(" %d"), b->number);
+      break;
+    default:
+      internal_error (__FILE__, __LINE__,
+                     _("unhandled tracepoint type %d"), (int) b->type);
+    }
+
+  say_where (b);
 }
 
-/* Callback for iterate_over_threads.  */
-static int
-bpstat_remove_breakpoint_callback (struct thread_info *th, void *data)
+static void
+tracepoint_print_recreate (struct breakpoint *self, struct ui_file *fp)
 {
-  struct breakpoint *bpt = data;
+  struct tracepoint *tp = (struct tracepoint *) self;
 
-  bpstat_remove_bp_location (th->control.stop_bpstat, bpt);
-  return 0;
+  if (self->type == bp_fast_tracepoint)
+    fprintf_unfiltered (fp, "ftrace");
+  if (self->type == bp_static_tracepoint)
+    fprintf_unfiltered (fp, "strace");
+  else if (self->type == bp_tracepoint)
+    fprintf_unfiltered (fp, "trace");
+  else
+    internal_error (__FILE__, __LINE__,
+                   _("unhandled tracepoint type %d"), (int) self->type);
+
+  fprintf_unfiltered (fp, " %s", self->addr_string);
+  print_recreate_thread (self, fp);
+
+  if (tp->pass_count)
+    fprintf_unfiltered (fp, "  passcount %d\n", tp->pass_count);
 }
 
+struct breakpoint_ops tracepoint_breakpoint_ops;
+
 /* Delete a breakpoint and clean up all traces of it in the data
    structures.  */
 
@@ -10464,11 +11244,16 @@ delete_breakpoint (struct breakpoint *bpt)
   if (bpt->related_breakpoint != bpt)
     {
       struct breakpoint *related;
+      struct watchpoint *w;
 
       if (bpt->type == bp_watchpoint_scope)
-       watchpoint_del_at_next_stop (bpt->related_breakpoint);
+       w = (struct watchpoint *) bpt->related_breakpoint;
       else if (bpt->related_breakpoint->type == bp_watchpoint_scope)
-       watchpoint_del_at_next_stop (bpt);
+       w = (struct watchpoint *) bpt;
+      else
+       w = NULL;
+      if (w != NULL)
+       watchpoint_del_at_next_stop (w);
 
       /* Unlink bpt from the bpt->related_breakpoint ring.  */
       for (related = bpt; related->related_breakpoint != bpt;
@@ -10494,24 +11279,10 @@ delete_breakpoint (struct breakpoint *bpt)
       break;
     }
 
-  decref_counted_command_line (&bpt->commands);
-  xfree (bpt->cond_string);
-  xfree (bpt->cond_exp);
-  xfree (bpt->addr_string);
-  xfree (bpt->addr_string_range_end);
-  xfree (bpt->exp);
-  xfree (bpt->exp_string);
-  xfree (bpt->exp_string_reparse);
-  value_free (bpt->val);
-  xfree (bpt->source_file);
-  xfree (bpt->exec_pathname);
-  clean_up_filters (&bpt->syscalls_to_be_caught);
-
-
   /* Be sure no bpstat's are pointing at the breakpoint after it's
      been freed.  */
   /* FIXME, how can we find all bpstat's?  We just check stop_bpstat
-     in all threeds for now.  Note that we cannot just remove bpstats
+     in all threads for now.  Note that we cannot just remove bpstats
      pointing at bpt from the stop_bpstat list entirely, as breakpoint
      commands are associated with the bpstat; if we remove it here,
      then the later call to bpstat_do_actions (&stop_bpstat); in
@@ -10528,11 +11299,10 @@ delete_breakpoint (struct breakpoint *bpt)
      self-contained, but it's not the case now.  */
   update_global_location_list (0);
 
-
+  bpt->ops->dtor (bpt);
   /* On the chance that someone will soon try again to delete this
      same bp, we mark it as deleted before freeing its storage.  */
   bpt->type = bp_none;
-
   xfree (bpt);
 }
 
@@ -10548,8 +11318,42 @@ make_cleanup_delete_breakpoint (struct breakpoint *b)
   return make_cleanup (do_delete_breakpoint_cleanup, b);
 }
 
-/* A callback for map_breakpoint_numbers that calls
-   delete_breakpoint.  */
+/* Iterator function to call a user-provided callback function once
+   for each of B and its related breakpoints.  */
+
+static void
+iterate_over_related_breakpoints (struct breakpoint *b,
+                                 void (*function) (struct breakpoint *,
+                                                   void *),
+                                 void *data)
+{
+  struct breakpoint *related;
+
+  related = b;
+  do
+    {
+      struct breakpoint *next;
+
+      /* FUNCTION may delete RELATED.  */
+      next = related->related_breakpoint;
+
+      if (next == related)
+       {
+         /* RELATED is the last ring entry.  */
+         function (related, data);
+
+         /* FUNCTION may have deleted it, so we'd never reach back to
+            B.  There's nothing left to do anyway, so just break
+            out.  */
+         break;
+       }
+      else
+       function (related, data);
+
+      related = next;
+    }
+  while (related != b);
+}
 
 static void
 do_delete_breakpoint (struct breakpoint *b, void *ignore)
@@ -10557,6 +11361,15 @@ do_delete_breakpoint (struct breakpoint *b, void *ignore)
   delete_breakpoint (b);
 }
 
+/* A callback for map_breakpoint_numbers that calls
+   delete_breakpoint.  */
+
+static void
+do_map_delete_breakpoint (struct breakpoint *b, void *ignore)
+{
+  iterate_over_related_breakpoints (b, do_delete_breakpoint, NULL);
+}
+
 void
 delete_command (char *arg, int from_tty)
 {
@@ -10588,7 +11401,7 @@ delete_command (char *arg, int from_tty)
        }
     }
   else
-    map_breakpoint_numbers (arg, do_delete_breakpoint, NULL);
+    map_breakpoint_numbers (arg, do_map_delete_breakpoint, NULL);
 }
 
 static int
@@ -10674,6 +11487,7 @@ ambiguous_names_p (struct bp_location *loc)
 static struct symtab_and_line
 update_static_tracepoint (struct breakpoint *b, struct symtab_and_line sal)
 {
+  struct tracepoint *tp = (struct tracepoint *) b;
   struct static_tracepoint_marker marker;
   CORE_ADDR pc;
   int i;
@@ -10684,13 +11498,13 @@ update_static_tracepoint (struct breakpoint *b, struct symtab_and_line sal)
 
   if (target_static_tracepoint_marker_at (pc, &marker))
     {
-      if (strcmp (b->static_trace_marker_id, marker.str_id) != 0)
+      if (strcmp (tp->static_trace_marker_id, marker.str_id) != 0)
        warning (_("static tracepoint %d changed probed marker from %s to %s"),
                 b->number,
-                b->static_trace_marker_id, marker.str_id);
+                tp->static_trace_marker_id, marker.str_id);
 
-      xfree (b->static_trace_marker_id);
-      b->static_trace_marker_id = xstrdup (marker.str_id);
+      xfree (tp->static_trace_marker_id);
+      tp->static_trace_marker_id = xstrdup (marker.str_id);
       release_static_tracepoint_marker (&marker);
 
       return sal;
@@ -10701,27 +11515,28 @@ update_static_tracepoint (struct breakpoint *b, struct symtab_and_line sal)
   if (!sal.explicit_pc
       && sal.line != 0
       && sal.symtab != NULL
-      && b->static_trace_marker_id != NULL)
+      && tp->static_trace_marker_id != NULL)
     {
       VEC(static_tracepoint_marker_p) *markers;
 
       markers
-       = target_static_tracepoint_markers_by_strid (b->static_trace_marker_id);
+       = target_static_tracepoint_markers_by_strid (tp->static_trace_marker_id);
 
       if (!VEC_empty(static_tracepoint_marker_p, markers))
        {
          struct symtab_and_line sal;
          struct symbol *sym;
          struct static_tracepoint_marker *marker;
+         struct ui_out *uiout = current_uiout;
 
          marker = VEC_index (static_tracepoint_marker_p, markers, 0);
 
-         xfree (b->static_trace_marker_id);
-         b->static_trace_marker_id = xstrdup (marker->str_id);
+         xfree (tp->static_trace_marker_id);
+         tp->static_trace_marker_id = xstrdup (marker->str_id);
 
          warning (_("marker for static tracepoint %d (%s) not "
                     "found at previous line number"),
-                  b->number, b->static_trace_marker_id);
+                  b->number, tp->static_trace_marker_id);
 
          init_sal (&sal);
 
@@ -10936,14 +11751,16 @@ addr_string_to_sals (struct breakpoint *b, char *addr_string, int *found)
     {
       if (marker_spec)
        {
+         struct tracepoint *tp = (struct tracepoint *) b;
+
          sals = decode_static_tracepoint_spec (&s);
-         if (sals.nelts > b->static_trace_marker_id_idx)
+         if (sals.nelts > tp->static_trace_marker_id_idx)
            {
-             sals.sals[0] = sals.sals[b->static_trace_marker_id_idx];
+             sals.sals[0] = sals.sals[tp->static_trace_marker_id_idx];
              sals.nelts = 1;
            }
          else
-           error (_("marker %s not found"), b->static_trace_marker_id);
+           error (_("marker %s not found"), tp->static_trace_marker_id);
        }
       else
        sals = decode_line_1 (&s, 1, (struct symtab *) NULL, 0, NULL);
@@ -11008,23 +11825,17 @@ addr_string_to_sals (struct breakpoint *b, char *addr_string, int *found)
   return sals;
 }
 
-/* Reevaluate a hardware or software breakpoint and recreate its locations.
-   This is necessary after symbols are read (e.g., an executable or DSO
-   was loaded, or the inferior just started).  */
+/* The default re_set method, for typical hardware or software
+   breakpoints.  Reevaluate the breakpoint and recreate its
+   locations.  */
 
 static void
-re_set_breakpoint (struct breakpoint *b)
+breakpoint_re_set_default (struct breakpoint *b)
 {
   int found;
   struct symtabs_and_lines sals, sals_end;
   struct symtabs_and_lines expanded = {0};
   struct symtabs_and_lines expanded_end = {0};
-  struct cleanup *cleanups = make_cleanup (null_cleanup, NULL);
-
-  input_radix = b->input_radix;
-  save_current_space_and_thread ();
-  switch_to_program_space_and_thread (b->pspace);
-  set_language (b->language);
 
   sals = addr_string_to_sals (b, b->addr_string, &found);
   if (found)
@@ -11044,7 +11855,21 @@ re_set_breakpoint (struct breakpoint *b)
     }
 
   update_breakpoint_locations (b, expanded, expanded_end);
-  do_cleanups (cleanups);
+}
+
+/* Prepare the global context for a re-set of breakpoint B.  */
+
+static struct cleanup *
+prepare_re_set_context (struct breakpoint *b)
+{
+  struct cleanup *cleanups;
+
+  input_radix = b->input_radix;
+  cleanups = save_current_space_and_thread ();
+  switch_to_program_space_and_thread (b->pspace);
+  set_language (b->language);
+
+  return cleanups;
 }
 
 /* Reset a breakpoint given it's struct breakpoint * BINT.
@@ -11056,111 +11881,11 @@ breakpoint_re_set_one (void *bint)
 {
   /* Get past catch_errs.  */
   struct breakpoint *b = (struct breakpoint *) bint;
+  struct cleanup *cleanups;
 
-  switch (b->type)
-    {
-    case bp_none:
-      warning (_("attempted to reset apparently deleted breakpoint #%d?"),
-              b->number);
-      return 0;
-    case bp_breakpoint:
-    case bp_hardware_breakpoint:
-    case bp_tracepoint:
-    case bp_fast_tracepoint:
-    case bp_static_tracepoint:
-    case bp_gnu_ifunc_resolver:
-      /* Do not attempt to re-set breakpoints disabled during startup.  */
-      if (b->enable_state == bp_startup_disabled)
-       return 0;
-
-      if (b->addr_string == NULL)
-       {
-         /* Anything without a string can't be re-set.  */
-         delete_breakpoint (b);
-         return 0;
-       }
-
-      re_set_breakpoint (b);
-      break;
-
-    case bp_watchpoint:
-    case bp_hardware_watchpoint:
-    case bp_read_watchpoint:
-    case bp_access_watchpoint:
-      /* Watchpoint can be either on expression using entirely global
-        variables, or it can be on local variables.
-
-        Watchpoints of the first kind are never auto-deleted, and
-        even persist across program restarts. Since they can use
-        variables from shared libraries, we need to reparse
-        expression as libraries are loaded and unloaded.
-
-        Watchpoints on local variables can also change meaning as
-        result of solib event.  For example, if a watchpoint uses
-        both a local and a global variables in expression, it's a
-        local watchpoint, but unloading of a shared library will make
-        the expression invalid.  This is not a very common use case,
-        but we still re-evaluate expression, to avoid surprises to
-        the user.
-
-        Note that for local watchpoints, we re-evaluate it only if
-        watchpoints frame id is still valid.  If it's not, it means
-        the watchpoint is out of scope and will be deleted soon.  In
-        fact, I'm not sure we'll ever be called in this case.
-
-        If a local watchpoint's frame id is still valid, then
-        b->exp_valid_block is likewise valid, and we can safely use it.
-        
-        Don't do anything about disabled watchpoints, since they will
-        be reevaluated again when enabled.  */
-      update_watchpoint (b, 1 /* reparse */);
-      break;
-      /* We needn't really do anything to reset these, since the mask
-         that requests them is unaffected by e.g., new libraries being
-         loaded.  */
-    case bp_catchpoint:
-      break;
-
-    default:
-      printf_filtered (_("Deleting unknown breakpoint type %d\n"), b->type);
-      /* fall through */
-      /* Delete overlay event and longjmp master breakpoints; they will be
-        reset later by breakpoint_re_set.  */
-    case bp_overlay_event:
-    case bp_longjmp_master:
-    case bp_std_terminate_master:
-    case bp_exception_master:
-      delete_breakpoint (b);
-      break;
-
-      /* This breakpoint is special, it's set up when the inferior
-         starts and we really don't want to touch it.  */
-    case bp_shlib_event:
-
-      /* Like bp_shlib_event, this breakpoint type is special.
-        Once it is set up, we do not want to touch it.  */
-    case bp_thread_event:
-
-      /* Keep temporary breakpoints, which can be encountered when we
-         step over a dlopen call and SOLIB_ADD is resetting the
-         breakpoints.  Otherwise these should have been blown away via
-         the cleanup chain or by breakpoint_init_inferior when we
-         rerun the executable.  */
-    case bp_until:
-    case bp_finish:
-    case bp_watchpoint_scope:
-    case bp_call_dummy:
-    case bp_std_terminate:
-    case bp_step_resume:
-    case bp_longjmp:
-    case bp_longjmp_resume:
-    case bp_exception:
-    case bp_exception_resume:
-    case bp_jit_event:
-    case bp_gnu_ifunc_resolver_return:
-      break;
-    }
-
+  cleanups = prepare_re_set_context (b);
+  b->ops->re_set (b);
+  do_cleanups (cleanups);
   return 0;
 }
 
@@ -11323,25 +12048,8 @@ map_breakpoint_numbers (char *args, void (*function) (struct breakpoint *,
          ALL_BREAKPOINTS_SAFE (b, tmp)
            if (b->number == num)
              {
-               struct breakpoint *related_breakpoint;
-
                match = 1;
-               related_breakpoint = b;
-               do
-                 {
-                   struct breakpoint *next_related_b;
-
-                   /* FUNCTION can be also delete_breakpoint.  */
-                   next_related_b = related_breakpoint->related_breakpoint;
-                   function (related_breakpoint, data);
-
-                   /* For delete_breakpoint of the last entry of the ring we
-                      were traversing we would never get back to B.  */
-                   if (next_related_b == related_breakpoint)
-                     break;
-                   related_breakpoint = next_related_b;
-                 }
-               while (related_breakpoint != b);
+               function (b, data);
                break;
              }
          if (match == 0)
@@ -11411,18 +12119,35 @@ disable_breakpoint (struct breakpoint *bpt)
 
   bpt->enable_state = bp_disabled;
 
+  if (target_supports_enable_disable_tracepoint ()
+      && current_trace_status ()->running && is_tracepoint (bpt))
+    {
+      struct bp_location *location;
+     
+      for (location = bpt->loc; location; location = location->next)
+       target_disable_tracepoint (location);
+    }
+
   update_global_location_list (0);
 
   observer_notify_breakpoint_modified (bpt);
 }
 
+/* A callback for iterate_over_related_breakpoints.  */
+
+static void
+do_disable_breakpoint (struct breakpoint *b, void *ignore)
+{
+  disable_breakpoint (b);
+}
+
 /* A callback for map_breakpoint_numbers that calls
    disable_breakpoint.  */
 
 static void
 do_map_disable_breakpoint (struct breakpoint *b, void *ignore)
 {
-  disable_breakpoint (b);
+  iterate_over_related_breakpoints (b, do_disable_breakpoint, NULL);
 }
 
 static void
@@ -11440,7 +12165,13 @@ disable_command (char *args, int from_tty)
     {
       struct bp_location *loc = find_location_by_number (args);
       if (loc)
-       loc->enabled = 0;
+       {
+         loc->enabled = 0;
+         if (target_supports_enable_disable_tracepoint ()
+             && current_trace_status ()->running && loc->owner
+             && is_tracepoint (loc->owner))
+           target_disable_tracepoint (loc);
+       }
       update_global_location_list (0);
     }
   else
@@ -11448,7 +12179,7 @@ disable_command (char *args, int from_tty)
 }
 
 static void
-do_enable_breakpoint (struct breakpoint *bpt, enum bpdisp disposition)
+enable_breakpoint_disp (struct breakpoint *bpt, enum bpdisp disposition)
 {
   int target_resources_ok;
 
@@ -11473,9 +12204,11 @@ do_enable_breakpoint (struct breakpoint *bpt, enum bpdisp disposition)
 
       TRY_CATCH (e, RETURN_MASK_ALL)
        {
+         struct watchpoint *w = (struct watchpoint *) bpt;
+
          orig_enable_state = bpt->enable_state;
          bpt->enable_state = bp_enabled;
-         update_watchpoint (bpt, 1 /* reparse */);
+         update_watchpoint (w, 1 /* reparse */);
        }
       if (e.reason < 0)
        {
@@ -11488,6 +12221,16 @@ do_enable_breakpoint (struct breakpoint *bpt, enum bpdisp disposition)
 
   if (bpt->enable_state != bp_permanent)
     bpt->enable_state = bp_enabled;
+
+  if (target_supports_enable_disable_tracepoint ()
+      && current_trace_status ()->running && is_tracepoint (bpt))
+    {
+      struct bp_location *location;
+
+      for (location = bpt->loc; location; location = location->next)
+       target_enable_tracepoint (location);
+    }
+
   bpt->disposition = disposition;
   update_global_location_list (1);
   breakpoints_changed ();
@@ -11499,7 +12242,13 @@ do_enable_breakpoint (struct breakpoint *bpt, enum bpdisp disposition)
 void
 enable_breakpoint (struct breakpoint *bpt)
 {
-  do_enable_breakpoint (bpt, bpt->disposition);
+  enable_breakpoint_disp (bpt, bpt->disposition);
+}
+
+static void
+do_enable_breakpoint (struct breakpoint *bpt, void *arg)
+{
+  enable_breakpoint (bpt);
 }
 
 /* A callback for map_breakpoint_numbers that calls
@@ -11508,7 +12257,7 @@ enable_breakpoint (struct breakpoint *bpt)
 static void
 do_map_enable_breakpoint (struct breakpoint *b, void *ignore)
 {
-  enable_breakpoint (b);
+  iterate_over_related_breakpoints (b, do_enable_breakpoint, NULL);
 }
 
 /* The enable command enables the specified breakpoints (or all defined
@@ -11530,7 +12279,13 @@ enable_command (char *args, int from_tty)
     {
       struct bp_location *loc = find_location_by_number (args);
       if (loc)
-       loc->enabled = 1;
+       {
+         loc->enabled = 1;
+         if (target_supports_enable_disable_tracepoint ()
+             && current_trace_status ()->running && loc->owner
+             && is_tracepoint (loc->owner))
+           target_enable_tracepoint (loc);
+       }
       update_global_location_list (1);
     }
   else
@@ -11538,27 +12293,39 @@ enable_command (char *args, int from_tty)
 }
 
 static void
-enable_once_breakpoint (struct breakpoint *bpt, void *ignore)
+do_enable_breakpoint_disp (struct breakpoint *bpt, void *arg)
+{
+  enum bpdisp disp = *(enum bpdisp *) arg;
+
+  enable_breakpoint_disp (bpt, disp);
+}
+
+static void
+do_map_enable_once_breakpoint (struct breakpoint *bpt, void *ignore)
 {
-  do_enable_breakpoint (bpt, disp_disable);
+  enum bpdisp disp = disp_disable;
+
+  iterate_over_related_breakpoints (bpt, do_enable_breakpoint_disp, &disp);
 }
 
 static void
 enable_once_command (char *args, int from_tty)
 {
-  map_breakpoint_numbers (args, enable_once_breakpoint, NULL);
+  map_breakpoint_numbers (args, do_map_enable_once_breakpoint, NULL);
 }
 
 static void
-enable_delete_breakpoint (struct breakpoint *bpt, void *ignore)
+do_map_enable_delete_breakpoint (struct breakpoint *bpt, void *ignore)
 {
-  do_enable_breakpoint (bpt, disp_del);
+  enum bpdisp disp = disp_del;
+
+  iterate_over_related_breakpoints (bpt, do_enable_breakpoint_disp, &disp);
 }
 
 static void
 enable_delete_command (char *args, int from_tty)
 {
-  map_breakpoint_numbers (args, enable_delete_breakpoint, NULL);
+  map_breakpoint_numbers (args, do_map_enable_delete_breakpoint, NULL);
 }
 \f
 static void
@@ -11583,20 +12350,24 @@ invalidate_bp_value_on_memory_change (CORE_ADDR addr, int len,
 
   ALL_BREAKPOINTS (bp)
     if (bp->enable_state == bp_enabled
-       && bp->type == bp_hardware_watchpoint
-       && bp->val_valid && bp->val)
+       && bp->type == bp_hardware_watchpoint)
       {
-       struct bp_location *loc;
+       struct watchpoint *wp = (struct watchpoint *) bp;
 
-       for (loc = bp->loc; loc != NULL; loc = loc->next)
-         if (loc->loc_type == bp_loc_hardware_watchpoint
-             && loc->address + loc->length > addr
-             && addr + len > loc->address)
-           {
-             value_free (bp->val);
-             bp->val = NULL;
-             bp->val_valid = 0;
-           }
+       if (wp->val_valid && wp->val)
+         {
+           struct bp_location *loc;
+
+           for (loc = bp->loc; loc != NULL; loc = loc->next)
+             if (loc->loc_type == bp_loc_hardware_watchpoint
+                 && loc->address + loc->length > addr
+                 && addr + len > loc->address)
+               {
+                 value_free (wp->val);
+                 wp->val = NULL;
+                 wp->val_valid = 0;
+               }
+         }
       }
 }
 
@@ -11821,11 +12592,13 @@ catching_syscall_number (int syscall_number)
   ALL_BREAKPOINTS (bp)
     if (is_syscall_catchpoint_enabled (bp))
       {
-       if (bp->syscalls_to_be_caught)
+       struct syscall_catchpoint *c = (struct syscall_catchpoint *) bp;
+
+       if (c->syscalls_to_be_caught)
          {
             int i, iter;
             for (i = 0;
-                 VEC_iterate (int, bp->syscalls_to_be_caught, i, iter);
+                 VEC_iterate (int, c->syscalls_to_be_caught, i, iter);
                  i++)
              if (syscall_number == iter)
                return 1;
@@ -11870,7 +12643,7 @@ trace_command (char *arg, int from_tty)
                         bp_tracepoint /* type_wanted */,
                         0 /* Ignore count */,
                         pending_break_support,
-                        NULL,
+                        &tracepoint_breakpoint_ops,
                         from_tty,
                         1 /* enabled */,
                         0 /* internal */))
@@ -11887,7 +12660,7 @@ ftrace_command (char *arg, int from_tty)
                         bp_fast_tracepoint /* type_wanted */,
                         0 /* Ignore count */,
                         pending_break_support,
-                        NULL,
+                        &tracepoint_breakpoint_ops,
                         from_tty,
                         1 /* enabled */,
                         0 /* internal */))
@@ -11906,7 +12679,7 @@ strace_command (char *arg, int from_tty)
                         bp_static_tracepoint /* type_wanted */,
                         0 /* Ignore count */,
                         pending_break_support,
-                        NULL,
+                        &tracepoint_breakpoint_ops,
                         from_tty,
                         1 /* enabled */,
                         0 /* internal */))
@@ -11937,11 +12710,11 @@ read_uploaded_action (void)
    the target does not necessarily have all the information used when
    the tracepoint was originally defined.  */
   
-struct breakpoint *
+struct tracepoint *
 create_tracepoint_from_upload (struct uploaded_tp *utp)
 {
   char *addr_str, small_buf[100];
-  struct breakpoint *tp;
+  struct tracepoint *tp;
 
   if (utp->at_string)
     addr_str = utp->at_string;
@@ -11971,7 +12744,7 @@ create_tracepoint_from_upload (struct uploaded_tp *utp)
                          utp->type /* type_wanted */,
                          0 /* Ignore count */,
                          pending_break_support,
-                         NULL,
+                         &tracepoint_breakpoint_ops,
                          0 /* from_tty */,
                          utp->enabled /* enabled */,
                          0 /* internal */))
@@ -11985,7 +12758,7 @@ create_tracepoint_from_upload (struct uploaded_tp *utp)
 
   if (utp->pass > 0)
     {
-      sprintf (small_buf, "%d %d", utp->pass, tp->number);
+      sprintf (small_buf, "%d %d", utp->pass, tp->base.number);
 
       trace_pass_command (small_buf, 0);
     }
@@ -12003,7 +12776,7 @@ create_tracepoint_from_upload (struct uploaded_tp *utp)
 
       cmd_list = read_command_lines_1 (read_uploaded_action, 1, NULL, NULL);
 
-      breakpoint_set_commands (tp, cmd_list);
+      breakpoint_set_commands (&tp->base, cmd_list);
     }
   else if (!VEC_empty (char_ptr, utp->actions)
           || !VEC_empty (char_ptr, utp->step_actions))
@@ -12012,7 +12785,7 @@ create_tracepoint_from_upload (struct uploaded_tp *utp)
             utp->number);
 
   return tp;
-  }
+}
   
 /* Print information on tracepoint number TPNUM_EXP, or all if
    omitted.  */
@@ -12020,6 +12793,7 @@ create_tracepoint_from_upload (struct uploaded_tp *utp)
 static void
 tracepoints_info (char *args, int from_tty)
 {
+  struct ui_out *uiout = current_uiout;
   int num_printed;
 
   num_printed = breakpoint_1 (args, 0, is_tracepoint);
@@ -12084,19 +12858,19 @@ delete_trace_command (char *arg, int from_tty)
        }
     }
   else
-    map_breakpoint_numbers (arg, do_delete_breakpoint, NULL);
+    map_breakpoint_numbers (arg, do_map_delete_breakpoint, NULL);
 }
 
 /* Helper function for trace_pass_command.  */
 
 static void
-trace_pass_set_count (struct breakpoint *bp, int count, int from_tty)
+trace_pass_set_count (struct tracepoint *tp, int count, int from_tty)
 {
-  bp->pass_count = count;
-  observer_notify_tracepoint_modified (bp->number);
+  tp->pass_count = count;
+  observer_notify_tracepoint_modified (tp->base.number);
   if (from_tty)
     printf_filtered (_("Setting tracepoint %d's passcount to %d\n"),
-                    bp->number, count);
+                    tp->base.number, count);
 }
 
 /* Set passcount for tracepoint.
@@ -12108,7 +12882,7 @@ trace_pass_set_count (struct breakpoint *bp, int count, int from_tty)
 static void
 trace_pass_command (char *args, int from_tty)
 {
-  struct breakpoint *t1;
+  struct tracepoint *t1;
   unsigned int count;
 
   if (args == 0 || *args == 0)
@@ -12122,12 +12896,15 @@ trace_pass_command (char *args, int from_tty)
 
   if (*args && strncasecmp (args, "all", 3) == 0)
     {
+      struct breakpoint *b;
+
       args += 3;                       /* Skip special argument "all".  */
       if (*args)
        error (_("Junk at end of arguments."));
 
-      ALL_TRACEPOINTS (t1)
+      ALL_TRACEPOINTS (b)
       {
+       t1 = (struct tracepoint *) b;
        trace_pass_set_count (t1, count, from_tty);
       }
     }
@@ -12151,14 +12928,14 @@ trace_pass_command (char *args, int from_tty)
     }
 }
 
-struct breakpoint *
+struct tracepoint *
 get_tracepoint (int num)
 {
   struct breakpoint *t;
 
   ALL_TRACEPOINTS (t)
     if (t->number == num)
-      return t;
+      return (struct tracepoint *) t;
 
   return NULL;
 }
@@ -12167,14 +12944,18 @@ get_tracepoint (int num)
    different from the tracepoint number after disconnecting and
    reconnecting).  */
 
-struct breakpoint *
+struct tracepoint *
 get_tracepoint_by_number_on_target (int num)
 {
-  struct breakpoint *t;
+  struct breakpoint *b;
 
-  ALL_TRACEPOINTS (t)
-    if (t->number_on_target == num)
-      return t;
+  ALL_TRACEPOINTS (b)
+    {
+      struct tracepoint *t = (struct tracepoint *) b;
+
+      if (t->number_on_target == num)
+       return t;
+    }
 
   return NULL;
 }
@@ -12183,7 +12964,7 @@ get_tracepoint_by_number_on_target (int num)
    If STATE is not NULL, use, get_number_or_range_state and ignore ARG.
    If OPTIONAL_P is true, then if the argument is missing, the most
    recent tracepoint (tracepoint_count) is returned.  */
-struct breakpoint *
+struct tracepoint *
 get_tracepoint_by_number (char **arg,
                          struct get_number_or_range_state *state,
                          int optional_p)
@@ -12222,13 +13003,25 @@ get_tracepoint_by_number (char **arg,
   ALL_TRACEPOINTS (t)
     if (t->number == tpnum)
     {
-      return t;
+      return (struct tracepoint *) t;
     }
 
   printf_unfiltered ("No tracepoint number %d.\n", tpnum);
   return NULL;
 }
 
+void
+print_recreate_thread (struct breakpoint *b, struct ui_file *fp)
+{
+  if (b->thread != -1)
+    fprintf_unfiltered (fp, " thread %d", b->thread);
+
+  if (b->task != 0)
+    fprintf_unfiltered (fp, " task %d", b->task);
+
+  fprintf_unfiltered (fp, "\n");
+}
+
 /* Save information on user settable breakpoints (watchpoints, etc) to
    a new script file named FILENAME.  If FILTER is non-NULL, call it
    on each breakpoint and only include the ones for which it returns
@@ -12297,57 +13090,7 @@ save_breakpoints (char *filename, int from_tty,
     if (filter && !filter (tp))
       continue;
 
-    if (tp->ops != NULL && tp->ops->print_recreate != NULL)
-      (tp->ops->print_recreate) (tp, fp);
-    else
-      {
-       if (tp->type == bp_fast_tracepoint)
-         fprintf_unfiltered (fp, "ftrace");
-       if (tp->type == bp_static_tracepoint)
-         fprintf_unfiltered (fp, "strace");
-       else if (tp->type == bp_tracepoint)
-         fprintf_unfiltered (fp, "trace");
-       else if (tp->type == bp_breakpoint && tp->disposition == disp_del)
-         fprintf_unfiltered (fp, "tbreak");
-       else if (tp->type == bp_breakpoint)
-         fprintf_unfiltered (fp, "break");
-       else if (tp->type == bp_hardware_breakpoint
-                && tp->disposition == disp_del)
-         fprintf_unfiltered (fp, "thbreak");
-       else if (tp->type == bp_hardware_breakpoint)
-         fprintf_unfiltered (fp, "hbreak");
-       else if (tp->type == bp_watchpoint)
-         fprintf_unfiltered (fp, "watch");
-       else if (tp->type == bp_hardware_watchpoint)
-         fprintf_unfiltered (fp, "watch");
-       else if (tp->type == bp_read_watchpoint)
-         fprintf_unfiltered (fp, "rwatch");
-       else if (tp->type == bp_access_watchpoint)
-         fprintf_unfiltered (fp, "awatch");
-       else
-         internal_error (__FILE__, __LINE__,
-                         _("unhandled breakpoint type %d"), (int) tp->type);
-
-       if (tp->exp_string)
-         fprintf_unfiltered (fp, " %s", tp->exp_string);
-       else if (tp->addr_string)
-         fprintf_unfiltered (fp, " %s", tp->addr_string);
-       else
-         {
-           char tmp[40];
-
-           sprintf_vma (tmp, tp->loc->address);
-           fprintf_unfiltered (fp, " *0x%s", tmp);
-         }
-      }
-
-    if (tp->thread != -1)
-      fprintf_unfiltered (fp, " thread %d", tp->thread);
-
-    if (tp->task != 0)
-      fprintf_unfiltered (fp, " task %d", tp->task);
-
-    fprintf_unfiltered (fp, "\n");
+    tp->ops->print_recreate (tp, fp);
 
     /* Note, we can't rely on tp->number for anything, as we can't
        assume the recreated breakpoint numbers will match.  Use $bpnum
@@ -12359,21 +13102,18 @@ save_breakpoints (char *filename, int from_tty,
     if (tp->ignore_count)
       fprintf_unfiltered (fp, "  ignore $bpnum %d\n", tp->ignore_count);
 
-    if (tp->pass_count)
-      fprintf_unfiltered (fp, "  passcount %d\n", tp->pass_count);
-
     if (tp->commands)
       {
        volatile struct gdb_exception ex;       
 
        fprintf_unfiltered (fp, "  commands\n");
        
-       ui_out_redirect (uiout, fp);
+       ui_out_redirect (current_uiout, fp);
        TRY_CATCH (ex, RETURN_MASK_ALL)
          {
-           print_command_lines (uiout, tp->commands->commands, 2);
+           print_command_lines (current_uiout, tp->commands->commands, 2);
          }
-       ui_out_redirect (uiout, NULL);
+       ui_out_redirect (current_uiout, NULL);
 
        if (ex.reason < 0)
          throw_exception (ex);
@@ -12466,9 +13206,7 @@ static struct cmd_list_element *catch_cmdlist;
 /* List of subcommands for "tcatch".  */
 static struct cmd_list_element *tcatch_cmdlist;
 
-/* Like add_cmd, but add the command to both the "catch" and "tcatch"
-   lists, and pass some additional user data to the command function.  */
-static void
+void
 add_catch_command (char *name, char *docstring,
                   void (*sfunc) (char *args, int from_tty,
                                  struct cmd_list_element *command),
@@ -12523,11 +13261,161 @@ iterate_over_breakpoints (int (*callback) (struct breakpoint *, void *),
   return NULL;
 }
 
+void
+initialize_breakpoint_ops (void)
+{
+  static int initialized = 0;
+
+  struct breakpoint_ops *ops;
+
+  if (initialized)
+    return;
+  initialized = 1;
+
+  /* The breakpoint_ops structure to be inherit by all kinds of
+     breakpoints (real breakpoints, i.e., user "break" breakpoints,
+     internal and momentary breakpoints, etc.).  */
+  ops = &bkpt_base_breakpoint_ops;
+  *ops = base_breakpoint_ops;
+  ops->re_set = bkpt_re_set;
+  ops->insert_location = bkpt_insert_location;
+  ops->remove_location = bkpt_remove_location;
+  ops->breakpoint_hit = bkpt_breakpoint_hit;
+
+  /* The breakpoint_ops structure to be used in regular breakpoints.  */
+  ops = &bkpt_breakpoint_ops;
+  *ops = bkpt_base_breakpoint_ops;
+  ops->re_set = bkpt_re_set;
+  ops->resources_needed = bkpt_resources_needed;
+  ops->print_it = bkpt_print_it;
+  ops->print_mention = bkpt_print_mention;
+  ops->print_recreate = bkpt_print_recreate;
+
+  /* Ranged breakpoints.  */
+  ops = &ranged_breakpoint_ops;
+  *ops = bkpt_breakpoint_ops;
+  ops->breakpoint_hit = breakpoint_hit_ranged_breakpoint;
+  ops->resources_needed = resources_needed_ranged_breakpoint;
+  ops->print_it = print_it_ranged_breakpoint;
+  ops->print_one = print_one_ranged_breakpoint;
+  ops->print_one_detail = print_one_detail_ranged_breakpoint;
+  ops->print_mention = print_mention_ranged_breakpoint;
+  ops->print_recreate = print_recreate_ranged_breakpoint;
+
+  /* Internal breakpoints.  */
+  ops = &internal_breakpoint_ops;
+  *ops = bkpt_base_breakpoint_ops;
+  ops->re_set = internal_bkpt_re_set;
+  ops->check_status = internal_bkpt_check_status;
+  ops->print_it = internal_bkpt_print_it;
+  ops->print_mention = internal_bkpt_print_mention;
+
+  /* Momentary breakpoints.  */
+  ops = &momentary_breakpoint_ops;
+  *ops = bkpt_base_breakpoint_ops;
+  ops->re_set = momentary_bkpt_re_set;
+  ops->check_status = momentary_bkpt_check_status;
+  ops->print_it = momentary_bkpt_print_it;
+  ops->print_mention = momentary_bkpt_print_mention;
+
+  /* GNU v3 exception catchpoints.  */
+  ops = &gnu_v3_exception_catchpoint_ops;
+  *ops = bkpt_breakpoint_ops;
+  ops->print_it = print_it_exception_catchpoint;
+  ops->print_one = print_one_exception_catchpoint;
+  ops->print_mention = print_mention_exception_catchpoint;
+  ops->print_recreate = print_recreate_exception_catchpoint;
+
+  /* Watchpoints.  */
+  ops = &watchpoint_breakpoint_ops;
+  *ops = base_breakpoint_ops;
+  ops->dtor = dtor_watchpoint;
+  ops->re_set = re_set_watchpoint;
+  ops->insert_location = insert_watchpoint;
+  ops->remove_location = remove_watchpoint;
+  ops->breakpoint_hit = breakpoint_hit_watchpoint;
+  ops->check_status = check_status_watchpoint;
+  ops->resources_needed = resources_needed_watchpoint;
+  ops->works_in_software_mode = works_in_software_mode_watchpoint;
+  ops->print_it = print_it_watchpoint;
+  ops->print_mention = print_mention_watchpoint;
+  ops->print_recreate = print_recreate_watchpoint;
+
+  /* Masked watchpoints.  */
+  ops = &masked_watchpoint_breakpoint_ops;
+  *ops = watchpoint_breakpoint_ops;
+  ops->insert_location = insert_masked_watchpoint;
+  ops->remove_location = remove_masked_watchpoint;
+  ops->resources_needed = resources_needed_masked_watchpoint;
+  ops->works_in_software_mode = works_in_software_mode_masked_watchpoint;
+  ops->print_it = print_it_masked_watchpoint;
+  ops->print_one_detail = print_one_detail_masked_watchpoint;
+  ops->print_mention = print_mention_masked_watchpoint;
+  ops->print_recreate = print_recreate_masked_watchpoint;
+
+  /* Tracepoints.  */
+  ops = &tracepoint_breakpoint_ops;
+  *ops = base_breakpoint_ops;
+  ops->re_set = tracepoint_re_set;
+  ops->breakpoint_hit = tracepoint_breakpoint_hit;
+  ops->print_one_detail = tracepoint_print_one_detail;
+  ops->print_mention = tracepoint_print_mention;
+  ops->print_recreate = tracepoint_print_recreate;
+
+  /* Fork catchpoints.  */
+  ops = &catch_fork_breakpoint_ops;
+  *ops = base_breakpoint_ops;
+  ops->insert_location = insert_catch_fork;
+  ops->remove_location = remove_catch_fork;
+  ops->breakpoint_hit = breakpoint_hit_catch_fork;
+  ops->print_it = print_it_catch_fork;
+  ops->print_one = print_one_catch_fork;
+  ops->print_mention = print_mention_catch_fork;
+  ops->print_recreate = print_recreate_catch_fork;
+
+  /* Vfork catchpoints.  */
+  ops = &catch_vfork_breakpoint_ops;
+  *ops = base_breakpoint_ops;
+  ops->insert_location = insert_catch_vfork;
+  ops->remove_location = remove_catch_vfork;
+  ops->breakpoint_hit = breakpoint_hit_catch_vfork;
+  ops->print_it = print_it_catch_vfork;
+  ops->print_one = print_one_catch_vfork;
+  ops->print_mention = print_mention_catch_vfork;
+  ops->print_recreate = print_recreate_catch_vfork;
+
+  /* Exec catchpoints.  */
+  ops = &catch_exec_breakpoint_ops;
+  *ops = base_breakpoint_ops;
+  ops->dtor = dtor_catch_exec;
+  ops->insert_location = insert_catch_exec;
+  ops->remove_location = remove_catch_exec;
+  ops->breakpoint_hit = breakpoint_hit_catch_exec;
+  ops->print_it = print_it_catch_exec;
+  ops->print_one = print_one_catch_exec;
+  ops->print_mention = print_mention_catch_exec;
+  ops->print_recreate = print_recreate_catch_exec;
+
+  /* Syscall catchpoints.  */
+  ops = &catch_syscall_breakpoint_ops;
+  *ops = base_breakpoint_ops;
+  ops->dtor = dtor_catch_syscall;
+  ops->insert_location = insert_catch_syscall;
+  ops->remove_location = remove_catch_syscall;
+  ops->breakpoint_hit = breakpoint_hit_catch_syscall;
+  ops->print_it = print_it_catch_syscall;
+  ops->print_one = print_one_catch_syscall;
+  ops->print_mention = print_mention_catch_syscall;
+  ops->print_recreate = print_recreate_catch_syscall;
+}
+
 void
 _initialize_breakpoint (void)
 {
   struct cmd_list_element *c;
 
+  initialize_breakpoint_ops ();
+
   observer_attach_solib_unloaded (disable_breakpoints_in_unloaded_shlib);
   observer_attach_inferior_exit (clear_syscall_counts);
   observer_attach_memory_changed (invalidate_bp_value_on_memory_change);
@@ -12634,7 +13522,7 @@ If a breakpoint is hit while enabled in this fashion, it becomes disabled."),
 Disable some breakpoints.\n\
 Arguments are breakpoint numbers with spaces in between.\n\
 To disable all breakpoints, give no argument.\n\
-A disabled breakpoint is not forgotten, but has no effect until reenabled."),
+A disabled breakpoint is not forgotten, but has no effect until re-enabled."),
                  &disablelist, "disable ", 1, &cmdlist);
   add_com_alias ("dis", "disable", class_breakpoint, 1);
   add_com_alias ("disa", "disable", class_breakpoint, 1);
@@ -12643,13 +13531,13 @@ A disabled breakpoint is not forgotten, but has no effect until reenabled."),
 Disable some breakpoints.\n\
 Arguments are breakpoint numbers with spaces in between.\n\
 To disable all breakpoints, give no argument.\n\
-A disabled breakpoint is not forgotten, but has no effect until reenabled."));
+A disabled breakpoint is not forgotten, but has no effect until re-enabled."));
 
   add_cmd ("breakpoints", class_alias, disable_command, _("\
 Disable some breakpoints.\n\
 Arguments are breakpoint numbers with spaces in between.\n\
 To disable all breakpoints, give no argument.\n\
-A disabled breakpoint is not forgotten, but has no effect until reenabled.\n\
+A disabled breakpoint is not forgotten, but has no effect until re-enabled.\n\
 This command may be abbreviated \"disable\"."),
           &disablelist);
 
@@ -12834,20 +13722,6 @@ Arguments, if given, should be one or more system call names\n\
                     catch_syscall_completer,
                     CATCH_PERMANENT,
                     CATCH_TEMPORARY);
-  add_catch_command ("exception", _("\
-Catch Ada exceptions, when raised.\n\
-With an argument, catch only exceptions with the given name."),
-                    catch_ada_exception_command,
-                     NULL,
-                    CATCH_PERMANENT,
-                    CATCH_TEMPORARY);
-  add_catch_command ("assert", _("\
-Catch failed Ada assertions, when raised.\n\
-With an argument, catch only exceptions with the given name."),
-                    catch_assert_command,
-                     NULL,
-                    CATCH_PERMANENT,
-                    CATCH_TEMPORARY);
 
   c = add_com ("watch", class_breakpoint, watch_command, _("\
 Set a watchpoint for an expression.\n\
This page took 0.128181 seconds and 4 git commands to generate.