/* Cache and manage the values of registers for GDB, the GNU debugger.
- Copyright (C) 1986, 1987, 1989, 1991, 1994, 1995, 1996, 1998, 2000, 2001,
- 2002, 2004, 2007, 2008, 2009, 2010, 2011 Free Software Foundation, Inc.
+ Copyright (C) 1986-1987, 1989, 1991, 1994-1996, 1998, 2000-2002,
+ 2004, 2007-2012 Free Software Foundation, Inc.
This file is part of GDB.
#include "gdbcmd.h" /* For maintenanceprintlist. */
#include "observer.h"
#include "exceptions.h"
+#include "remote.h"
/*
* DATA STRUCTURE
long sizeof_cooked_registers;
long sizeof_cooked_register_status;
- /* Offset and size (in 8 bit bytes), of reach register in the
+ /* Offset and size (in 8 bit bytes), of each register in the
register cache. All registers (including those in the range
[NR_RAW_REGISTERS .. NR_COOKED_REGISTERS) are given an
offset. */
}
}
-void
+static void
regcache_restore (struct regcache *dst,
regcache_cooked_read_ftype *cooked_read,
void *cooked_read_context)
{
if (gdbarch_register_reggroup_p (gdbarch, regnum, restore_reggroup))
{
- int valid = cooked_read (cooked_read_context, regnum, buf);
+ enum register_status status;
- if (valid)
+ status = cooked_read (cooked_read_context, regnum, buf);
+ if (status == REG_VALID)
regcache_cooked_write (dst, regnum, buf);
}
}
return newbuf;
}
-int
+enum register_status
regcache_register_status (const struct regcache *regcache, int regnum)
{
gdb_assert (regcache != NULL);
static struct regcache_list *current_regcache;
struct regcache *
-get_thread_arch_regcache (ptid_t ptid, struct gdbarch *gdbarch)
+get_thread_arch_aspace_regcache (ptid_t ptid, struct gdbarch *gdbarch,
+ struct address_space *aspace)
{
struct regcache_list *list;
struct regcache *new_regcache;
&& get_regcache_arch (list->regcache) == gdbarch)
return list->regcache;
- new_regcache = regcache_xmalloc_1 (gdbarch,
- target_thread_address_space (ptid), 0);
+ new_regcache = regcache_xmalloc_1 (gdbarch, aspace, 0);
new_regcache->ptid = ptid;
- gdb_assert (new_regcache->aspace != NULL);
list = xmalloc (sizeof (struct regcache_list));
list->regcache = new_regcache;
return new_regcache;
}
+struct regcache *
+get_thread_arch_regcache (ptid_t ptid, struct gdbarch *gdbarch)
+{
+ struct address_space *aspace;
+
+ /* For the benefit of "maint print registers" & co when debugging an
+ executable, allow dumping the regcache even when there is no
+ thread selected (target_thread_address_space internal-errors if
+ no address space is found). Note that normal user commands will
+ fail higher up on the call stack due to no
+ target_has_registers. */
+ aspace = (ptid_equal (null_ptid, ptid)
+ ? NULL
+ : target_thread_address_space (ptid));
+
+ return get_thread_arch_aspace_regcache (ptid, gdbarch, aspace);
+}
+
static ptid_t current_thread_ptid;
static struct gdbarch *current_thread_arch;
registers_changed_ptid (ptid_t ptid)
{
struct regcache_list *list, **list_link;
- int wildcard = ptid_equal (ptid, minus_one_ptid);
list = current_regcache;
list_link = ¤t_regcache;
list = *list_link;
}
- if (wildcard || ptid_equal (ptid, current_thread_ptid))
+ if (ptid_match (current_thread_ptid, ptid))
{
current_thread_ptid = null_ptid;
current_thread_arch = NULL;
}
- if (wildcard || ptid_equal (ptid, inferior_ptid))
+ if (ptid_match (inferior_ptid, ptid))
{
/* We just deleted the regcache of the current thread. Need to
forget about any frames we have cached, too. */
return regcache->register_status[regnum];
}
+ else if (gdbarch_pseudo_register_read_value_p (regcache->descr->gdbarch))
+ {
+ struct value *mark, *computed;
+ enum register_status result = REG_VALID;
+
+ mark = value_mark ();
+
+ computed = gdbarch_pseudo_register_read_value (regcache->descr->gdbarch,
+ regcache, regnum);
+ if (value_entirely_available (computed))
+ memcpy (buf, value_contents_raw (computed),
+ regcache->descr->sizeof_register[regnum]);
+ else
+ {
+ memset (buf, 0, regcache->descr->sizeof_register[regnum]);
+ result = REG_UNAVAILABLE;
+ }
+
+ value_free_to_mark (mark);
+
+ return result;
+ }
else
return gdbarch_pseudo_register_read (regcache->descr->gdbarch, regcache,
regnum, buf);
}
+struct value *
+regcache_cooked_read_value (struct regcache *regcache, int regnum)
+{
+ gdb_assert (regnum >= 0);
+ gdb_assert (regnum < regcache->descr->nr_cooked_registers);
+
+ if (regnum < regcache->descr->nr_raw_registers
+ || (regcache->readonly_p
+ && regcache->register_status[regnum] != REG_UNKNOWN)
+ || !gdbarch_pseudo_register_read_value_p (regcache->descr->gdbarch))
+ {
+ struct value *result;
+
+ result = allocate_value (register_type (regcache->descr->gdbarch,
+ regnum));
+ VALUE_LVAL (result) = lval_register;
+ VALUE_REGNUM (result) = regnum;
+
+ /* It is more efficient in general to do this delegation in this
+ direction than in the other one, even though the value-based
+ API is preferred. */
+ if (regcache_cooked_read (regcache, regnum,
+ value_contents_raw (result)) == REG_UNAVAILABLE)
+ mark_value_bytes_unavailable (result, 0,
+ TYPE_LENGTH (value_type (result)));
+
+ return result;
+ }
+ else
+ return gdbarch_pseudo_register_read_value (regcache->descr->gdbarch,
+ regcache, regnum);
+}
+
enum register_status
regcache_cooked_read_signed (struct regcache *regcache, int regnum,
LONGEST *val)
enum regcache_dump_what
{
regcache_dump_none, regcache_dump_raw,
- regcache_dump_cooked, regcache_dump_groups
+ regcache_dump_cooked, regcache_dump_groups,
+ regcache_dump_remote
};
static void
}
}
+ /* Remote packet configuration. */
+ if (what_to_dump == regcache_dump_remote)
+ {
+ if (regnum < 0)
+ {
+ fprintf_unfiltered (file, "Rmt Nr g/G Offset");
+ }
+ else if (regnum < regcache->descr->nr_raw_registers)
+ {
+ int pnum, poffset;
+
+ if (remote_register_number_and_offset (get_regcache_arch (regcache), regnum,
+ &pnum, &poffset))
+ fprintf_unfiltered (file, "%7d %11d", pnum, poffset);
+ }
+ }
+
fprintf_unfiltered (file, "\n");
}
regcache_print (args, regcache_dump_groups);
}
+static void
+maintenance_print_remote_registers (char *args, int from_tty)
+{
+ regcache_print (args, regcache_dump_remote);
+}
+
extern initialize_file_ftype _initialize_regcache; /* -Wmissing-prototype */
void
"including each register's group.\n"
"Takes an optional file parameter."),
&maintenanceprintlist);
+ add_cmd ("remote-registers", class_maintenance,
+ maintenance_print_remote_registers, _("\
+Print the internal register configuration including each register's\n\
+remote register number and buffer offset in the g/G packets.\n\
+Takes an optional file parameter."),
+ &maintenanceprintlist);
}