* rs6000-tdep.c (rs6000_fetch_instruction)
[deliverable/binutils-gdb.git] / gdb / gdbserver / regcache.c
index 701d09232f856b527abe5a6972b690b31f46b075..a324d43df65ccdb6c2d38347bc7f45b564390679 100644 (file)
@@ -1,12 +1,12 @@
 /* Register support routines for the remote server for GDB.
-   Copyright 2001, 2002
+   Copyright (C) 2001, 2002, 2004, 2005, 2007, 2008
    Free Software Foundation, Inc.
 
    This file is part of GDB.
 
    This program is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
-   the Free Software Foundation; either version 2 of the License, or
+   the Free Software Foundation; either version 3 of the License, or
    (at your option) any later version.
 
    This program is distributed in the hope that it will be useful,
@@ -15,9 +15,7 @@
    GNU General Public License for more details.
 
    You should have received a copy of the GNU General Public License
-   along with this program; if not, write to the Free Software
-   Foundation, Inc., 59 Temple Place - Suite 330,
-   Boston, MA 02111-1307, USA.  */
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
 
 #include "server.h"
 #include "regdef.h"
 #include <stdlib.h>
 #include <string.h>
 
+/* The private data for the register cache.  Note that we have one
+   per inferior; this is primarily for simplicity, as the performance
+   benefit is minimal.  */
+
 struct inferior_regcache_data
 {
-  char *registers;
+  int registers_valid;
+  unsigned char *registers;
 };
 
 static int register_bytes;
@@ -38,7 +41,7 @@ static int num_registers;
 const char **gdbserver_expedite_regs;
 
 static struct inferior_regcache_data *
-get_regcache (struct inferior_info *inf)
+get_regcache (struct thread_info *inf, int fetch)
 {
   struct inferior_regcache_data *regcache;
 
@@ -47,35 +50,78 @@ get_regcache (struct inferior_info *inf)
   if (regcache == NULL)
     fatal ("no register cache");
 
+  /* FIXME - fetch registers for INF */
+  if (fetch && regcache->registers_valid == 0)
+    {
+      fetch_inferior_registers (0);
+      regcache->registers_valid = 1;
+    }
+
   return regcache;
 }
 
-int
-registers_length (void)
+void
+regcache_invalidate_one (struct inferior_list_entry *entry)
 {
-  return 2 * register_bytes;
+  struct thread_info *thread = (struct thread_info *) entry;
+  struct inferior_regcache_data *regcache;
+
+  regcache = (struct inferior_regcache_data *) inferior_regcache_data (thread);
+
+  if (regcache->registers_valid)
+    {
+      struct thread_info *saved_inferior = current_inferior;
+
+      current_inferior = thread;
+      store_inferior_registers (-1);
+      current_inferior = saved_inferior;
+    }
+
+  regcache->registers_valid = 0;
 }
 
 void
-create_register_cache (struct inferior_info *inferior)
+regcache_invalidate ()
+{
+  for_each_inferior (&all_threads, regcache_invalidate_one);
+}
+
+void *
+new_register_cache (void)
 {
   struct inferior_regcache_data *regcache;
 
   regcache = malloc (sizeof (*regcache));
 
-  regcache->registers = malloc (register_bytes);
+  /* Make sure to zero-initialize the register cache when it is created,
+     in case there are registers the target never fetches.  This way they'll
+     read as zero instead of garbage.  */
+  regcache->registers = calloc (1, register_bytes);
   if (regcache->registers == NULL)
     fatal ("Could not allocate register cache.");
 
-  set_inferior_regcache_data (inferior, regcache);
+  regcache->registers_valid = 0;
+
+  return regcache;
 }
 
 void
-free_register_cache (struct inferior_info *inferior)
+free_register_cache (void *regcache_p)
+{
+  struct inferior_regcache_data *regcache
+    = (struct inferior_regcache_data *) regcache_p;
+
+  free (regcache->registers);
+  free (regcache);
+}
+
+static void
+realloc_register_cache (struct inferior_list_entry *thread_p)
 {
-  free (get_regcache (current_inferior)->registers);
-  free (get_regcache (current_inferior));
-  set_inferior_regcache_data (inferior, NULL);
+  struct thread_info *thread = (struct thread_info *) thread_p;
+
+  free_register_cache (inferior_regcache_data (thread));
+  set_inferior_regcache_data (thread, new_register_cache ());
 }
 
 void
@@ -94,12 +140,19 @@ set_register_cache (struct reg *regs, int n)
     }
 
   register_bytes = offset / 8;
+
+  /* Make sure PBUFSIZ is large enough to hold a full register packet.  */
+  if (2 * register_bytes + 32 > PBUFSIZ)
+    fatal ("Register packet size exceeds PBUFSIZ.");
+
+  /* Re-allocate all pre-existing register caches.  */
+  for_each_inferior (&all_threads, realloc_register_cache);
 }
 
 void
 registers_to_string (char *buf)
 {
-  char *registers = get_regcache (current_inferior)->registers;
+  unsigned char *registers = get_regcache (current_inferior, 1)->registers;
 
   convert_int_to_ascii (registers, buf, register_bytes);
 }
@@ -108,7 +161,7 @@ void
 registers_from_string (char *buf)
 {
   int len = strlen (buf);
-  char *registers = get_regcache (current_inferior)->registers;
+  unsigned char *registers = get_regcache (current_inferior, 1)->registers;
 
   if (len != register_bytes * 2)
     {
@@ -155,10 +208,11 @@ register_size (int n)
   return reg_defs[n].size / 8;
 }
 
-char *
-register_data (int n)
+static unsigned char *
+register_data (int n, int fetch)
 {
-  char *registers = get_regcache (current_inferior)->registers;
+  unsigned char *registers
+    = get_regcache (current_inferior, fetch)->registers;
 
   return registers + (reg_defs[n].offset / 8);
 }
@@ -166,7 +220,7 @@ register_data (int n)
 void
 supply_register (int n, const void *buf)
 {
-  memcpy (register_data (n), buf, register_size (n));
+  memcpy (register_data (n, 0), buf, register_size (n));
 }
 
 void
@@ -178,7 +232,13 @@ supply_register_by_name (const char *name, const void *buf)
 void
 collect_register (int n, void *buf)
 {
-  memcpy (buf, register_data (n), register_size (n));
+  memcpy (buf, register_data (n, 1), register_size (n));
+}
+
+void
+collect_register_as_string (int n, char *buf)
+{
+  convert_int_to_ascii (register_data (n, 1), buf, register_size (n));
 }
 
 void
This page took 0.027924 seconds and 4 git commands to generate.