aboutsummaryrefslogtreecommitdiff
path: root/gdb/gdbserver
diff options
context:
space:
mode:
authorPedro Alves <palves@redhat.com>2011-01-28 13:36:32 +0000
committerPedro Alves <palves@redhat.com>2011-01-28 13:36:32 +0000
commit1c79eb8a7d7126b5fcb734fb374be42a717d4373 (patch)
treeb755b132d513e73c122099d1f4ec958ad44f701c /gdb/gdbserver
parent85724a0e6091239d4c901a03659d5b7e8946c5c6 (diff)
downloadgdb-1c79eb8a7d7126b5fcb734fb374be42a717d4373.zip
gdb-1c79eb8a7d7126b5fcb734fb374be42a717d4373.tar.gz
gdb-1c79eb8a7d7126b5fcb734fb374be42a717d4373.tar.bz2
gdb/gdbserver/
* regcache.c (init_register_cache): Initialize regcache->register_status. (free_register_cache): Release regcache->register_status. (regcache_cpy): Copy register_status. (registers_to_string): Print 'x's for unavailable registers. (supply_register): Mark the register's status valid or unavailable, depending on whether a buffer was passed in or not. (supply_register_zeroed): New. (supply_regblock): Mark the registers' status valid or unavailable, depending on whether a buffer was passed in or not. * regcache.h (REG_UNAVAILABLE, REG_VALID): New defines. (struct regcache): New `register_status' field. (supply_register_zeroed): Declare. * i387-fp.c (i387_xsave_to_cache): Zero out registers using supply_register_zeroed, rather than passing a NULL buffer to supply_register. * tracepoint.c (fetch_traceframe_registers): Update comment.
Diffstat (limited to 'gdb/gdbserver')
-rw-r--r--gdb/gdbserver/ChangeLog20
-rw-r--r--gdb/gdbserver/i387-fp.c6
-rw-r--r--gdb/gdbserver/regcache.c87
-rw-r--r--gdb/gdbserver/regcache.h18
-rw-r--r--gdb/gdbserver/tracepoint.c3
5 files changed, 124 insertions, 10 deletions
diff --git a/gdb/gdbserver/ChangeLog b/gdb/gdbserver/ChangeLog
index 39eb4e7..79ed909 100644
--- a/gdb/gdbserver/ChangeLog
+++ b/gdb/gdbserver/ChangeLog
@@ -1,5 +1,25 @@
2011-01-28 Pedro Alves <pedro@codesourcery.com>
+ * regcache.c (init_register_cache): Initialize
+ regcache->register_status.
+ (free_register_cache): Release regcache->register_status.
+ (regcache_cpy): Copy register_status.
+ (registers_to_string): Print 'x's for unavailable registers.
+ (supply_register): Mark the register's status valid or
+ unavailable, depending on whether a buffer was passed in or not.
+ (supply_register_zeroed): New.
+ (supply_regblock): Mark the registers' status valid or
+ unavailable, depending on whether a buffer was passed in or not.
+ * regcache.h (REG_UNAVAILABLE, REG_VALID): New defines.
+ (struct regcache): New `register_status' field.
+ (supply_register_zeroed): Declare.
+ * i387-fp.c (i387_xsave_to_cache): Zero out registers using
+ supply_register_zeroed, rather than passing a NULL buffer to
+ supply_register.
+ * tracepoint.c (fetch_traceframe_registers): Update comment.
+
+2011-01-28 Pedro Alves <pedro@codesourcery.com>
+
* i387-fp.c (i387_xsave_to_cache): Make passing NULL as register
buffer explicit.
diff --git a/gdb/gdbserver/i387-fp.c b/gdb/gdbserver/i387-fp.c
index 3dfe06b..80b5de6 100644
--- a/gdb/gdbserver/i387-fp.c
+++ b/gdb/gdbserver/i387-fp.c
@@ -482,7 +482,7 @@ i387_xsave_to_cache (struct regcache *regcache, const void *buf)
if ((clear_bv & I386_XSTATE_X87) != 0)
{
for (i = 0; i < 8; i++)
- supply_register (regcache, i + st0_regnum, NULL);
+ supply_register_zeroed (regcache, i + st0_regnum);
}
else
{
@@ -499,7 +499,7 @@ i387_xsave_to_cache (struct regcache *regcache, const void *buf)
if ((clear_bv & I386_XSTATE_SSE))
{
for (i = 0; i < num_xmm_registers; i++)
- supply_register (regcache, i + xmm0_regnum, NULL);
+ supply_register_zeroed (regcache, i + xmm0_regnum);
}
else
{
@@ -516,7 +516,7 @@ i387_xsave_to_cache (struct regcache *regcache, const void *buf)
if ((clear_bv & I386_XSTATE_AVX) != 0)
{
for (i = 0; i < num_xmm_registers; i++)
- supply_register (regcache, i + ymm0h_regnum, NULL);
+ supply_register_zeroed (regcache, i + ymm0h_regnum);
}
else
{
diff --git a/gdb/gdbserver/regcache.c b/gdb/gdbserver/regcache.c
index ec0f51c..ecd9744 100644
--- a/gdb/gdbserver/regcache.c
+++ b/gdb/gdbserver/regcache.c
@@ -98,6 +98,8 @@ init_register_cache (struct regcache *regcache, unsigned char *regbuf)
garbage. */
regcache->registers = xcalloc (1, register_bytes);
regcache->registers_owned = 1;
+ regcache->register_status = xcalloc (1, num_registers);
+ gdb_assert (REG_UNAVAILABLE == 0);
}
else
#else
@@ -108,6 +110,9 @@ init_register_cache (struct regcache *regcache, unsigned char *regbuf)
{
regcache->registers = regbuf;
regcache->registers_owned = 0;
+#ifndef IN_PROCESS_AGENT
+ regcache->register_status = NULL;
+#endif
}
regcache->registers_valid = 0;
@@ -136,6 +141,7 @@ free_register_cache (struct regcache *regcache)
{
if (regcache->registers_owned)
free (regcache->registers);
+ free (regcache->register_status);
free (regcache);
}
}
@@ -146,6 +152,10 @@ void
regcache_cpy (struct regcache *dst, struct regcache *src)
{
memcpy (dst->registers, src->registers, register_bytes);
+#ifndef IN_PROCESS_AGENT
+ if (dst->register_status != NULL && src->register_status != NULL)
+ memcpy (dst->register_status, src->register_status, num_registers);
+#endif
dst->registers_valid = src->registers_valid;
}
@@ -209,8 +219,23 @@ void
registers_to_string (struct regcache *regcache, char *buf)
{
unsigned char *registers = regcache->registers;
+ int i;
- convert_int_to_ascii (registers, buf, register_bytes);
+ for (i = 0; i < num_registers; i++)
+ {
+ if (regcache->register_status[i] == REG_VALID)
+ {
+ convert_int_to_ascii (registers, buf, register_size (i));
+ buf += register_size (i) * 2;
+ }
+ else
+ {
+ memset (buf, 'x', register_size (i) * 2);
+ buf += register_size (i) * 2;
+ }
+ registers += register_size (i);
+ }
+ *buf = '\0';
}
void
@@ -273,22 +298,74 @@ register_data (struct regcache *regcache, int n, int fetch)
return regcache->registers + (reg_defs[n].offset / 8);
}
+/* Supply register N, whose contents are stored in BUF, to REGCACHE.
+ If BUF is NULL, the register's value is recorded as
+ unavailable. */
+
void
supply_register (struct regcache *regcache, int n, const void *buf)
{
if (buf)
- memcpy (register_data (regcache, n, 0), buf, register_size (n));
+ {
+ memcpy (register_data (regcache, n, 0), buf, register_size (n));
+#ifndef IN_PROCESS_AGENT
+ if (regcache->register_status != NULL)
+ regcache->register_status[n] = REG_VALID;
+#endif
+ }
else
- memset (register_data (regcache, n, 0), 0, register_size (n));
+ {
+ memset (register_data (regcache, n, 0), 0, register_size (n));
+#ifndef IN_PROCESS_AGENT
+ if (regcache->register_status != NULL)
+ regcache->register_status[n] = REG_UNAVAILABLE;
+#endif
+ }
}
+/* Supply register N with value zero to REGCACHE. */
+
+void
+supply_register_zeroed (struct regcache *regcache, int n)
+{
+ memset (register_data (regcache, n, 0), 0, register_size (n));
+#ifndef IN_PROCESS_AGENT
+ if (regcache->register_status != NULL)
+ regcache->register_status[n] = REG_VALID;
+#endif
+}
+
+/* Supply the whole register set whose contents are stored in BUF, to
+ REGCACHE. If BUF is NULL, all the registers' values are recorded
+ as unavailable. */
+
void
supply_regblock (struct regcache *regcache, const void *buf)
{
if (buf)
- memcpy (regcache->registers, buf, register_bytes);
+ {
+ memcpy (regcache->registers, buf, register_bytes);
+#ifndef IN_PROCESS_AGENT
+ {
+ int i;
+
+ for (i = 0; i < num_registers; i++)
+ regcache->register_status[i] = REG_VALID;
+ }
+#endif
+ }
else
- memset (regcache->registers, 0, register_bytes);
+ {
+ memset (regcache->registers, 0, register_bytes);
+#ifndef IN_PROCESS_AGENT
+ {
+ int i;
+
+ for (i = 0; i < num_registers; i++)
+ regcache->register_status[i] = REG_UNAVAILABLE;
+ }
+#endif
+ }
}
#ifndef IN_PROCESS_AGENT
diff --git a/gdb/gdbserver/regcache.h b/gdb/gdbserver/regcache.h
index df3b261..5fe64cb 100644
--- a/gdb/gdbserver/regcache.h
+++ b/gdb/gdbserver/regcache.h
@@ -23,15 +23,31 @@
struct inferior_list_entry;
struct thread_info;
+/* The register exists, it has a value, but we don't know what it is.
+ Used when inspecting traceframes. */
+#define REG_UNAVAILABLE 0
+
+/* We know the register's value (and we have it cached). */
+#define REG_VALID 1
+
/* The data for the register cache. Note that we have one per
inferior; this is primarily for simplicity, as the performance
benefit is minimal. */
struct regcache
{
+ /* Whether the REGISTERS buffer's contents are valid. If false, we
+ haven't fetched the registers from the target yet. Not that this
+ register cache is _not_ pass-through, unlike GDB's. Note that
+ "valid" here is unrelated to whether the registers are available
+ in a traceframe. For that, check REGISTER_STATUS below. */
int registers_valid;
int registers_owned;
unsigned char *registers;
+#ifndef IN_PROCESS_AGENT
+ /* One of REG_UNAVAILBLE or REG_VALID. */
+ unsigned char *register_status;
+#endif
};
struct regcache *init_register_cache (struct regcache *regcache,
@@ -84,6 +100,8 @@ extern const char *gdbserver_xmltarget;
void supply_register (struct regcache *regcache, int n, const void *buf);
+void supply_register_zeroed (struct regcache *regcache, int n);
+
void supply_register_by_name (struct regcache *regcache,
const char *name, const void *buf);
diff --git a/gdb/gdbserver/tracepoint.c b/gdb/gdbserver/tracepoint.c
index c9e9ead..2da57ed 100644
--- a/gdb/gdbserver/tracepoint.c
+++ b/gdb/gdbserver/tracepoint.c
@@ -4840,8 +4840,7 @@ fetch_traceframe_registers (int tfnum, struct regcache *regcache, int regnum)
dataptr = traceframe_find_regblock (tframe, tfnum);
if (dataptr == NULL)
{
- /* We don't like making up numbers, but GDB has all manner of
- troubles when the target says there are no registers. */
+ /* Mark registers unavailable. */
supply_regblock (regcache, NULL);
/* We can generally guess at a PC, although this will be