diff --git a/gdb/gdbserver/ChangeLog b/gdb/gdbserver/ChangeLog index 39eb4e76af..79ed9096e4 100644 --- a/gdb/gdbserver/ChangeLog +++ b/gdb/gdbserver/ChangeLog @@ -1,3 +1,23 @@ +2011-01-28 Pedro Alves + + * 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 * i387-fp.c (i387_xsave_to_cache): Make passing NULL as register diff --git a/gdb/gdbserver/i387-fp.c b/gdb/gdbserver/i387-fp.c index 3dfe06be3b..80b5de66f0 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 ec0f51cc4d..ecd974441b 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 df3b2615bc..5fe64cb1d8 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 c9e9ead327..2da57edb99 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