[PATCH v4 3/6] Refactor arm_software_single_step to use regcache.

Antoine Tremblay
2015-12-02T13:18:18Z

This patch is in preparation for software single step support on ARM in
GDBServer. It refactors arm_*_software_single_step and sub-functions to
use regcache instead of frame to access registers so that the code can be
shared more easily between GDB and GDBServer.

Note also that since the intention is at some point to get rid of frame
completely in that function, memory reads have also been replaced by
read_memory_unsigned_integer rather than get_frame_memory_unsigned.

No regressions, tested on ubuntu 14.04 ARMv7 and x86.
With gdbserver-{native,extended} / { -marm -mthumb }

gdb/ChangeLog:

* arm-linux-tdep.c (arm_linux_software_single_step): Use regcache
instead of frame.
* arm-tdep.c (arm_is_thumb): New function.
(shifted_reg_va): Use regcache instead of frame.
(thumb_get_next_pc_raw): Likewise.
(arm_get_next_pc_raw): Likewise.
(thumb_deal_with_atomic_sequence_raw): Likewise.
(arm_deal_with_atomic_sequence_raw): Likewise.
(arm_deal_with_atomic_sequence): Likewise.
* arm-tdep.h (arm_get_next_pc): Likewise.
(arm_deal_with_atomic_sequence): Likewise.
(arm_is_thumb): New declaration.
* common/common-regcache.h (register_status) New enum.
(regcache_raw_read_unsigned): New declaration.
* regcache.h (enum register_status): Move to common-regcache.h.
(regcache_raw_read_unsigned): Likewise.

gdb/gdbserver/ChangeLog:

* regcache.c (regcache_raw_read_unsigned): New function.
* regcache.h (REG_UNAVAILABLE, REG_VALID): Replaced by shared
register_status enum.
(init_register_cache): Initialize cache to REG_UNAVAILABLE.
---
gdb/arm-linux-tdep.c | 10 +--
gdb/arm-tdep.c | 164 +++++++++++++++++++++++++++----------------
gdb/arm-tdep.h | 6 +-
gdb/common/common-regcache.h | 22 ++++++
gdb/gdbserver/regcache.c | 26 ++++++-
gdb/gdbserver/regcache.h | 7 --
gdb/regcache.h | 21 ------
7 files changed, 158 insertions(+), 98 deletions(-)

diff --git a/gdb/arm-linux-tdep.c b/gdb/arm-linux-tdep.c
index 73e1271..2c1ce88 100644
--- a/gdb/arm-linux-tdep.c
+++ b/gdb/arm-linux-tdep.c
@@ -910,11 +910,13 @@ arm_linux_syscall_next_pc (struct frame_info *frame)
static int
arm_linux_software_single_step (struct frame_info *frame)
{
- struct gdbarch *gdbarch = get_frame_arch (frame);
- struct address_space *aspace = get_frame_address_space (frame);
+ struct regcache *regcache = get_current_regcache ();
+ struct gdbarch *gdbarch = get_regcache_arch (regcache);
+ struct address_space *aspace = get_regcache_aspace (regcache);
+
CORE_ADDR next_pc;

- if (arm_deal_with_atomic_sequence (frame))
+ if (arm_deal_with_atomic_sequence (regcache))
return 1;

/* If the target does have hardware single step, GDB doesn't have
@@ -922,7 +924,7 @@ arm_linux_software_single_step (struct frame_info *frame)
if (target_can_do_single_step () == 1)
return 0;

- next_pc = arm_get_next_pc (frame, get_frame_pc (frame));
+ next_pc = arm_get_next_pc (regcache, frame, regcache_read_pc (regcache));

/* The Linux kernel offers some user-mode helpers in a high page. We can
not read this page (as of 2.6.23), and even if we could then we couldn't
diff --git a/gdb/arm-tdep.c b/gdb/arm-tdep.c
index 848af97..1d7e127 100644
--- a/gdb/arm-tdep.c
+++ b/gdb/arm-tdep.c
@@ -281,6 +281,19 @@ arm_psr_thumb_bit (struct gdbarch *gdbarch)
return CPSR_T;
}

+/* Determine if the processor is currently executing in Thumb mode. */
+
+int
+arm_is_thumb (struct regcache *regcache)
+{
+ ULONGEST cpsr;
+ ULONGEST t_bit = arm_psr_thumb_bit (get_regcache_arch (regcache));
+
+ regcache_raw_read_unsigned (regcache, ARM_PS_REGNUM, &cpsr);
+
+ return (cpsr & t_bit) != 0;
+}
+
/* Determine if FRAME is executing in Thumb mode. */

int
@@ -4302,25 +4315,29 @@ convert_to_extended (const struct floatformat *fmt, void *dbl, const void *ptr,
}

static unsigned long
-shifted_reg_val (struct frame_info *frame, unsigned long inst, int carry,
+shifted_reg_val (struct regcache *regcache, unsigned long inst, int carry,
unsigned long pc_val, unsigned long status_reg)
{
unsigned long res, shift;
int rm = bits (inst, 0, 3);
unsigned long shifttype = bits (inst, 5, 6);
+ ULONGEST rm_data;

if (bit (inst, 4))
{
int rs = bits (inst, 8, 11);
+ ULONGEST rs_data;
+ regcache_raw_read_unsigned (regcache, rs, &rs_data);
shift = (rs == 15 ? pc_val + 8
- : get_frame_register_unsigned (frame, rs)) & 0xFF;
+ : rs_data) & 0xFF;
}
else
shift = bits (inst, 7, 11);

+ regcache_raw_read_unsigned (regcache, rm, &rm_data);
res = (rm == ARM_PC_REGNUM
? (pc_val + (bit (inst, 4) ? 12 : 8))
- : get_frame_register_unsigned (frame, rm));
+ : rm_data);

switch (shifttype)
{
@@ -4372,15 +4389,16 @@ thumb_advance_itstate (unsigned int itstate)
another breakpoint by our caller. */

static CORE_ADDR
-thumb_get_next_pc_raw (struct frame_info *frame, CORE_ADDR pc)
+thumb_get_next_pc_raw (struct regcache *regcache, struct frame_info *frame,
+ CORE_ADDR pc)
{
- struct gdbarch *gdbarch = get_frame_arch (frame);
- struct address_space *aspace = get_frame_address_space (frame);
+ struct gdbarch *gdbarch = get_regcache_arch (regcache);
+ struct address_space *aspace = get_regcache_aspace (regcache);
enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
enum bfd_endian byte_order_for_code = gdbarch_byte_order_for_code (gdbarch);
unsigned long pc_val = ((unsigned long) pc) + 4; /* PC after prefetch */
unsigned short inst1;
- CORE_ADDR nextpc = pc + 2; /* Default is next instruction. */
+ ULONGEST nextpc = pc + 2; /* Default is next instruction. */
unsigned long offset;
ULONGEST status, itstate;

@@ -4397,7 +4415,7 @@ thumb_get_next_pc_raw (struct frame_info *frame, CORE_ADDR pc)
base condition. One of the low four bits will be set if an IT
block is active. These bits read as zero on earlier
processors. */
- status = get_frame_register_unsigned (frame, ARM_PS_REGNUM);
+ regcache_raw_read_unsigned (regcache, ARM_PS_REGNUM, &status);
itstate = ((status >> 8) & 0xfc) | ((status >> 25) & 0x3);

/* If-Then handling. On GNU/Linux, where this routine is used, we
@@ -4507,12 +4525,12 @@ thumb_get_next_pc_raw (struct frame_info *frame, CORE_ADDR pc)

if ((inst1 & 0xff00) == 0xbd00) /* pop {rlist, pc} */
{
- CORE_ADDR sp;
+ ULONGEST sp;

/* Fetch the saved PC from the stack. It's stored above
all of the other registers. */
offset = bitcount (bits (inst1, 0, 7)) * INT_REGISTER_SIZE;
- sp = get_frame_register_unsigned (frame, ARM_SP_REGNUM);
+ regcache_raw_read_unsigned (regcache, ARM_SP_REGNUM, &sp);
nextpc = read_memory_unsigned_integer (sp + offset, 4, byte_order);
}
else if ((inst1 & 0xf000) == 0xd000) /* conditional branch */
@@ -4568,7 +4586,7 @@ thumb_get_next_pc_raw (struct frame_info *frame, CORE_ADDR pc)
else if (inst1 == 0xf3de && (inst2 & 0xff00) == 0x3f00)
{
/* SUBS PC, LR, #imm8. */
- nextpc = get_frame_register_unsigned (frame, ARM_LR_REGNUM);
+ regcache_raw_read_unsigned (regcache, ARM_LR_REGNUM, &nextpc);
nextpc -= inst2 & 0x00ff;
}
else if ((inst2 & 0xd000) == 0x8000 && (inst1 & 0x0380) != 0x0380)
@@ -4626,24 +4644,26 @@ thumb_get_next_pc_raw (struct frame_info *frame, CORE_ADDR pc)

if (load_pc)
{
- CORE_ADDR addr = get_frame_register_unsigned (frame, rn);
- nextpc = get_frame_memory_unsigned (frame, addr + offset, 4);
+ ULONGEST addr;
+ regcache_raw_read_unsigned (regcache, rn, &addr);
+ nextpc = read_memory_unsigned_integer (addr + offset, 4,
+ byte_order);
}
}
else if ((inst1 & 0xffef) == 0xea4f && (inst2 & 0xfff0) == 0x0f00)
{
/* MOV PC or MOVS PC. */
- nextpc = get_frame_register_unsigned (frame, bits (inst2, 0, 3));
+ regcache_raw_read_unsigned (regcache, bits (inst2, 0, 3), &nextpc);
nextpc = MAKE_THUMB_ADDR (nextpc);
}
else if ((inst1 & 0xff70) == 0xf850 && (inst2 & 0xf000) == 0xf000)
{
/* LDR PC. */
- CORE_ADDR base;
+ ULONGEST base;
int rn, load_pc = 1;

rn = bits (inst1, 0, 3);
- base = get_frame_register_unsigned (frame, rn);
+ regcache_raw_read_unsigned (regcache, rn, &base);
if (rn == ARM_PC_REGNUM)
{
base = (base + 4) & ~(CORE_ADDR) 0x3;
@@ -4667,43 +4687,51 @@ thumb_get_next_pc_raw (struct frame_info *frame, CORE_ADDR pc)
else if ((inst2 & 0x0fc0) == 0x0000)
{
int shift = bits (inst2, 4, 5), rm = bits (inst2, 0, 3);
- base += get_frame_register_unsigned (frame, rm) << shift;
+ ULONGEST rm_data;
+ regcache_raw_read_unsigned (regcache, rm, &rm_data);
+ base += rm_data << shift;
}
else
/* Reserved. */
load_pc = 0;

if (load_pc)
- nextpc = get_frame_memory_unsigned (frame, base, 4);
+ nextpc = read_memory_unsigned_integer (base, 4, byte_order);
}
else if ((inst1 & 0xfff0) == 0xe8d0 && (inst2 & 0xfff0) == 0xf000)
{
/* TBB. */
- CORE_ADDR tbl_reg, table, offset, length;
+ ULONGEST tbl_reg, table, offset, length;

tbl_reg = bits (inst1, 0, 3);
if (tbl_reg == 0x0f)
table = pc + 4; /* Regcache copy of PC isn't right yet. */
else
- table = get_frame_register_unsigned (frame, tbl_reg);
+ regcache_raw_read_unsigned (regcache, tbl_reg, &table);
+
+ regcache_raw_read_unsigned (regcache, bits (inst2, 0, 3), &offset);

- offset = get_frame_register_unsigned (frame, bits (inst2, 0, 3));
- length = 2 * get_frame_memory_unsigned (frame, table + offset, 1);
+ length = 2 * read_memory_unsigned_integer (table + offset, 1,
+ byte_order);
nextpc = pc_val + length;
}
else if ((inst1 & 0xfff0) == 0xe8d0 && (inst2 & 0xfff0) == 0xf010)
{
/* TBH. */
- CORE_ADDR tbl_reg, table, offset, length;
+ ULONGEST tbl_reg, table, offset, length, reg_offset;

tbl_reg = bits (inst1, 0, 3);
if (tbl_reg == 0x0f)
table = pc + 4; /* Regcache copy of PC isn't right yet. */
else
- table = get_frame_register_unsigned (frame, tbl_reg);
+ regcache_raw_read_unsigned (regcache, tbl_reg, &table);
+
+ regcache_raw_read_unsigned (regcache, bits (inst2, 0, 3),
+ &reg_offset);
+ offset = 2 * reg_offset;

- offset = 2 * get_frame_register_unsigned (frame, bits (inst2, 0, 3));
- length = 2 * get_frame_memory_unsigned (frame, table + offset, 2);
+ length = 2 * read_memory_unsigned_integer (table + offset, 2,
+ byte_order);
nextpc = pc_val + length;
}
}
@@ -4712,14 +4740,14 @@ thumb_get_next_pc_raw (struct frame_info *frame, CORE_ADDR pc)
if (bits (inst1, 3, 6) == 0x0f)
nextpc = UNMAKE_THUMB_ADDR (pc_val);
else
- nextpc = get_frame_register_unsigned (frame, bits (inst1, 3, 6));
+ regcache_raw_read_unsigned (regcache, bits (inst1, 3, 6), &nextpc);
}
else if ((inst1 & 0xff87) == 0x4687) /* mov pc, REG */
{
if (bits (inst1, 3, 6) == 0x0f)
nextpc = pc_val;
else
- nextpc = get_frame_register_unsigned (frame, bits (inst1, 3, 6));
+ regcache_raw_read_unsigned (regcache, bits (inst1, 3, 6), &nextpc);

nextpc = MAKE_THUMB_ADDR (nextpc);
}
@@ -4727,7 +4755,8 @@ thumb_get_next_pc_raw (struct frame_info *frame, CORE_ADDR pc)
{
/* CBNZ or CBZ. */
int imm = (bit (inst1, 9) << 6) + (bits (inst1, 3, 7) << 1);
- ULONGEST reg = get_frame_register_unsigned (frame, bits (inst1, 0, 2));
+ ULONGEST reg;
+ regcache_raw_read_unsigned (regcache, bits (inst1, 0, 2), &reg);

if (bit (inst1, 11) && reg != 0)
nextpc = pc_val + imm;
@@ -4746,20 +4775,22 @@ thumb_get_next_pc_raw (struct frame_info *frame, CORE_ADDR pc)
address. */

static CORE_ADDR
-arm_get_next_pc_raw (struct frame_info *frame, CORE_ADDR pc)
+arm_get_next_pc_raw (struct regcache *regcache, struct frame_info *frame,
+ CORE_ADDR pc)
{
- struct gdbarch *gdbarch = get_frame_arch (frame);
+ struct gdbarch *gdbarch = get_regcache_arch (regcache);
enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
enum bfd_endian byte_order_for_code = gdbarch_byte_order_for_code (gdbarch);
unsigned long pc_val;
unsigned long this_instr;
- unsigned long status;
+ ULONGEST status;
CORE_ADDR nextpc;

pc_val = (unsigned long) pc;
this_instr = read_memory_unsigned_integer (pc, 4, byte_order_for_code);

- status = get_frame_register_unsigned (frame, ARM_PS_REGNUM);
+ regcache_raw_read_unsigned (regcache, ARM_PS_REGNUM, &status);
+
nextpc = (CORE_ADDR) (pc_val + 4); /* Default case */

if (bits (this_instr, 28, 31) == INST_NV)
@@ -4793,6 +4824,7 @@ arm_get_next_pc_raw (struct frame_info *frame, CORE_ADDR pc)
{
unsigned long operand1, operand2, result = 0;
unsigned long rn;
+ ULONGEST reg_data;
int c;

if (bits (this_instr, 12, 15) != 15)
@@ -4807,9 +4839,10 @@ arm_get_next_pc_raw (struct frame_info *frame, CORE_ADDR pc)
|| bits (this_instr, 4, 27) == 0x12fff3)
{
rn = bits (this_instr, 0, 3);
+ regcache_raw_read_unsigned (regcache, rn, &reg_data);
nextpc = ((rn == ARM_PC_REGNUM)
? (pc_val + 8)
- : get_frame_register_unsigned (frame, rn));
+ : reg_data);

return nextpc;
}
@@ -4817,9 +4850,10 @@ arm_get_next_pc_raw (struct frame_info *frame, CORE_ADDR pc)
/* Multiply into PC. */
c = (status & FLAG_C) ? 1 : 0;
rn = bits (this_instr, 16, 19);
+ regcache_raw_read_unsigned (regcache, rn, &reg_data);
operand1 = ((rn == ARM_PC_REGNUM)
? (pc_val + 8)
- : get_frame_register_unsigned (frame, rn));
+ : reg_data);

if (bit (this_instr, 25))
{
@@ -4829,7 +4863,7 @@ arm_get_next_pc_raw (struct frame_info *frame, CORE_ADDR pc)
& 0xffffffff;
}
else /* operand 2 is a shifted register. */
- operand2 = shifted_reg_val (frame, this_instr, c,
+ operand2 = shifted_reg_val (regcache, this_instr, c,
pc_val, status);

switch (bits (this_instr, 21, 24))
@@ -4920,15 +4954,17 @@ arm_get_next_pc_raw (struct frame_info *frame, CORE_ADDR pc)
/* rd == pc */
unsigned long rn;
unsigned long base;
+ ULONGEST reg_data;

if (bit (this_instr, 22))
error (_("Invalid update to pc in instruction"));

/* byte write to PC */
rn = bits (this_instr, 16, 19);
+ regcache_raw_read_unsigned (regcache, rn, &reg_data);
base = ((rn == ARM_PC_REGNUM)
? (pc_val + 8)
- : get_frame_register_unsigned (frame, rn));
+ : reg_data);

if (bit (this_instr, 24))
{
@@ -4936,7 +4972,8 @@ arm_get_next_pc_raw (struct frame_info *frame, CORE_ADDR pc)
int c = (status & FLAG_C) ? 1 : 0;
unsigned long offset =
(bit (this_instr, 25)
- ? shifted_reg_val (frame, this_instr, c, pc_val, status)
+ ? shifted_reg_val (regcache, this_instr, c, pc_val,
+ status)
: bits (this_instr, 0, 11));

if (bit (this_instr, 23))
@@ -4960,9 +4997,10 @@ arm_get_next_pc_raw (struct frame_info *frame, CORE_ADDR pc)
{
/* loading pc */
int offset = 0;
- unsigned long rn_val
- = get_frame_register_unsigned (frame,
- bits (this_instr, 16, 19));
+ ULONGEST rn_val;
+ regcache_raw_read_unsigned (regcache,
+ bits (this_instr, 16, 19),
+ &rn_val);

if (bit (this_instr, 23))
{
@@ -5019,14 +5057,15 @@ arm_get_next_pc_raw (struct frame_info *frame, CORE_ADDR pc)
loop is detected. */

CORE_ADDR
-arm_get_next_pc (struct frame_info *frame, CORE_ADDR pc)
+arm_get_next_pc (struct regcache *regcache, struct frame_info *frame,
+ CORE_ADDR pc)
{
CORE_ADDR nextpc;

- if (arm_frame_is_thumb (frame))
- nextpc = thumb_get_next_pc_raw (frame, pc);
+ if (arm_is_thumb (regcache))
+ nextpc = thumb_get_next_pc_raw (regcache, frame, pc);
else
- nextpc = arm_get_next_pc_raw (frame, pc);
+ nextpc = arm_get_next_pc_raw (regcache, frame, pc);

return nextpc;
}
@@ -5057,12 +5096,12 @@ arm_insert_single_step_breakpoint (struct gdbarch *gdbarch,
the sequence. */

static int
-thumb_deal_with_atomic_sequence_raw (struct frame_info *frame)
+thumb_deal_with_atomic_sequence_raw (struct regcache *regcache)
{
- struct gdbarch *gdbarch = get_frame_arch (frame);
- struct address_space *aspace = get_frame_address_space (frame);
+ struct gdbarch *gdbarch = get_regcache_arch (regcache);
+ struct address_space *aspace = get_regcache_aspace (regcache);
enum bfd_endian byte_order_for_code = gdbarch_byte_order_for_code (gdbarch);
- CORE_ADDR pc = get_frame_pc (frame);
+ CORE_ADDR pc = regcache_read_pc (regcache);
CORE_ADDR breaks[2] = {-1, -1};
CORE_ADDR loc = pc;
unsigned short insn1, insn2;
@@ -5073,7 +5112,7 @@ thumb_deal_with_atomic_sequence_raw (struct frame_info *frame)
ULONGEST status, itstate;

/* We currently do not support atomic sequences within an IT block. */
- status = get_frame_register_unsigned (frame, ARM_PS_REGNUM);
+ regcache_raw_read_unsigned (regcache, ARM_PS_REGNUM, &status);
itstate = ((status >> 8) & 0xfc) | ((status >> 25) & 0x3);
if (itstate & 0x0f)
return 0;
@@ -5188,12 +5227,12 @@ thumb_deal_with_atomic_sequence_raw (struct frame_info *frame)
}

static int
-arm_deal_with_atomic_sequence_raw (struct frame_info *frame)
+arm_deal_with_atomic_sequence_raw (struct regcache *regcache)
{
- struct gdbarch *gdbarch = get_frame_arch (frame);
- struct address_space *aspace = get_frame_address_space (frame);
+ struct gdbarch *gdbarch = get_regcache_arch (regcache);
+ struct address_space *aspace = get_regcache_aspace (regcache);
enum bfd_endian byte_order_for_code = gdbarch_byte_order_for_code (gdbarch);
- CORE_ADDR pc = get_frame_pc (frame);
+ CORE_ADDR pc = regcache_read_pc (regcache);
CORE_ADDR breaks[2] = {-1, -1};
CORE_ADDR loc = pc;
unsigned int insn;
@@ -5263,12 +5302,12 @@ arm_deal_with_atomic_sequence_raw (struct frame_info *frame)
}

int
-arm_deal_with_atomic_sequence (struct frame_info *frame)
+arm_deal_with_atomic_sequence (struct regcache *regcache)
{
- if (arm_frame_is_thumb (frame))
- return thumb_deal_with_atomic_sequence_raw (frame);
+ if (arm_is_thumb (regcache))
+ return thumb_deal_with_atomic_sequence_raw (regcache);
else
- return arm_deal_with_atomic_sequence_raw (frame);
+ return arm_deal_with_atomic_sequence_raw (regcache);
}

/* single_step() is called just before we want to resume the inferior,
@@ -5279,14 +5318,15 @@ arm_deal_with_atomic_sequence (struct frame_info *frame)
int
arm_software_single_step (struct frame_info *frame)
{
- struct gdbarch *gdbarch = get_frame_arch (frame);
- struct address_space *aspace = get_frame_address_space (frame);
+ struct regcache *regcache = get_current_regcache ();
+ struct gdbarch *gdbarch = get_regcache_arch (regcache);
+ struct address_space *aspace = get_regcache_aspace (regcache);
CORE_ADDR next_pc;

- if (arm_deal_with_atomic_sequence (frame))
+ if (arm_deal_with_atomic_sequence (regcache))
return 1;

- next_pc = arm_get_next_pc (frame, get_frame_pc (frame));
+ next_pc = arm_get_next_pc (regcache, frame, regcache_read_pc (regcache));
arm_insert_single_step_breakpoint (gdbarch, aspace, next_pc);

return 1;
diff --git a/gdb/arm-tdep.h b/gdb/arm-tdep.h
index 9b8447b..97ce97d 100644
--- a/gdb/arm-tdep.h
+++ b/gdb/arm-tdep.h
@@ -250,11 +250,13 @@ extern void
ULONGEST val, enum pc_write_style write_pc);

CORE_ADDR arm_skip_stub (struct frame_info *, CORE_ADDR);
-CORE_ADDR arm_get_next_pc (struct frame_info *, CORE_ADDR);
+CORE_ADDR arm_get_next_pc (struct regcache *regcache, struct frame_info *frame,
+ CORE_ADDR pc);
void arm_insert_single_step_breakpoint (struct gdbarch *,
struct address_space *, CORE_ADDR);
-int arm_deal_with_atomic_sequence (struct frame_info *);
+int arm_deal_with_atomic_sequence (struct regcache *);
int arm_software_single_step (struct frame_info *);
+int arm_is_thumb (struct regcache *regcache);
int arm_frame_is_thumb (struct frame_info *frame);

extern struct displaced_step_closure *
diff --git a/gdb/common/common-regcache.h b/gdb/common/common-regcache.h
index c470603..3dca30a 100644
--- a/gdb/common/common-regcache.h
+++ b/gdb/common/common-regcache.h
@@ -22,6 +22,24 @@

/* This header is a stopgap until we have an independent regcache. */

+enum register_status
+ {
+ /* The register value is not in the cache, and we don't know yet
+ whether it's available in the target (or traceframe). */
+ REG_UNKNOWN = 0,
+
+ /* The register value is valid and cached. */
+ REG_VALID = 1,
+
+ /* The register value is unavailable. E.g., we're inspecting a
+ traceframe, and this register wasn't collected. Note that this
+ is different a different "unavailable" from saying the register
+ does not exist in the target's architecture --- in that case,
+ the target should have given us a target description that does
+ not include the register in the first place. */
+ REG_UNAVAILABLE = -1
+ };
+
/* Return a pointer to the register cache associated with the
thread specified by PTID. This function must be provided by
the client. */
@@ -38,4 +56,8 @@ extern int regcache_register_size (const struct regcache *regcache, int n);

extern CORE_ADDR regcache_read_pc (struct regcache *regcache);

+/* Read a raw register into a unsigned integer. */
+extern enum register_status regcache_raw_read_unsigned
+ (struct regcache *regcache, int regnum, ULONGEST *val);
+
#endif /* COMMON_REGCACHE_H */
diff --git a/gdb/gdbserver/regcache.c b/gdb/gdbserver/regcache.c
index b9311fe..c608bf3 100644
--- a/gdb/gdbserver/regcache.c
+++ b/gdb/gdbserver/regcache.c
@@ -145,8 +145,9 @@ init_register_cache (struct regcache *regcache,
= (unsigned char *) xcalloc (1, tdesc->registers_size);
regcache->registers_owned = 1;
regcache->register_status
- = (unsigned char *) xcalloc (1, tdesc->num_registers);
- gdb_assert (REG_UNAVAILABLE == 0);
+ = (unsigned char *) xmalloc (tdesc->num_registers);
+ memset ((void *) regcache->register_status, REG_UNAVAILABLE,
+ tdesc->num_registers);
#else
gdb_assert_not_reached ("can't allocate memory from the heap");
#endif
@@ -435,6 +436,27 @@ collect_register (struct regcache *regcache, int n, void *buf)
register_size (regcache->tdesc, n));
}

+enum register_status
+regcache_raw_read_unsigned (struct regcache *regcache, int regnum,
+ ULONGEST *val)
+{
+ int size;
+
+ gdb_assert (regcache != NULL);
+ gdb_assert (regnum >= 0 && regnum < regcache->tdesc->num_registers);
+
+ size = register_size (regcache->tdesc, regnum);
+
+ if (size > (int) sizeof (ULONGEST))
+ error (_("That operation is not available on integers of more than"
+ "%d bytes."),
+ (int) sizeof (ULONGEST));
+
+ collect_register (regcache, regnum, val);
+
+ return REG_VALID;
+}
+
#ifndef IN_PROCESS_AGENT

void
diff --git a/gdb/gdbserver/regcache.h b/gdb/gdbserver/regcache.h
index a0be95e..f4b798b 100644
--- a/gdb/gdbserver/regcache.h
+++ b/gdb/gdbserver/regcache.h
@@ -24,13 +24,6 @@
struct thread_info;
struct target_desc;

-/* 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. */
diff --git a/gdb/regcache.h b/gdb/regcache.h
index a9fb44b..76de9e8 100644
--- a/gdb/regcache.h
+++ b/gdb/regcache.h
@@ -47,24 +47,6 @@ extern struct gdbarch *get_regcache_arch (const struct regcache *regcache);

extern struct address_space *get_regcache_aspace (const struct regcache *);

-enum register_status
- {
- /* The register value is not in the cache, and we don't know yet
- whether it's available in the target (or traceframe). */
- REG_UNKNOWN = 0,
-
- /* The register value is valid and cached. */
- REG_VALID = 1,
-
- /* The register value is unavailable. E.g., we're inspecting a
- traceframe, and this register wasn't collected. Note that this
- is different a different "unavailable" from saying the register
- does not exist in the target's architecture --- in that case,
- the target should have given us a target description that does
- not include the register in the first place. */
- REG_UNAVAILABLE = -1
- };
-
enum register_status regcache_register_status (const struct regcache *regcache,
int regnum);

@@ -78,9 +60,6 @@ void regcache_raw_write (struct regcache *regcache, int rawnum,
extern enum register_status
regcache_raw_read_signed (struct regcache *regcache,
int regnum, LONGEST *val);
-extern enum register_status
- regcache_raw_read_unsigned (struct regcache *regcache,
- int regnum, ULONGEST *val);
extern void regcache_raw_write_signed (struct regcache *regcache,
int regnum, LONGEST val);
extern void regcache_raw_write_unsigned (struct regcache *regcache,
--
2.6.3