]> git.ipfire.org Git - thirdparty/binutils-gdb.git/blobdiff - gdb/gdbserver/mem-break.c
Replace write_inferior_memory with target_write_memory
[thirdparty/binutils-gdb.git] / gdb / gdbserver / mem-break.c
index c808a84d751a0cdbdfa221673672904cb29e0542..582fcac1632a226452c88ba9a614b18cf871e5b7 100644 (file)
@@ -1,5 +1,5 @@
 /* Memory breakpoint operations for the remote server for GDB.
-   Copyright (C) 2002-2015 Free Software Foundation, Inc.
+   Copyright (C) 2002-2019 Free Software Foundation, Inc.
 
    Contributed by MontaVista Software.
 
@@ -133,8 +133,8 @@ enum bkpt_type
     /* A GDB access watchpoint, requested with a Z4 packet.  */
     gdb_breakpoint_Z4,
 
-    /* A basic-software-single-step breakpoint.  */
-    reinsert_breakpoint,
+    /* A software single-step breakpoint.  */
+    single_step_breakpoint,
 
     /* Any other breakpoint type that doesn't require specific
        treatment goes here.  E.g., an event breakpoint.  */
@@ -173,6 +173,17 @@ struct breakpoint
   /* The breakpoint's type.  */
   enum bkpt_type type;
 
+  /* Link to this breakpoint's raw breakpoint.  This is always
+     non-NULL.  */
+  struct raw_breakpoint *raw;
+};
+
+/* Breakpoint requested by GDB.  */
+
+struct gdb_breakpoint
+{
+  struct breakpoint base;
+
   /* Pointer to the condition list that should be evaluated on
      the target or NULL if the breakpoint is unconditional or
      if GDB doesn't want us to evaluate the conditionals on the
@@ -181,10 +192,13 @@ struct breakpoint
 
   /* Point to the list of commands to run when this is hit.  */
   struct point_command_list *command_list;
+};
 
-  /* Link to this breakpoint's raw breakpoint.  This is always
-     non-NULL.  */
-  struct raw_breakpoint *raw;
+/* Breakpoint used by GDBserver.  */
+
+struct other_breakpoint
+{
+  struct breakpoint base;
 
   /* Function to call when we hit this breakpoint.  If it returns 1,
      the breakpoint shall be deleted; 0 or if this callback is NULL,
@@ -192,6 +206,16 @@ struct breakpoint
   int (*handler) (CORE_ADDR);
 };
 
+/* Breakpoint for single step.  */
+
+struct single_step_breakpoint
+{
+  struct breakpoint base;
+
+  /* Thread the reinsert breakpoint belongs to.  */
+  ptid_t ptid;
+};
+
 /* Return the breakpoint size from its kind.  */
 
 static int
@@ -266,21 +290,37 @@ Z_packet_to_raw_bkpt_type (char z_type)
     }
 }
 
-int
-any_persistent_commands ()
+/* Return true if breakpoint TYPE is a GDB breakpoint.  */
+
+static int
+is_gdb_breakpoint (enum bkpt_type type)
+{
+  return (type == gdb_breakpoint_Z0
+         || type == gdb_breakpoint_Z1
+         || type == gdb_breakpoint_Z2
+         || type == gdb_breakpoint_Z3
+         || type == gdb_breakpoint_Z4);
+}
+
+bool
+any_persistent_commands (process_info *proc)
 {
-  struct process_info *proc = current_process ();
   struct breakpoint *bp;
   struct point_command_list *cl;
 
   for (bp = proc->breakpoints; bp != NULL; bp = bp->next)
     {
-      for (cl = bp->command_list; cl != NULL; cl = cl->next)
-       if (cl->persistence)
-         return 1;
+      if (is_gdb_breakpoint (bp->type))
+       {
+         struct gdb_breakpoint *gdb_bp = (struct gdb_breakpoint *) bp;
+
+         for (cl = gdb_bp->command_list; cl != NULL; cl = cl->next)
+           if (cl->persistence)
+             return true;
+       }
     }
 
-  return 0;
+  return false;
 }
 
 /* Find low-level breakpoint of type TYPE at address ADDR that is not
@@ -361,15 +401,15 @@ remove_memory_breakpoint (struct raw_breakpoint *bp)
   int err;
 
   /* Since there can be trap breakpoints inserted in the same address
-     range, we use `write_inferior_memory', which takes care of
+     range, we use `target_write_memory', which takes care of
      layering breakpoints on top of fast tracepoints, and on top of
      the buffer we pass it.  This works because the caller has already
      either unlinked the breakpoint or marked it uninserted.  Also
      note that we need to pass the current shadow contents, because
-     write_inferior_memory updates any shadow memory with what we pass
+     target_write_memory updates any shadow memory with what we pass
      here, and we want that to be a nop.  */
   memcpy (buf, bp->old_data, bp_size (bp));
-  err = write_inferior_memory (bp->pc, buf, bp_size (bp));
+  err = target_write_memory (bp->pc, buf, bp_size (bp));
   if (err != 0)
     {
       if (debug_threads)
@@ -408,32 +448,41 @@ set_raw_breakpoint_at (enum raw_bkpt_type type, CORE_ADDR where, int kind,
   else
     bp = find_raw_breakpoint_at (where, type, kind);
 
-  if (bp != NULL)
+  gdb::unique_xmalloc_ptr<struct raw_breakpoint> bp_holder;
+  if (bp == NULL)
     {
-      bp->refcount++;
-      return bp;
+      bp_holder.reset (XCNEW (struct raw_breakpoint));
+      bp = bp_holder.get ();
+      bp->pc = where;
+      bp->kind = kind;
+      bp->raw_type = type;
     }
 
-  bp = XCNEW (struct raw_breakpoint);
-  bp->pc = where;
-  bp->kind = kind;
-  bp->refcount = 1;
-  bp->raw_type = type;
-
-  *err = the_target->insert_point (bp->raw_type, bp->pc, bp->kind, bp);
-  if (*err != 0)
+  if (!bp->inserted)
     {
-      if (debug_threads)
-       debug_printf ("Failed to insert breakpoint at 0x%s (%d).\n",
-                     paddress (where), *err);
-      free (bp);
-      return NULL;
+      *err = the_target->insert_point (bp->raw_type, bp->pc, bp->kind, bp);
+      if (*err != 0)
+       {
+         if (debug_threads)
+           debug_printf ("Failed to insert breakpoint at 0x%s (%d).\n",
+                         paddress (where), *err);
+
+         return NULL;
+       }
+
+      bp->inserted = 1;
     }
 
-  bp->inserted = 1;
-  /* Link the breakpoint in.  */
-  bp->next = proc->raw_breakpoints;
-  proc->raw_breakpoints = bp;
+  /* If the breakpoint was allocated above, we know we want to keep it
+     now.  */
+  bp_holder.release ();
+
+  /* Link the breakpoint in, if this is the first reference.  */
+  if (++bp->refcount == 1)
+    {
+      bp->next = proc->raw_breakpoints;
+      proc->raw_breakpoints = bp;
+    }
   return bp;
 }
 
@@ -529,17 +578,17 @@ delete_fast_tracepoint_jump (struct fast_tracepoint_jump *todel)
              *bp_link = bp->next;
 
              /* Since there can be breakpoints inserted in the same
-                address range, we use `write_inferior_memory', which
+                address range, we use `target_write_memory', which
                 takes care of layering breakpoints on top of fast
                 tracepoints, and on top of the buffer we pass it.
                 This works because we've already unlinked the fast
                 tracepoint jump above.  Also note that we need to
                 pass the current shadow contents, because
-                write_inferior_memory updates any shadow memory with
+                target_write_memory updates any shadow memory with
                 what we pass here, and we want that to be a nop.  */
              buf = (unsigned char *) alloca (bp->length);
              memcpy (buf, fast_tracepoint_jump_shadow (bp), bp->length);
-             ret = write_inferior_memory (bp->pc, buf, bp->length);
+             ret = target_write_memory (bp->pc, buf, bp->length);
              if (ret != 0)
                {
                  /* Something went wrong, relink the jump.  */
@@ -623,14 +672,14 @@ set_fast_tracepoint_jump (CORE_ADDR where,
   proc->fast_tracepoint_jumps = jp;
 
   /* Since there can be trap breakpoints inserted in the same address
-     range, we use use `write_inferior_memory', which takes care of
+     range, we use use `target_write_memory', which takes care of
      layering breakpoints on top of fast tracepoints, on top of the
      buffer we pass it.  This works because we've already linked in
      the fast tracepoint jump above.  Also note that we need to pass
-     the current shadow contents, because write_inferior_memory
+     the current shadow contents, because target_write_memory
      updates any shadow memory with what we pass here, and we want
      that to be a nop.  */
-  err = write_inferior_memory (where, buf, length);
+  err = target_write_memory (where, buf, length);
   if (err != 0)
     {
       if (debug_threads)
@@ -672,17 +721,17 @@ uninsert_fast_tracepoint_jumps_at (CORE_ADDR pc)
       jp->inserted = 0;
 
       /* Since there can be trap breakpoints inserted in the same
-        address range, we use use `write_inferior_memory', which
+        address range, we use use `target_write_memory', which
         takes care of layering breakpoints on top of fast
         tracepoints, and on top of the buffer we pass it.  This works
         because we've already marked the fast tracepoint fast
         tracepoint jump uninserted above.  Also note that we need to
         pass the current shadow contents, because
-        write_inferior_memory updates any shadow memory with what we
+        target_write_memory updates any shadow memory with what we
         pass here, and we want that to be a nop.  */
       buf = (unsigned char *) alloca (jp->length);
       memcpy (buf, fast_tracepoint_jump_shadow (jp), jp->length);
-      err = write_inferior_memory (jp->pc, buf, jp->length);
+      err = target_write_memory (jp->pc, buf, jp->length);
       if (err != 0)
        {
          jp->inserted = 1;
@@ -720,16 +769,16 @@ reinsert_fast_tracepoint_jumps_at (CORE_ADDR where)
   jp->inserted = 1;
 
   /* Since there can be trap breakpoints inserted in the same address
-     range, we use `write_inferior_memory', which takes care of
+     range, we use `target_write_memory', which takes care of
      layering breakpoints on top of fast tracepoints, and on top of
      the buffer we pass it.  This works because we've already marked
      the fast tracepoint jump inserted above.  Also note that we need
      to pass the current shadow contents, because
-     write_inferior_memory updates any shadow memory with what we pass
+     target_write_memory updates any shadow memory with what we pass
      here, and we want that to be a nop.  */
   buf = (unsigned char *) alloca (jp->length);
   memcpy (buf, fast_tracepoint_jump_shadow (jp), jp->length);
-  err = write_inferior_memory (where, buf, jp->length);
+  err = target_write_memory (where, buf, jp->length);
   if (err != 0)
     {
       jp->inserted = 0;
@@ -765,11 +814,32 @@ set_breakpoint (enum bkpt_type type, enum raw_bkpt_type raw_type,
       return NULL;
     }
 
-  bp = XCNEW (struct breakpoint);
-  bp->type = type;
+  if (is_gdb_breakpoint (type))
+    {
+      struct gdb_breakpoint *gdb_bp = XCNEW (struct gdb_breakpoint);
+
+      bp = (struct breakpoint *) gdb_bp;
+      gdb_assert (handler == NULL);
+    }
+  else if (type == other_breakpoint)
+    {
+      struct other_breakpoint *other_bp = XCNEW (struct other_breakpoint);
+
+      other_bp->handler = handler;
+      bp = (struct breakpoint *) other_bp;
+    }
+  else if (type == single_step_breakpoint)
+    {
+      struct single_step_breakpoint *ss_bp
+       = XCNEW (struct single_step_breakpoint);
+
+      bp = (struct breakpoint *) ss_bp;
+    }
+  else
+    gdb_assert_not_reached ("unhandled breakpoint type");
 
+  bp->type = type;
   bp->raw = raw;
-  bp->handler = handler;
 
   bp->next = proc->breakpoints;
   proc->breakpoints = bp;
@@ -777,20 +847,29 @@ set_breakpoint (enum bkpt_type type, enum raw_bkpt_type raw_type,
   return bp;
 }
 
-/* See mem-break.h  */
+/* Set breakpoint of TYPE on address WHERE with handler HANDLER.  */
 
-struct breakpoint *
-set_breakpoint_at (CORE_ADDR where, int (*handler) (CORE_ADDR))
+static struct breakpoint *
+set_breakpoint_type_at (enum bkpt_type type, CORE_ADDR where,
+                       int (*handler) (CORE_ADDR))
 {
   int err_ignored;
   CORE_ADDR placed_address = where;
   int breakpoint_kind = target_breakpoint_kind_from_pc (&placed_address);
 
-  return set_breakpoint (other_breakpoint, raw_bkpt_type_sw,
+  return set_breakpoint (type, raw_bkpt_type_sw,
                         placed_address, breakpoint_kind, handler,
                         &err_ignored);
 }
 
+/* See mem-break.h  */
+
+struct breakpoint *
+set_breakpoint_at (CORE_ADDR where, int (*handler) (CORE_ADDR))
+{
+  return set_breakpoint_type_at (other_breakpoint, where, handler);
+}
+
 
 static int
 delete_raw_breakpoint (struct process_info *proc, struct raw_breakpoint *todel)
@@ -907,7 +986,7 @@ delete_breakpoint (struct breakpoint *todel)
    address ADDR and return a pointer to its structure.  If KIND is -1,
    the breakpoint's kind is ignored.  */
 
-static struct breakpoint *
+static struct gdb_breakpoint *
 find_gdb_breakpoint (char z_type, CORE_ADDR addr, int kind)
 {
   struct process_info *proc = current_process ();
@@ -917,7 +996,7 @@ find_gdb_breakpoint (char z_type, CORE_ADDR addr, int kind)
   for (bp = proc->breakpoints; bp != NULL; bp = bp->next)
     if (bp->type == type && bp->raw->pc == addr
        && (kind == -1 || bp->raw->kind == kind))
-      return bp;
+      return (struct gdb_breakpoint *) bp;
 
   return NULL;
 }
@@ -935,10 +1014,10 @@ z_type_supported (char z_type)
    failure returns NULL and sets *ERR to either -1 for error, or 1 if
    Z_TYPE breakpoints are not supported on this target.  */
 
-static struct breakpoint *
+static struct gdb_breakpoint *
 set_gdb_breakpoint_1 (char z_type, CORE_ADDR addr, int kind, int *err)
 {
-  struct breakpoint *bp;
+  struct gdb_breakpoint *bp;
   enum bkpt_type type;
   enum raw_bkpt_type raw_type;
 
@@ -964,12 +1043,12 @@ set_gdb_breakpoint_1 (char z_type, CORE_ADDR addr, int kind, int *err)
 
       if (bp != NULL)
        {
-         if (bp->raw->kind != kind)
+         if (bp->base.raw->kind != kind)
            {
              /* A different kind than previously seen.  The previous
                 breakpoint must be gone then.  */
-             bp->raw->inserted = -1;
-             delete_breakpoint (bp);
+             bp->base.raw->inserted = -1;
+             delete_breakpoint ((struct breakpoint *) bp);
              bp = NULL;
            }
          else if (z_type == Z_PACKET_SW_BP)
@@ -1005,7 +1084,8 @@ set_gdb_breakpoint_1 (char z_type, CORE_ADDR addr, int kind, int *err)
 
   raw_type = Z_packet_to_raw_bkpt_type (z_type);
   type = Z_packet_to_bkpt_type (z_type);
-  return set_breakpoint (type, raw_type, addr, kind, NULL, err);
+  return (struct gdb_breakpoint *) set_breakpoint (type, raw_type, addr,
+                                                  kind, NULL, err);
 }
 
 static int
@@ -1023,22 +1103,17 @@ check_gdb_bp_preconditions (char z_type, int *err)
       *err = 1;
       return 0;
     }
-  else if (current_thread == NULL)
-    {
-      *err = -1;
-      return 0;
-    }
-  else
-    return 1;
+
+  return 1;
 }
 
 /* See mem-break.h.  This is a wrapper for set_gdb_breakpoint_1 that
    knows to prepare to access memory for Z0 breakpoints.  */
 
-struct breakpoint *
+struct gdb_breakpoint *
 set_gdb_breakpoint (char z_type, CORE_ADDR addr, int kind, int *err)
 {
-  struct breakpoint *bp;
+  struct gdb_breakpoint *bp;
 
   if (!check_gdb_bp_preconditions (z_type, err))
     return NULL;
@@ -1047,9 +1122,11 @@ set_gdb_breakpoint (char z_type, CORE_ADDR addr, int kind, int *err)
      access memory.  */
   if (z_type == Z_PACKET_SW_BP)
     {
-      *err = prepare_to_access_memory ();
-      if (*err != 0)
-       return NULL;
+      if (prepare_to_access_memory () != 0)
+       {
+         *err = -1;
+         return NULL;
+       }
     }
 
   bp = set_gdb_breakpoint_1 (z_type, addr, kind, err);
@@ -1068,7 +1145,7 @@ set_gdb_breakpoint (char z_type, CORE_ADDR addr, int kind, int *err)
 static int
 delete_gdb_breakpoint_1 (char z_type, CORE_ADDR addr, int kind)
 {
-  struct breakpoint *bp;
+  struct gdb_breakpoint *bp;
   int err;
 
   bp = find_gdb_breakpoint (z_type, addr, kind);
@@ -1078,7 +1155,7 @@ delete_gdb_breakpoint_1 (char z_type, CORE_ADDR addr, int kind)
   /* Before deleting the breakpoint, make sure to free its condition
      and command lists.  */
   clear_breakpoint_conditions_and_commands (bp);
-  err = delete_breakpoint (bp);
+  err = delete_breakpoint ((struct breakpoint *) bp);
   if (err != 0)
     return -1;
 
@@ -1118,7 +1195,7 @@ delete_gdb_breakpoint (char z_type, CORE_ADDR addr, int kind)
 /* Clear all conditions associated with a breakpoint.  */
 
 static void
-clear_breakpoint_conditions (struct breakpoint *bp)
+clear_breakpoint_conditions (struct gdb_breakpoint *bp)
 {
   struct point_cond_list *cond;
 
@@ -1143,7 +1220,7 @@ clear_breakpoint_conditions (struct breakpoint *bp)
 /* Clear all commands associated with a breakpoint.  */
 
 static void
-clear_breakpoint_commands (struct breakpoint *bp)
+clear_breakpoint_commands (struct gdb_breakpoint *bp)
 {
   struct point_command_list *cmd;
 
@@ -1166,7 +1243,7 @@ clear_breakpoint_commands (struct breakpoint *bp)
 }
 
 void
-clear_breakpoint_conditions_and_commands (struct breakpoint *bp)
+clear_breakpoint_conditions_and_commands (struct gdb_breakpoint *bp)
 {
   clear_breakpoint_conditions (bp);
   clear_breakpoint_commands (bp);
@@ -1175,7 +1252,7 @@ clear_breakpoint_conditions_and_commands (struct breakpoint *bp)
 /* Add condition CONDITION to GDBserver's breakpoint BP.  */
 
 static void
-add_condition_to_breakpoint (struct breakpoint *bp,
+add_condition_to_breakpoint (struct gdb_breakpoint *bp,
                             struct agent_expr *condition)
 {
   struct point_cond_list *new_cond;
@@ -1192,9 +1269,9 @@ add_condition_to_breakpoint (struct breakpoint *bp,
 /* Add a target-side condition CONDITION to a breakpoint.  */
 
 int
-add_breakpoint_condition (struct breakpoint *bp, char **condition)
+add_breakpoint_condition (struct gdb_breakpoint *bp, const char **condition)
 {
-  char *actparm = *condition;
+  const char *actparm = *condition;
   struct agent_expr *cond;
 
   if (condition == NULL)
@@ -1207,8 +1284,7 @@ add_breakpoint_condition (struct breakpoint *bp, char **condition)
 
   if (cond == NULL)
     {
-      fprintf (stderr, "Condition evaluation failed. "
-              "Assuming unconditional.\n");
+      warning ("Condition evaluation failed. Assuming unconditional.");
       return 0;
     }
 
@@ -1226,7 +1302,7 @@ static int
 gdb_condition_true_at_breakpoint_z_type (char z_type, CORE_ADDR addr)
 {
   /* Fetch registers for the current inferior.  */
-  struct breakpoint *bp = find_gdb_breakpoint (z_type, addr, -1);
+  struct gdb_breakpoint *bp = find_gdb_breakpoint (z_type, addr, -1);
   ULONGEST value = 0;
   struct point_cond_list *cl;
   int err = 0;
@@ -1272,8 +1348,8 @@ gdb_condition_true_at_breakpoint (CORE_ADDR where)
 
 /* Add commands COMMANDS to GDBserver's breakpoint BP.  */
 
-void
-add_commands_to_breakpoint (struct breakpoint *bp,
+static void
+add_commands_to_breakpoint (struct gdb_breakpoint *bp,
                            struct agent_expr *commands, int persist)
 {
   struct point_command_list *new_cmd;
@@ -1291,10 +1367,10 @@ add_commands_to_breakpoint (struct breakpoint *bp,
 /* Add a target-side command COMMAND to the breakpoint at ADDR.  */
 
 int
-add_breakpoint_commands (struct breakpoint *bp, char **command,
+add_breakpoint_commands (struct gdb_breakpoint *bp, const char **command,
                         int persist)
 {
-  char *actparm = *command;
+  const char *actparm = *command;
   struct agent_expr *cmd;
 
   if (command == NULL)
@@ -1307,8 +1383,7 @@ add_breakpoint_commands (struct breakpoint *bp, char **command,
 
   if (cmd == NULL)
     {
-      fprintf (stderr, "Command evaluation failed. "
-              "Disabling.\n");
+      warning ("Command evaluation failed. Disabling.");
       return 0;
     }
 
@@ -1325,7 +1400,7 @@ add_breakpoint_commands (struct breakpoint *bp, char **command,
 static int
 gdb_no_commands_at_breakpoint_z_type (char z_type, CORE_ADDR addr)
 {
-  struct breakpoint *bp = find_gdb_breakpoint (z_type, addr, -1);
+  struct gdb_breakpoint *bp = find_gdb_breakpoint (z_type, addr, -1);
 
   if (bp == NULL)
     return 1;
@@ -1355,7 +1430,7 @@ static int
 run_breakpoint_commands_z_type (char z_type, CORE_ADDR addr)
 {
   /* Fetch registers for the current inferior.  */
-  struct breakpoint *bp = find_gdb_breakpoint (z_type, addr, -1);
+  struct gdb_breakpoint *bp = find_gdb_breakpoint (z_type, addr, -1);
   ULONGEST value = 0;
   struct point_command_list *cl;
   int err = 0;
@@ -1402,18 +1477,21 @@ gdb_breakpoint_here (CORE_ADDR where)
 }
 
 void
-set_reinsert_breakpoint (CORE_ADDR stop_at)
+set_single_step_breakpoint (CORE_ADDR stop_at, ptid_t ptid)
 {
-  struct breakpoint *bp;
+  struct single_step_breakpoint *bp;
 
-  bp = set_breakpoint_at (stop_at, NULL);
-  bp->type = reinsert_breakpoint;
+  gdb_assert (current_ptid.pid () == ptid.pid ());
+
+  bp = (struct single_step_breakpoint *) set_breakpoint_type_at (single_step_breakpoint,
+                                                               stop_at, NULL);
+  bp->ptid = ptid;
 }
 
 void
-delete_reinsert_breakpoints (void)
+delete_single_step_breakpoints (struct thread_info *thread)
 {
-  struct process_info *proc = current_process ();
+  struct process_info *proc = get_thread_process (thread);
   struct breakpoint *bp, **bp_link;
 
   bp = proc->breakpoints;
@@ -1421,11 +1499,16 @@ delete_reinsert_breakpoints (void)
 
   while (bp)
     {
-      if (bp->type == reinsert_breakpoint)
+      if (bp->type == single_step_breakpoint
+         && ((struct single_step_breakpoint *) bp)->ptid == ptid_of (thread))
        {
+         struct thread_info *saved_thread = current_thread;
+
+         current_thread = thread;
          *bp_link = bp->next;
          release_breakpoint (proc, bp);
          bp = *bp_link;
+         current_thread = saved_thread;
        }
       else
        {
@@ -1504,13 +1587,40 @@ uninsert_all_breakpoints (void)
       uninsert_raw_breakpoint (bp);
 }
 
+void
+uninsert_single_step_breakpoints (struct thread_info *thread)
+{
+  struct process_info *proc = get_thread_process (thread);
+  struct breakpoint *bp;
+
+  for (bp = proc->breakpoints; bp != NULL; bp = bp->next)
+    {
+    if (bp->type == single_step_breakpoint
+       && ((struct single_step_breakpoint *) bp)->ptid == ptid_of (thread))
+      {
+       gdb_assert (bp->raw->inserted > 0);
+
+       /* Only uninsert the raw breakpoint if it only belongs to a
+          reinsert breakpoint.  */
+       if (bp->raw->refcount == 1)
+         {
+           struct thread_info *saved_thread = current_thread;
+
+           current_thread = thread;
+           uninsert_raw_breakpoint (bp->raw);
+           current_thread = saved_thread;
+         }
+      }
+    }
+}
+
 static void
 reinsert_raw_breakpoint (struct raw_breakpoint *bp)
 {
   int err;
 
   if (bp->inserted)
-    error ("Breakpoint already inserted at reinsert time.");
+    return;
 
   err = the_target->insert_point (bp->raw_type, bp->pc, bp->kind, bp);
   if (err == 0)
@@ -1548,6 +1658,30 @@ reinsert_breakpoints_at (CORE_ADDR pc)
     }
 }
 
+int
+has_single_step_breakpoints (struct thread_info *thread)
+{
+  struct process_info *proc = get_thread_process (thread);
+  struct breakpoint *bp, **bp_link;
+
+  bp = proc->breakpoints;
+  bp_link = &proc->breakpoints;
+
+  while (bp)
+    {
+      if (bp->type == single_step_breakpoint
+         && ((struct single_step_breakpoint *) bp)->ptid == ptid_of (thread))
+       return 1;
+      else
+       {
+         bp_link = &bp->next;
+         bp = *bp_link;
+       }
+    }
+
+  return 0;
+}
+
 void
 reinsert_all_breakpoints (void)
 {
@@ -1561,6 +1695,31 @@ reinsert_all_breakpoints (void)
       reinsert_raw_breakpoint (bp);
 }
 
+void
+reinsert_single_step_breakpoints (struct thread_info *thread)
+{
+  struct process_info *proc = get_thread_process (thread);
+  struct breakpoint *bp;
+
+  for (bp = proc->breakpoints; bp != NULL; bp = bp->next)
+    {
+      if (bp->type == single_step_breakpoint
+         && ((struct single_step_breakpoint *) bp)->ptid == ptid_of (thread))
+       {
+         gdb_assert (bp->raw->inserted > 0);
+
+         if (bp->raw->refcount == 1)
+           {
+             struct thread_info *saved_thread = current_thread;
+
+             current_thread = thread;
+             reinsert_raw_breakpoint (bp->raw);
+             current_thread = saved_thread;
+           }
+       }
+    }
+}
+
 void
 check_breakpoints (CORE_ADDR stop_pc)
 {
@@ -1584,14 +1743,20 @@ check_breakpoints (CORE_ADDR stop_pc)
              return;
            }
 
-         if (bp->handler != NULL && (*bp->handler) (stop_pc))
+         if (bp->type == other_breakpoint)
            {
-             *bp_link = bp->next;
+             struct other_breakpoint *other_bp
+               = (struct other_breakpoint *) bp;
 
-             release_breakpoint (proc, bp);
+             if (other_bp->handler != NULL && (*other_bp->handler) (stop_pc))
+               {
+                 *bp_link = bp->next;
+
+                 release_breakpoint (proc, bp);
 
-             bp = *bp_link;
-             continue;
+                 bp = *bp_link;
+                 continue;
+               }
            }
        }
 
@@ -1665,6 +1830,23 @@ hardware_breakpoint_inserted_here (CORE_ADDR addr)
   return 0;
 }
 
+/* See mem-break.h.  */
+
+int
+single_step_breakpoint_inserted_here (CORE_ADDR addr)
+{
+  struct process_info *proc = current_process ();
+  struct breakpoint *bp;
+
+  for (bp = proc->breakpoints; bp != NULL; bp = bp->next)
+    if (bp->type == single_step_breakpoint
+       && bp->raw->pc == addr
+       && bp->raw->inserted)
+      return 1;
+
+  return 0;
+}
+
 static int
 validate_inserted_breakpoint (struct raw_breakpoint *bp)
 {
@@ -1696,7 +1878,12 @@ delete_disabled_breakpoints (void)
     {
       next = bp->next;
       if (bp->raw->inserted < 0)
-       delete_breakpoint_1 (proc, bp);
+       {
+         /* If single_step_breakpoints become disabled, that means the
+            manipulations (insertion and removal) of them are wrong.  */
+         gdb_assert (bp->type != single_step_breakpoint);
+         delete_breakpoint_1 (proc, bp);
+       }
     }
 }
 
@@ -1952,16 +2139,10 @@ clone_agent_expr (const struct agent_expr *src_ax)
 /* Deep-copy the contents of one breakpoint to another.  */
 
 static struct breakpoint *
-clone_one_breakpoint (const struct breakpoint *src)
+clone_one_breakpoint (const struct breakpoint *src, ptid_t ptid)
 {
   struct breakpoint *dest;
   struct raw_breakpoint *dest_raw;
-  struct point_cond_list *current_cond;
-  struct point_cond_list *new_cond;
-  struct point_cond_list *cond_tail = NULL;
-  struct point_command_list *current_cmd;
-  struct point_command_list *new_cmd;
-  struct point_command_list *cmd_tail = NULL;
 
   /* Clone the raw breakpoint.  */
   dest_raw = XCNEW (struct raw_breakpoint);
@@ -1973,50 +2154,83 @@ clone_one_breakpoint (const struct breakpoint *src)
   dest_raw->inserted = src->raw->inserted;
 
   /* Clone the high-level breakpoint.  */
-  dest = XCNEW (struct breakpoint);
-  dest->type = src->type;
-  dest->raw = dest_raw;
-  dest->handler = src->handler;
-
-  /* Clone the condition list.  */
-  for (current_cond = src->cond_list; current_cond != NULL;
-       current_cond = current_cond->next)
+  if (is_gdb_breakpoint (src->type))
     {
-      new_cond = XCNEW (struct point_cond_list);
-      new_cond->cond = clone_agent_expr (current_cond->cond);
-      APPEND_TO_LIST (&dest->cond_list, new_cond, cond_tail);
+      struct gdb_breakpoint *gdb_dest = XCNEW (struct gdb_breakpoint);
+      struct point_cond_list *current_cond;
+      struct point_cond_list *new_cond;
+      struct point_cond_list *cond_tail = NULL;
+      struct point_command_list *current_cmd;
+      struct point_command_list *new_cmd;
+      struct point_command_list *cmd_tail = NULL;
+
+      /* Clone the condition list.  */
+      for (current_cond = ((struct gdb_breakpoint *) src)->cond_list;
+          current_cond != NULL;
+          current_cond = current_cond->next)
+       {
+         new_cond = XCNEW (struct point_cond_list);
+         new_cond->cond = clone_agent_expr (current_cond->cond);
+         APPEND_TO_LIST (&gdb_dest->cond_list, new_cond, cond_tail);
+       }
+
+      /* Clone the command list.  */
+      for (current_cmd = ((struct gdb_breakpoint *) src)->command_list;
+          current_cmd != NULL;
+          current_cmd = current_cmd->next)
+       {
+         new_cmd = XCNEW (struct point_command_list);
+         new_cmd->cmd = clone_agent_expr (current_cmd->cmd);
+         new_cmd->persistence = current_cmd->persistence;
+         APPEND_TO_LIST (&gdb_dest->command_list, new_cmd, cmd_tail);
+       }
+
+      dest = (struct breakpoint *) gdb_dest;
     }
+  else if (src->type == other_breakpoint)
+    {
+      struct other_breakpoint *other_dest = XCNEW (struct other_breakpoint);
 
-  /* Clone the command list.  */
-  for (current_cmd = src->command_list; current_cmd != NULL;
-       current_cmd = current_cmd->next)
+      other_dest->handler = ((struct other_breakpoint *) src)->handler;
+      dest = (struct breakpoint *) other_dest;
+    }
+  else if (src->type == single_step_breakpoint)
     {
-      new_cmd = XCNEW (struct point_command_list);
-      new_cmd->cmd = clone_agent_expr (current_cmd->cmd);
-      new_cmd->persistence = current_cmd->persistence;
-      APPEND_TO_LIST (&dest->command_list, new_cmd, cmd_tail);
+      struct single_step_breakpoint *ss_dest
+       = XCNEW (struct single_step_breakpoint);
+
+      dest = (struct breakpoint *) ss_dest;
+      /* Since single-step breakpoint is thread specific, don't copy
+        thread id from SRC, use ID instead.  */
+      ss_dest->ptid = ptid;
     }
+  else
+    gdb_assert_not_reached ("unhandled breakpoint type");
+
+  dest->type = src->type;
+  dest->raw = dest_raw;
 
   return dest;
 }
 
-/* Create a new breakpoint list NEW_LIST that is a copy of the
-   list starting at SRC_LIST.  Create the corresponding new
-   raw_breakpoint list NEW_RAW_LIST as well.  */
+/* See mem-break.h.  */
 
 void
-clone_all_breakpoints (struct breakpoint **new_list,
-                      struct raw_breakpoint **new_raw_list,
-                      const struct breakpoint *src_list)
+clone_all_breakpoints (struct thread_info *child_thread,
+                      const struct thread_info *parent_thread)
 {
   const struct breakpoint *bp;
   struct breakpoint *new_bkpt;
   struct breakpoint *bkpt_tail = NULL;
   struct raw_breakpoint *raw_bkpt_tail = NULL;
+  struct process_info *child_proc = get_thread_process (child_thread);
+  struct process_info *parent_proc = get_thread_process (parent_thread);
+  struct breakpoint **new_list = &child_proc->breakpoints;
+  struct raw_breakpoint **new_raw_list = &child_proc->raw_breakpoints;
 
-  for (bp = src_list; bp != NULL; bp = bp->next)
+  for (bp = parent_proc->breakpoints; bp != NULL; bp = bp->next)
     {
-      new_bkpt = clone_one_breakpoint (bp);
+      new_bkpt = clone_one_breakpoint (bp, ptid_of (child_thread));
       APPEND_TO_LIST (new_list, new_bkpt, bkpt_tail);
       APPEND_TO_LIST (new_raw_list, new_bkpt->raw, raw_bkpt_tail);
     }