Mention PR gdb/17096 in ChangeLog
[deliverable/binutils-gdb.git] / gdb / regcache.c
index 7ec75c80944b49ba2748f32327f8c68e89cf8dea..5ee90b0805511767f847c3639d1ad78b9d4af7e0 100644 (file)
@@ -1,6 +1,6 @@
 /* Cache and manage the values of registers for GDB, the GNU debugger.
 
-   Copyright (C) 1986-2013 Free Software Foundation, Inc.
+   Copyright (C) 1986-2014 Free Software Foundation, Inc.
 
    This file is part of GDB.
 
@@ -25,8 +25,7 @@
 #include "regcache.h"
 #include "reggroups.h"
 #include "gdb_assert.h"
-#include "gdb_string.h"
-#include "gdbcmd.h"            /* For maintenanceprintlist.  */
+#include <string.h>
 #include "observer.h"
 #include "exceptions.h"
 #include "remote.h"
@@ -218,22 +217,22 @@ regcache_xmalloc_1 (struct gdbarch *gdbarch, struct address_space *aspace,
 
   gdb_assert (gdbarch != NULL);
   descr = regcache_descr (gdbarch);
-  regcache = XMALLOC (struct regcache);
+  regcache = XNEW (struct regcache);
   regcache->descr = descr;
   regcache->readonly_p = readonly_p;
   if (readonly_p)
     {
       regcache->registers
-       = XCALLOC (descr->sizeof_cooked_registers, gdb_byte);
+       = XCNEWVEC (gdb_byte, descr->sizeof_cooked_registers);
       regcache->register_status
-       = XCALLOC (descr->sizeof_cooked_register_status, signed char);
+       = XCNEWVEC (signed char, descr->sizeof_cooked_register_status);
     }
   else
     {
       regcache->registers
-       = XCALLOC (descr->sizeof_raw_registers, gdb_byte);
+       = XCNEWVEC (gdb_byte, descr->sizeof_raw_registers);
       regcache->register_status
-       = XCALLOC (descr->sizeof_raw_register_status, signed char);
+       = XCNEWVEC (signed char, descr->sizeof_raw_register_status);
     }
   regcache->aspace = aspace;
   regcache->ptid = minus_one_ptid;
@@ -268,6 +267,32 @@ make_cleanup_regcache_xfree (struct regcache *regcache)
   return make_cleanup (do_regcache_xfree, regcache);
 }
 
+/* Cleanup routines for invalidating a register.  */
+
+struct register_to_invalidate
+{
+  struct regcache *regcache;
+  int regnum;
+};
+
+static void
+do_regcache_invalidate (void *data)
+{
+  struct register_to_invalidate *reg = data;
+
+  regcache_invalidate (reg->regcache, reg->regnum);
+}
+
+static struct cleanup *
+make_cleanup_regcache_invalidate (struct regcache *regcache, int regnum)
+{
+  struct register_to_invalidate* reg = XNEW (struct register_to_invalidate);
+
+  reg->regcache = regcache;
+  reg->regnum = regnum;
+  return make_cleanup_dtor (do_regcache_invalidate, (void *) reg, xfree);
+}
+
 /* Return REGCACHE's architecture.  */
 
 struct gdbarch *
@@ -847,7 +872,8 @@ void
 regcache_raw_write (struct regcache *regcache, int regnum,
                    const gdb_byte *buf)
 {
-  struct cleanup *old_chain;
+  struct cleanup *chain_before_save_inferior;
+  struct cleanup *chain_before_invalidate_register;
 
   gdb_assert (regcache != NULL && buf != NULL);
   gdb_assert (regnum >= 0 && regnum < regcache->descr->nr_raw_registers);
@@ -865,16 +891,26 @@ regcache_raw_write (struct regcache *regcache, int regnum,
                  regcache->descr->sizeof_register[regnum]) == 0))
     return;
 
-  old_chain = save_inferior_ptid ();
+  chain_before_save_inferior = save_inferior_ptid ();
   inferior_ptid = regcache->ptid;
 
   target_prepare_to_store (regcache);
   memcpy (register_buffer (regcache, regnum), buf,
          regcache->descr->sizeof_register[regnum]);
   regcache->register_status[regnum] = REG_VALID;
+
+  /* Register a cleanup function for invalidating the register after it is
+     written, in case of a failure.  */
+  chain_before_invalidate_register
+    = make_cleanup_regcache_invalidate (regcache, regnum);
+
   target_store_registers (regcache, regnum);
 
-  do_cleanups (old_chain);
+  /* The target did not throw an error so we can discard invalidating the
+     register and restore the cleanup chain to what it was.  */
+  discard_cleanups (chain_before_invalidate_register);
+
+  do_cleanups (chain_before_save_inferior);
 }
 
 void
This page took 0.024576 seconds and 4 git commands to generate.