Compare commits

...

7 Commits

Author SHA1 Message Date
Alan Hayward
8cc29a6ace [PATCH 7/7]: Regcache: Refactor raw_set_cached_value 2017-08-15 16:41:00 +01:00
Alan Hayward
a20c2452a4 [PATCH 6/7]: Regcache: jit should use a writable regcache 2017-08-15 16:40:35 +01:00
Alan Hayward
4ac8135dd8 [PATCH 5/7]: Regcache: Allow writable regcache 2017-08-15 16:40:09 +01:00
Alan Hayward
e9a5485336 [PATCH 4/7] Regcache: Refactor dup/cpy/save/restore 2017-08-15 16:39:47 +01:00
Alan Hayward
5c7af491c5 [PATCH 3/7]: Regcache: Remove xmalloc/xfree methods 2017-08-15 16:39:27 +01:00
Alan Hayward
c14731f7e9 [PATCH 2/7] Regcache: Only target_regcache reads/writes go to the target 2017-08-15 16:39:04 +01:00
Alan Hayward
15587be5bd [PATCH 1/7] Regcache: Subclass ptid functionality to target_regcache 2017-08-15 16:38:22 +01:00
11 changed files with 275 additions and 281 deletions

View File

@@ -1021,13 +1021,12 @@ struct regcache *
frame_save_as_regcache (struct frame_info *this_frame) frame_save_as_regcache (struct frame_info *this_frame)
{ {
struct address_space *aspace = get_frame_address_space (this_frame); struct address_space *aspace = get_frame_address_space (this_frame);
struct regcache *regcache = regcache_xmalloc (get_frame_arch (this_frame), regcache *backup = new regcache (get_frame_arch (this_frame), aspace);
aspace); struct cleanup *cleanups = make_cleanup_regcache_delete (backup);
struct cleanup *cleanups = make_cleanup_regcache_xfree (regcache);
regcache_save (regcache, do_frame_register_read, this_frame); backup->save (do_frame_register_read, this_frame);
discard_cleanups (cleanups); discard_cleanups (cleanups);
return regcache; return backup;
} }
void void
@@ -1063,7 +1062,7 @@ frame_pop (struct frame_info *this_frame)
trying to extract the old values from the current regcache while trying to extract the old values from the current regcache while
at the same time writing new values into that same cache. */ at the same time writing new values into that same cache. */
scratch = frame_save_as_regcache (prev_frame); scratch = frame_save_as_regcache (prev_frame);
cleanups = make_cleanup_regcache_xfree (scratch); cleanups = make_cleanup_regcache_delete (scratch);
/* FIXME: cagney/2003-03-16: It should be possible to tell the /* FIXME: cagney/2003-03-16: It should be possible to tell the
target's register cache that it is about to be hit with a burst target's register cache that it is about to be hit with a burst
@@ -1073,9 +1072,8 @@ frame_pop (struct frame_info *this_frame)
Unfortunately, they don't implement it. Their lack of a formal Unfortunately, they don't implement it. Their lack of a formal
definition can lead to targets writing back bogus values definition can lead to targets writing back bogus values
(arguably a bug in the target code mind). */ (arguably a bug in the target code mind). */
/* Now copy those saved registers into the current regcache. /* Now copy those saved registers into the current regcache. */
Here, regcache_cpy() calls regcache_restore(). */ scratch->restore_to (get_current_regcache ());
regcache_cpy (get_current_regcache (), scratch);
do_cleanups (cleanups); do_cleanups (cleanups);
/* We've made right mess of GDB's local state, just discard /* We've made right mess of GDB's local state, just discard

View File

@@ -27,11 +27,11 @@ namespace selftests {
/* A read-write regcache which doesn't write the target. */ /* A read-write regcache which doesn't write the target. */
class regcache_test : public regcache class regcache_test : public target_regcache
{ {
public: public:
explicit regcache_test (struct gdbarch *gdbarch) explicit regcache_test (struct gdbarch *gdbarch)
: regcache (gdbarch, NULL, false) : target_regcache (gdbarch, NULL)
{ {
set_ptid (inferior_ptid); set_ptid (inferior_ptid);
@@ -40,7 +40,8 @@ public:
void raw_write (int regnum, const gdb_byte *buf) override void raw_write (int regnum, const gdb_byte *buf) override
{ {
raw_set_cached_value (regnum, buf); /* Bypass writing to the target. */
regcache::raw_write (regnum, buf);
} }
}; };

View File

@@ -1602,8 +1602,8 @@ advance_command (char *arg, int from_tty)
struct value * struct value *
get_return_value (struct value *function, struct type *value_type) get_return_value (struct value *function, struct type *value_type)
{ {
regcache stop_regs (regcache::readonly, *get_current_regcache ()); regcache *stop_regs = get_current_regcache ()->dup ();
struct gdbarch *gdbarch = stop_regs.arch (); struct gdbarch *gdbarch = stop_regs->arch ();
struct value *value; struct value *value;
value_type = check_typedef (value_type); value_type = check_typedef (value_type);
@@ -1623,7 +1623,7 @@ get_return_value (struct value *function, struct type *value_type)
case RETURN_VALUE_ABI_RETURNS_ADDRESS: case RETURN_VALUE_ABI_RETURNS_ADDRESS:
case RETURN_VALUE_ABI_PRESERVES_ADDRESS: case RETURN_VALUE_ABI_PRESERVES_ADDRESS:
value = allocate_value (value_type); value = allocate_value (value_type);
gdbarch_return_value (gdbarch, function, value_type, &stop_regs, gdbarch_return_value (gdbarch, function, value_type, stop_regs,
value_contents_raw (value), NULL); value_contents_raw (value), NULL);
break; break;
case RETURN_VALUE_STRUCT_CONVENTION: case RETURN_VALUE_STRUCT_CONVENTION:
@@ -1633,6 +1633,7 @@ get_return_value (struct value *function, struct type *value_type)
internal_error (__FILE__, __LINE__, _("bad switch")); internal_error (__FILE__, __LINE__, _("bad switch"));
} }
delete stop_regs;
return value; return value;
} }

View File

@@ -8911,7 +8911,7 @@ save_infcall_suspend_state (void)
inf_state->stop_pc = stop_pc; inf_state->stop_pc = stop_pc;
inf_state->registers = regcache_dup (regcache); inf_state->registers = regcache->dup ();
return inf_state; return inf_state;
} }
@@ -8922,7 +8922,7 @@ void
restore_infcall_suspend_state (struct infcall_suspend_state *inf_state) restore_infcall_suspend_state (struct infcall_suspend_state *inf_state)
{ {
struct thread_info *tp = inferior_thread (); struct thread_info *tp = inferior_thread ();
struct regcache *regcache = get_current_regcache (); target_regcache *regcache = get_current_regcache ();
struct gdbarch *gdbarch = get_regcache_arch (regcache); struct gdbarch *gdbarch = get_regcache_arch (regcache);
tp->suspend = inf_state->thread_suspend; tp->suspend = inf_state->thread_suspend;
@@ -8942,7 +8942,7 @@ restore_infcall_suspend_state (struct infcall_suspend_state *inf_state)
(and perhaps other times). */ (and perhaps other times). */
if (target_has_execution) if (target_has_execution)
/* NB: The register write goes through to the target. */ /* NB: The register write goes through to the target. */
regcache_cpy (regcache, inf_state->registers); inf_state->registers->restore_to (regcache);
discard_infcall_suspend_state (inf_state); discard_infcall_suspend_state (inf_state);
} }
@@ -8963,7 +8963,7 @@ make_cleanup_restore_infcall_suspend_state
void void
discard_infcall_suspend_state (struct infcall_suspend_state *inf_state) discard_infcall_suspend_state (struct infcall_suspend_state *inf_state)
{ {
regcache_xfree (inf_state->registers); delete inf_state->registers;
xfree (inf_state->siginfo_data); xfree (inf_state->siginfo_data);
xfree (inf_state); xfree (inf_state);
} }

View File

@@ -1125,7 +1125,7 @@ jit_unwind_reg_set_impl (struct gdb_unwind_callbacks *cb, int dwarf_regnum,
return; return;
} }
regcache_raw_set_cached_value (priv->regcache, gdb_reg, value->value); priv->regcache->raw_supply (gdb_reg, value->value);
value->free (value); value->free (value);
} }
@@ -1168,7 +1168,7 @@ jit_dealloc_cache (struct frame_info *this_frame, void *cache)
struct jit_unwind_private *priv_data = (struct jit_unwind_private *) cache; struct jit_unwind_private *priv_data = (struct jit_unwind_private *) cache;
gdb_assert (priv_data->regcache != NULL); gdb_assert (priv_data->regcache != NULL);
regcache_xfree (priv_data->regcache); delete priv_data->regcache;
xfree (priv_data); xfree (priv_data);
} }
@@ -1206,7 +1206,7 @@ jit_frame_sniffer (const struct frame_unwind *self,
*cache = XCNEW (struct jit_unwind_private); *cache = XCNEW (struct jit_unwind_private);
priv_data = (struct jit_unwind_private *) *cache; priv_data = (struct jit_unwind_private *) *cache;
priv_data->regcache = regcache_xmalloc (gdbarch, aspace); priv_data->regcache = new regcache (gdbarch, aspace, false);
priv_data->this_frame = this_frame; priv_data->this_frame = this_frame;
callbacks.priv_data = priv_data; callbacks.priv_data = priv_data;

View File

@@ -129,7 +129,7 @@ free_fork (struct fork_info *fp)
if (fp) if (fp)
{ {
if (fp->savedregs) if (fp->savedregs)
regcache_xfree (fp->savedregs); delete fp->savedregs;
if (fp->filepos) if (fp->filepos)
xfree (fp->filepos); xfree (fp->filepos);
xfree (fp); xfree (fp);
@@ -264,7 +264,7 @@ fork_load_infrun_state (struct fork_info *fp)
linux_nat_switch_fork (fp->ptid); linux_nat_switch_fork (fp->ptid);
if (fp->savedregs && fp->clobber_regs) if (fp->savedregs && fp->clobber_regs)
regcache_cpy (get_current_regcache (), fp->savedregs); fp->savedregs->restore_to (get_current_regcache ());
registers_changed (); registers_changed ();
reinit_frame_cache (); reinit_frame_cache ();
@@ -295,9 +295,9 @@ fork_save_infrun_state (struct fork_info *fp, int clobber_regs)
DIR *d; DIR *d;
if (fp->savedregs) if (fp->savedregs)
regcache_xfree (fp->savedregs); delete fp->savedregs;
fp->savedregs = regcache_dup (get_current_regcache ()); fp->savedregs = get_current_regcache ()->dup ();
fp->clobber_regs = clobber_regs; fp->clobber_regs = clobber_regs;
if (clobber_regs) if (clobber_regs)

View File

@@ -1051,7 +1051,7 @@ mi_cmd_data_list_changed_registers (const char *command, char **argv, int argc)
prev_regs = this_regs; prev_regs = this_regs;
this_regs = frame_save_as_regcache (get_selected_frame (NULL)); this_regs = frame_save_as_regcache (get_selected_frame (NULL));
cleanup = make_cleanup_regcache_xfree (prev_regs); cleanup = make_cleanup_regcache_delete (prev_regs);
/* Note that the test for a valid register must include checking the /* Note that the test for a valid register must include checking the
gdbarch_register_name because gdbarch_num_regs may be allocated gdbarch_register_name because gdbarch_num_regs may be allocated

View File

@@ -1364,13 +1364,13 @@ ppu2spu_sniffer (const struct frame_unwind *self,
= FRAME_OBSTACK_CALLOC (1, struct ppu2spu_cache); = FRAME_OBSTACK_CALLOC (1, struct ppu2spu_cache);
struct address_space *aspace = get_frame_address_space (this_frame); struct address_space *aspace = get_frame_address_space (this_frame);
struct regcache *regcache = regcache_xmalloc (data.gdbarch, aspace); regcache *backup = new regcache (data.gdbarch, aspace);
struct cleanup *cleanups = make_cleanup_regcache_xfree (regcache); struct cleanup *cleanups = make_cleanup_regcache_delete (backup);
regcache_save (regcache, ppu2spu_unwind_register, &data); backup->save (ppu2spu_unwind_register, &data);
discard_cleanups (cleanups); discard_cleanups (cleanups);
cache->frame_id = frame_id_build (base, func); cache->frame_id = frame_id_build (base, func);
cache->regcache = regcache; cache->regcache = backup;
*this_prologue_cache = cache; *this_prologue_cache = cache;
return 1; return 1;
} }
@@ -1383,7 +1383,7 @@ static void
ppu2spu_dealloc_cache (struct frame_info *self, void *this_cache) ppu2spu_dealloc_cache (struct frame_info *self, void *this_cache)
{ {
struct ppu2spu_cache *cache = (struct ppu2spu_cache *) this_cache; struct ppu2spu_cache *cache = (struct ppu2spu_cache *) this_cache;
regcache_xfree (cache->regcache); delete cache->regcache;
} }
static const struct frame_unwind ppu2spu_unwind = { static const struct frame_unwind ppu2spu_unwind = {

View File

@@ -189,25 +189,36 @@ regcache_register_size (const struct regcache *regcache, int n)
} }
regcache::regcache (gdbarch *gdbarch, address_space *aspace_, regcache::regcache (gdbarch *gdbarch, address_space *aspace_,
bool readonly_p_) bool readonly_p_, bool allocate_registers)
: m_aspace (aspace_), m_readonly_p (readonly_p_) : m_aspace (aspace_), m_readonly_p (readonly_p_)
{ {
gdb_assert (gdbarch != NULL); gdb_assert (gdbarch != NULL);
m_descr = regcache_descr (gdbarch); m_descr = regcache_descr (gdbarch);
if (m_readonly_p) if (allocate_registers)
{ {
/* Need extra space to store the additional cooked registers for when
the detached regcache is used to save a regcache. */
m_registers = XCNEWVEC (gdb_byte, m_descr->sizeof_cooked_registers); m_registers = XCNEWVEC (gdb_byte, m_descr->sizeof_cooked_registers);
m_register_status = XCNEWVEC (signed char,
m_descr->sizeof_cooked_register_status);
}
else
{
m_registers = XCNEWVEC (gdb_byte, m_descr->sizeof_raw_registers);
m_register_status = XCNEWVEC (signed char,
m_descr->sizeof_raw_register_status);
} }
/* All status' are initialised to REG_UNKNOWN. */
m_register_status = XCNEWVEC (signed char,
m_descr->sizeof_cooked_register_status);
}
target_regcache::target_regcache (gdbarch *gdbarch, address_space *aspace_)
: regcache (gdbarch, aspace_, false, false)
{
/* Only allocate the raw registers - cooked registers are not cached.
Note that the register status is still fully allocated, to allow the
checking of the state of any register. */
m_registers = XCNEWVEC (gdb_byte, m_descr->sizeof_raw_registers);
m_ptid = minus_one_ptid; m_ptid = minus_one_ptid;
/* A target_regcache should never be readonly. */
gdb_assert (!m_readonly_p);
} }
static enum register_status static enum register_status
@@ -218,13 +229,6 @@ do_cooked_read (void *src, int regnum, gdb_byte *buf)
return regcache_cooked_read (regcache, regnum, buf); return regcache_cooked_read (regcache, regnum, buf);
} }
regcache::regcache (readonly_t, const regcache &src)
: regcache (src.arch (), src.aspace (), true)
{
gdb_assert (!src.m_readonly_p);
save (do_cooked_read, (void *) &src);
}
gdbarch * gdbarch *
regcache::arch () const regcache::arch () const
{ {
@@ -241,31 +245,18 @@ regcache_get_ptid (const struct regcache *regcache)
return regcache->ptid (); return regcache->ptid ();
} }
struct regcache *
regcache_xmalloc (struct gdbarch *gdbarch, struct address_space *aspace)
{
return new regcache (gdbarch, aspace);
}
void
regcache_xfree (struct regcache *regcache)
{
if (regcache == NULL)
return;
delete regcache;
}
static void static void
do_regcache_xfree (void *data) do_regcache_delete (void *data)
{ {
regcache_xfree ((struct regcache *) data); if (data == NULL)
return;
delete (regcache *) data;
} }
struct cleanup * struct cleanup *
make_cleanup_regcache_xfree (struct regcache *regcache) make_cleanup_regcache_delete (struct regcache *regcache)
{ {
return make_cleanup (do_regcache_xfree, regcache); return make_cleanup (do_regcache_delete, regcache);
} }
/* Cleanup routines for invalidating a register. */ /* Cleanup routines for invalidating a register. */
@@ -317,23 +308,11 @@ regcache::register_buffer (int regnum) const
} }
void void
regcache_save (struct regcache *regcache, regcache::save (regcache_cooked_read_ftype *cooked_read, void *src)
regcache_cooked_read_ftype *cooked_read, void *src)
{
regcache->save (cooked_read, src);
}
void
regcache::save (regcache_cooked_read_ftype *cooked_read,
void *src)
{ {
struct gdbarch *gdbarch = m_descr->gdbarch; struct gdbarch *gdbarch = m_descr->gdbarch;
int regnum; int regnum;
/* The DST should be `read-only', if it wasn't then the save would
end up trying to write the register values back out to the
target. */
gdb_assert (m_readonly_p);
/* Clear the dest. */ /* Clear the dest. */
memset (m_registers, 0, m_descr->sizeof_cooked_registers); memset (m_registers, 0, m_descr->sizeof_cooked_registers);
memset (m_register_status, 0, m_descr->sizeof_cooked_register_status); memset (m_register_status, 0, m_descr->sizeof_cooked_register_status);
@@ -359,15 +338,14 @@ regcache::save (regcache_cooked_read_ftype *cooked_read,
} }
void void
regcache::restore (struct regcache *src) regcache::restore_to (target_regcache *dst)
{ {
struct gdbarch *gdbarch = m_descr->gdbarch; struct gdbarch *gdbarch = m_descr->gdbarch;
int regnum; int regnum;
gdb_assert (dst != NULL);
gdb_assert (dst->m_descr->gdbarch == m_descr->gdbarch);
gdb_assert (dst != this);
/* The dst had better not be read-only. If it is, the `restore'
doesn't make much sense. */
gdb_assert (!m_readonly_p);
gdb_assert (src->m_readonly_p);
/* Copy over any registers, being careful to only restore those that /* Copy over any registers, being careful to only restore those that
were both saved and need to be restored. The full [0 .. gdbarch_num_regs were both saved and need to be restored. The full [0 .. gdbarch_num_regs
+ gdbarch_num_pseudo_regs) range is checked since some architectures need + gdbarch_num_pseudo_regs) range is checked since some architectures need
@@ -376,27 +354,33 @@ regcache::restore (struct regcache *src)
{ {
if (gdbarch_register_reggroup_p (gdbarch, regnum, restore_reggroup)) if (gdbarch_register_reggroup_p (gdbarch, regnum, restore_reggroup))
{ {
if (src->m_register_status[regnum] == REG_VALID) if (m_register_status[regnum] == REG_VALID)
cooked_write (regnum, src->register_buffer (regnum)); dst->cooked_write (regnum, register_buffer (regnum));
} }
} }
} }
void /* Duplicate detached regcache to a detached regcache. */
regcache_cpy (struct regcache *dst, struct regcache *src) regcache*
regcache::dup (bool readonly_p)
{ {
gdb_assert (src != NULL && dst != NULL); regcache *new_regcache = new regcache (arch (), aspace (), readonly_p);
gdb_assert (src->m_descr->gdbarch == dst->m_descr->gdbarch);
gdb_assert (src != dst);
gdb_assert (src->m_readonly_p && !dst->m_readonly_p);
dst->restore (src); memcpy (new_regcache->m_registers, m_registers,
m_descr->sizeof_cooked_registers);
memcpy (new_regcache->m_register_status, m_register_status,
m_descr->sizeof_cooked_register_status);
return new_regcache;
} }
struct regcache * /* Duplicate a target_regcache to a detached regcache. */
regcache_dup (struct regcache *src) regcache*
target_regcache::dup (bool readonly_p)
{ {
return new regcache (regcache::readonly, *src); regcache *new_regcache = new regcache (arch (), aspace (), readonly_p);
new_regcache->save (do_cooked_read, (void *) this);
return new_regcache;
} }
enum register_status enum register_status
@@ -410,14 +394,17 @@ enum register_status
regcache::get_register_status (int regnum) const regcache::get_register_status (int regnum) const
{ {
gdb_assert (regnum >= 0); gdb_assert (regnum >= 0);
if (m_readonly_p) gdb_assert (regnum < m_descr->nr_cooked_registers);
gdb_assert (regnum < m_descr->nr_cooked_registers);
else
gdb_assert (regnum < m_descr->nr_raw_registers);
return (enum register_status) m_register_status[regnum]; return (enum register_status) m_register_status[regnum];
} }
enum register_status
target_regcache::get_register_status (int regnum) const
{
gdb_assert (regnum < m_descr->nr_raw_registers);
return regcache::get_register_status (regnum);
}
void void
regcache_invalidate (struct regcache *regcache, int regnum) regcache_invalidate (struct regcache *regcache, int regnum)
{ {
@@ -440,25 +427,25 @@ regcache::invalidate (int regnum)
recording if the register values have been changed (eg. by the recording if the register values have been changed (eg. by the
user). Therefore all registers must be written back to the user). Therefore all registers must be written back to the
target when appropriate. */ target when appropriate. */
std::forward_list<regcache *> regcache::current_regcache; std::forward_list<target_regcache *> target_regcache::current_regcache;
struct regcache * target_regcache *
get_thread_arch_aspace_regcache (ptid_t ptid, struct gdbarch *gdbarch, get_thread_arch_aspace_regcache (ptid_t ptid, struct gdbarch *gdbarch,
struct address_space *aspace) struct address_space *aspace)
{ {
for (const auto &regcache : regcache::current_regcache) for (const auto &regcache : target_regcache::current_regcache)
if (ptid_equal (regcache->ptid (), ptid) && regcache->arch () == gdbarch) if (ptid_equal (regcache->ptid (), ptid) && regcache->arch () == gdbarch)
return regcache; return regcache;
regcache *new_regcache = new regcache (gdbarch, aspace, false); target_regcache *new_regcache = new target_regcache (gdbarch, aspace);
regcache::current_regcache.push_front (new_regcache); target_regcache::current_regcache.push_front (new_regcache);
new_regcache->set_ptid (ptid); new_regcache->set_ptid (ptid);
return new_regcache; return new_regcache;
} }
struct regcache * target_regcache *
get_thread_arch_regcache (ptid_t ptid, struct gdbarch *gdbarch) get_thread_arch_regcache (ptid_t ptid, struct gdbarch *gdbarch)
{ {
struct address_space *aspace; struct address_space *aspace;
@@ -479,7 +466,7 @@ get_thread_arch_regcache (ptid_t ptid, struct gdbarch *gdbarch)
static ptid_t current_thread_ptid; static ptid_t current_thread_ptid;
static struct gdbarch *current_thread_arch; static struct gdbarch *current_thread_arch;
struct regcache * target_regcache *
get_thread_regcache (ptid_t ptid) get_thread_regcache (ptid_t ptid)
{ {
if (!current_thread_arch || !ptid_equal (current_thread_ptid, ptid)) if (!current_thread_arch || !ptid_equal (current_thread_ptid, ptid))
@@ -491,7 +478,7 @@ get_thread_regcache (ptid_t ptid)
return get_thread_arch_regcache (ptid, current_thread_arch); return get_thread_arch_regcache (ptid, current_thread_arch);
} }
struct regcache * target_regcache *
get_current_regcache (void) get_current_regcache (void)
{ {
return get_thread_regcache (inferior_ptid); return get_thread_regcache (inferior_ptid);
@@ -502,7 +489,7 @@ get_current_regcache (void)
struct regcache * struct regcache *
get_thread_regcache_for_ptid (ptid_t ptid) get_thread_regcache_for_ptid (ptid_t ptid)
{ {
return get_thread_regcache (ptid); return (struct regcache*) get_thread_regcache (ptid);
} }
/* Observer for the target_changed event. */ /* Observer for the target_changed event. */
@@ -516,9 +503,9 @@ regcache_observer_target_changed (struct target_ops *target)
/* Update global variables old ptids to hold NEW_PTID if they were /* Update global variables old ptids to hold NEW_PTID if they were
holding OLD_PTID. */ holding OLD_PTID. */
void void
regcache::regcache_thread_ptid_changed (ptid_t old_ptid, ptid_t new_ptid) target_regcache::regcache_thread_ptid_changed (ptid_t old_ptid, ptid_t new_ptid)
{ {
for (auto &regcache : regcache::current_regcache) for (auto &regcache : target_regcache::current_regcache)
{ {
if (ptid_equal (regcache->ptid (), old_ptid)) if (ptid_equal (regcache->ptid (), old_ptid))
regcache->set_ptid (new_ptid); regcache->set_ptid (new_ptid);
@@ -539,15 +526,15 @@ regcache::regcache_thread_ptid_changed (ptid_t old_ptid, ptid_t new_ptid)
void void
registers_changed_ptid (ptid_t ptid) registers_changed_ptid (ptid_t ptid)
{ {
for (auto oit = regcache::current_regcache.before_begin (), for (auto oit = target_regcache::current_regcache.before_begin (),
it = std::next (oit); it = std::next (oit);
it != regcache::current_regcache.end (); it != target_regcache::current_regcache.end ();
) )
{ {
if (ptid_match ((*it)->ptid (), ptid)) if (ptid_match ((*it)->ptid (), ptid))
{ {
delete *it; delete *it;
it = regcache::current_regcache.erase_after (oit); it = target_regcache::current_regcache.erase_after (oit);
} }
else else
oit = it++; oit = it++;
@@ -589,16 +576,14 @@ regcache_raw_update (struct regcache *regcache, int regnum)
} }
void void
regcache::raw_update (int regnum) target_regcache::raw_update (int regnum)
{ {
gdb_assert (regnum >= 0 && regnum < m_descr->nr_raw_registers); gdb_assert (regnum >= 0 && regnum < m_descr->nr_raw_registers);
/* Make certain that the register cache is up-to-date with respect /* Make certain that the register cache is up-to-date with respect
to the current thread. This switching shouldn't be necessary to the current thread. */
only there is still only one target side register cache. Sigh!
On the bright side, at least there is a regcache object. */
if (!m_readonly_p && get_register_status (regnum) == REG_UNKNOWN) if (get_register_status (regnum) == REG_UNKNOWN)
{ {
target_fetch_registers (this, regnum); target_fetch_registers (this, regnum);
@@ -618,17 +603,19 @@ regcache_raw_read (struct regcache *regcache, int regnum, gdb_byte *buf)
enum register_status enum register_status
regcache::raw_read (int regnum, gdb_byte *buf) regcache::raw_read (int regnum, gdb_byte *buf)
{
return raw_get_cached_reg (regnum, buf);
}
enum register_status
target_regcache::raw_read (int regnum, gdb_byte *buf)
{ {
gdb_assert (buf != NULL); gdb_assert (buf != NULL);
/* Read register value from the target into the regcache. */
raw_update (regnum); raw_update (regnum);
if (m_register_status[regnum] != REG_VALID) return raw_get_cached_reg (regnum, buf);
memset (buf, 0, m_descr->sizeof_register[regnum]);
else
memcpy (buf, register_buffer (regnum),
m_descr->sizeof_register[regnum]);
return (enum register_status) m_register_status[regnum];
} }
enum register_status enum register_status
@@ -719,8 +706,7 @@ regcache::cooked_read (int regnum, gdb_byte *buf)
gdb_assert (regnum < m_descr->nr_cooked_registers); gdb_assert (regnum < m_descr->nr_cooked_registers);
if (regnum < m_descr->nr_raw_registers) if (regnum < m_descr->nr_raw_registers)
return raw_read (regnum, buf); return raw_read (regnum, buf);
else if (m_readonly_p else if (m_register_status[regnum] != REG_UNKNOWN)
&& m_register_status[regnum] != REG_UNKNOWN)
{ {
/* Read-only register cache, perhaps the cooked value was /* Read-only register cache, perhaps the cooked value was
cached? */ cached? */
@@ -772,7 +758,7 @@ regcache::cooked_read_value (int regnum)
gdb_assert (regnum < m_descr->nr_cooked_registers); gdb_assert (regnum < m_descr->nr_cooked_registers);
if (regnum < m_descr->nr_raw_registers if (regnum < m_descr->nr_raw_registers
|| (m_readonly_p && m_register_status[regnum] != REG_UNKNOWN) || m_register_status[regnum] != REG_UNKNOWN
|| !gdbarch_pseudo_register_read_value_p (m_descr->gdbarch)) || !gdbarch_pseudo_register_read_value_p (m_descr->gdbarch))
{ {
struct value *result; struct value *result;
@@ -859,21 +845,42 @@ regcache_cooked_write_unsigned (struct regcache *regcache, int regnum,
regcache->cooked_write (regnum, val); regcache->cooked_write (regnum, val);
} }
/* See regcache.h. */
void void
regcache_raw_set_cached_value (struct regcache *regcache, int regnum, regcache::raw_set_cached_reg (int regnum, const gdb_byte *buf)
const gdb_byte *buf)
{ {
regcache->raw_set_cached_value (regnum, buf); gdb_assert (regnum >= 0 && regnum < m_descr->nr_raw_registers);
gdb_assert (!m_readonly_p);
if (buf)
{
memcpy (register_buffer (regnum), buf, m_descr->sizeof_register[regnum]);
m_register_status[regnum] = REG_VALID;
}
else
{
/* This memset not strictly necessary, but better than garbage
in case the register value manages to escape somewhere (due
to a bug, no less). */
memset (register_buffer (regnum), 0, m_descr->sizeof_register[regnum]);
m_register_status[regnum] = REG_UNAVAILABLE;
}
gdb_assert (regnum >= 0 && regnum < m_descr->nr_raw_registers);
} }
void enum register_status
regcache::raw_set_cached_value (int regnum, const gdb_byte *buf) regcache::raw_get_cached_reg (int regnum, gdb_byte *buf) const
{ {
memcpy (register_buffer (regnum), buf, gdb_assert (regnum >= 0 && regnum < m_descr->nr_raw_registers);
m_descr->sizeof_register[regnum]); gdb_assert (buf != NULL);
m_register_status[regnum] = REG_VALID;
if (m_register_status[regnum] != REG_VALID)
memset (buf, 0, m_descr->sizeof_register[regnum]);
else
memcpy (buf, register_buffer (regnum),
m_descr->sizeof_register[regnum]);
return (enum register_status) m_register_status[regnum];
} }
void void
@@ -886,12 +893,24 @@ regcache_raw_write (struct regcache *regcache, int regnum,
void void
regcache::raw_write (int regnum, const gdb_byte *buf) regcache::raw_write (int regnum, const gdb_byte *buf)
{
gdb_assert (regnum >= 0 && regnum < m_descr->nr_raw_registers);
/* On the sparc, writing %g0 is a no-op, so we don't even want to
change the registers array if something writes to this register. */
if (gdbarch_cannot_store_register (arch (), regnum))
return;
raw_set_cached_reg (regnum, buf);
}
void
target_regcache::raw_write (int regnum, const gdb_byte *buf)
{ {
struct cleanup *old_chain; struct cleanup *old_chain;
gdb_assert (buf != NULL); gdb_assert (buf != NULL);
gdb_assert (regnum >= 0 && regnum < m_descr->nr_raw_registers); gdb_assert (regnum >= 0 && regnum < m_descr->nr_raw_registers);
gdb_assert (!m_readonly_p);
/* On the sparc, writing %g0 is a no-op, so we don't even want to /* On the sparc, writing %g0 is a no-op, so we don't even want to
change the registers array if something writes to this register. */ change the registers array if something writes to this register. */
@@ -906,7 +925,7 @@ regcache::raw_write (int regnum, const gdb_byte *buf)
return; return;
target_prepare_to_store (this); target_prepare_to_store (this);
raw_set_cached_value (regnum, buf); raw_set_cached_reg (regnum, buf);
/* Register a cleanup function for invalidating the register after it is /* Register a cleanup function for invalidating the register after it is
written, in case of a failure. */ written, in case of a failure. */
@@ -1065,28 +1084,7 @@ regcache_raw_supply (struct regcache *regcache, int regnum, const void *buf)
void void
regcache::raw_supply (int regnum, const void *buf) regcache::raw_supply (int regnum, const void *buf)
{ {
void *regbuf; raw_set_cached_reg (regnum, (const gdb_byte*) buf);
size_t size;
gdb_assert (regnum >= 0 && regnum < m_descr->nr_raw_registers);
gdb_assert (!m_readonly_p);
regbuf = register_buffer (regnum);
size = m_descr->sizeof_register[regnum];
if (buf)
{
memcpy (regbuf, buf, size);
m_register_status[regnum] = REG_VALID;
}
else
{
/* This memset not strictly necessary, but better than garbage
in case the register value manages to escape somewhere (due
to a bug, no less). */
memset (regbuf, 0, size);
m_register_status[regnum] = REG_UNAVAILABLE;
}
} }
/* Supply register REGNUM to REGCACHE. Value to supply is an integer stored at /* Supply register REGNUM to REGCACHE. Value to supply is an integer stored at
@@ -1146,15 +1144,7 @@ regcache_raw_collect (const struct regcache *regcache, int regnum, void *buf)
void void
regcache::raw_collect (int regnum, void *buf) const regcache::raw_collect (int regnum, void *buf) const
{ {
const void *regbuf; raw_get_cached_reg (regnum, (gdb_byte*) buf);
size_t size;
gdb_assert (buf != NULL);
gdb_assert (regnum >= 0 && regnum < m_descr->nr_raw_registers);
regbuf = register_buffer (regnum);
size = m_descr->sizeof_register[regnum];
memcpy (buf, regbuf, size);
} }
/* Transfer a single or all registers belonging to a certain register /* Transfer a single or all registers belonging to a certain register
@@ -1668,7 +1658,7 @@ maintenance_print_remote_registers (char *args, int from_tty)
namespace selftests { namespace selftests {
class regcache_access : public regcache class regcache_access : public target_regcache
{ {
public: public:
@@ -1677,8 +1667,8 @@ public:
static size_t static size_t
current_regcache_size () current_regcache_size ()
{ {
return std::distance (regcache::current_regcache.begin (), return std::distance (target_regcache::current_regcache.begin (),
regcache::current_regcache.end ()); target_regcache::current_regcache.end ());
} }
}; };
@@ -1692,7 +1682,7 @@ current_regcache_test (void)
/* Get regcache from ptid1, a new regcache is added to /* Get regcache from ptid1, a new regcache is added to
current_regcache. */ current_regcache. */
regcache *regcache = get_thread_arch_aspace_regcache (ptid1, target_regcache *regcache = get_thread_arch_aspace_regcache (ptid1,
target_gdbarch (), target_gdbarch (),
NULL); NULL);
@@ -1745,7 +1735,8 @@ _initialize_regcache (void)
= gdbarch_data_register_post_init (init_regcache_descr); = gdbarch_data_register_post_init (init_regcache_descr);
observer_attach_target_changed (regcache_observer_target_changed); observer_attach_target_changed (regcache_observer_target_changed);
observer_attach_thread_ptid_changed (regcache::regcache_thread_ptid_changed); observer_attach_thread_ptid_changed
(target_regcache::regcache_thread_ptid_changed);
add_com ("flushregs", class_maintenance, reg_flush_command, add_com ("flushregs", class_maintenance, reg_flush_command,
_("Force gdb to flush its register cache (maintainer command)")); _("Force gdb to flush its register cache (maintainer command)"));

View File

@@ -24,21 +24,19 @@
#include <forward_list> #include <forward_list>
struct regcache; struct regcache;
class target_regcache;
struct regset; struct regset;
struct gdbarch; struct gdbarch;
struct address_space; struct address_space;
extern struct regcache *get_current_regcache (void); extern target_regcache *get_current_regcache (void);
extern struct regcache *get_thread_regcache (ptid_t ptid); extern target_regcache *get_thread_regcache (ptid_t ptid);
extern struct regcache *get_thread_arch_regcache (ptid_t, struct gdbarch *); extern target_regcache *get_thread_arch_regcache (ptid_t, struct gdbarch *);
extern struct regcache *get_thread_arch_aspace_regcache (ptid_t, extern target_regcache *get_thread_arch_aspace_regcache (ptid_t,
struct gdbarch *, struct gdbarch *,
struct address_space *); struct address_space *);
void regcache_xfree (struct regcache *regcache); struct cleanup *make_cleanup_regcache_delete (regcache *regcache);
struct cleanup *make_cleanup_regcache_xfree (struct regcache *regcache);
struct regcache *regcache_xmalloc (struct gdbarch *gdbarch,
struct address_space *aspace);
/* Return REGCACHE's ptid. */ /* Return REGCACHE's ptid. */
@@ -81,14 +79,6 @@ extern void regcache_raw_write_unsigned (struct regcache *regcache,
extern LONGEST regcache_raw_get_signed (struct regcache *regcache, extern LONGEST regcache_raw_get_signed (struct regcache *regcache,
int regnum); int regnum);
/* Set a raw register's value in the regcache's buffer. Unlike
regcache_raw_write, this is not write-through. The intention is
allowing to change the buffer contents of a read-only regcache
allocated with regcache_xmalloc. */
extern void regcache_raw_set_cached_value
(struct regcache *regcache, int regnum, const gdb_byte *buf);
/* Partial transfer of raw registers. These perform read, modify, /* Partial transfer of raw registers. These perform read, modify,
write style operations. The read variant returns the status of the write style operations. The read variant returns the status of the
register. */ register. */
@@ -211,20 +201,10 @@ extern struct type *register_type (struct gdbarch *gdbarch, int regnum);
extern int register_size (struct gdbarch *gdbarch, int regnum); extern int register_size (struct gdbarch *gdbarch, int regnum);
/* Save/restore a register cache. The set of registers saved /
restored into the DST regcache determined by the save_reggroup /
restore_reggroup respectively. COOKED_READ returns zero iff the
register's value can't be returned. */
typedef enum register_status (regcache_cooked_read_ftype) (void *src, typedef enum register_status (regcache_cooked_read_ftype) (void *src,
int regnum, int regnum,
gdb_byte *buf); gdb_byte *buf);
extern void regcache_save (struct regcache *dst,
regcache_cooked_read_ftype *cooked_read,
void *cooked_read_context);
enum regcache_dump_what enum regcache_dump_what
{ {
regcache_dump_none, regcache_dump_raw, regcache_dump_none, regcache_dump_raw,
@@ -240,30 +220,20 @@ typedef struct cached_reg
gdb_byte *data; gdb_byte *data;
} cached_reg_t; } cached_reg_t;
/* The register cache for storing raw register values. */
/* A register cache. This is not connected to a target - reads and writes will
not be passed through to a target and ptid is unset. */
class regcache class regcache
{ {
public: public:
regcache (gdbarch *gdbarch, address_space *aspace_) regcache (gdbarch *gdbarch, address_space *aspace_, bool readonly_p_ = true,
: regcache (gdbarch, aspace_, true) bool allocate_registers = true);
{}
struct readonly_t {};
static constexpr readonly_t readonly {};
/* Create a readonly regcache from a non-readonly regcache. */
regcache (readonly_t, const regcache &src);
regcache (const regcache &) = delete; regcache (const regcache &) = delete;
void operator= (const regcache &) = delete; void operator= (const regcache &) = delete;
/* class regcache is only extended in unit test, so only mark it virtual ~regcache ()
virtual when selftest is enabled. */
#if GDB_SELF_TEST
virtual
#endif
~regcache ()
{ {
xfree (m_registers); xfree (m_registers);
xfree (m_register_status); xfree (m_register_status);
@@ -276,19 +246,22 @@ public:
return m_aspace; return m_aspace;
} }
/* Duplicate self into a new regcache. */
virtual regcache* dup (bool readonly_p = true);
/* Copy the register contents from a target_regcache to self.
All cooked registers are read and cached. */
void save (regcache_cooked_read_ftype *cooked_read, void *src); void save (regcache_cooked_read_ftype *cooked_read, void *src);
/* Copy register contents to a target_regcache. All cached cooked registers
are also restored. */
void restore_to (target_regcache *dst);
enum register_status cooked_read (int regnum, gdb_byte *buf); enum register_status cooked_read (int regnum, gdb_byte *buf);
void cooked_write (int regnum, const gdb_byte *buf); void cooked_write (int regnum, const gdb_byte *buf);
enum register_status raw_read (int regnum, gdb_byte *buf); virtual enum register_status raw_read (int regnum, gdb_byte *buf);
virtual void raw_write (int regnum, const gdb_byte *buf);
/* class regcache is only extended in unit test, so only mark it
virtual when selftest is enabled. */
#if GDB_SELF_TEST
virtual
#endif
void raw_write (int regnum, const gdb_byte *buf);
template<typename T, typename = RequireLongest<T>> template<typename T, typename = RequireLongest<T>>
enum register_status raw_read (int regnum, T *val); enum register_status raw_read (int regnum, T *val);
@@ -304,7 +277,7 @@ public:
template<typename T, typename = RequireLongest<T>> template<typename T, typename = RequireLongest<T>>
void cooked_write (int regnum, T val); void cooked_write (int regnum, T val);
void raw_update (int regnum); virtual void raw_update (int regnum) {}
void raw_collect (int regnum, void *buf) const; void raw_collect (int regnum, void *buf) const;
@@ -318,9 +291,7 @@ public:
void raw_supply_zeroed (int regnum); void raw_supply_zeroed (int regnum);
enum register_status get_register_status (int regnum) const; virtual enum register_status get_register_status (int regnum) const;
void raw_set_cached_value (int regnum, const gdb_byte *buf);
void invalidate (int regnum); void invalidate (int regnum);
@@ -344,40 +315,23 @@ public:
void dump (ui_file *file, enum regcache_dump_what what_to_dump); void dump (ui_file *file, enum regcache_dump_what what_to_dump);
ptid_t ptid () const virtual ptid_t ptid () const
{ {
return m_ptid; /* Ptid of a non-target regcache is always -1. */
} return (ptid_t) -1;
void set_ptid (const ptid_t ptid)
{
this->m_ptid = ptid;
} }
/* Dump the contents of a register from the register cache to the target /* Dump the contents of a register from the register cache to the target
debug. */ debug. */
void debug_print_register (const char *func, int regno); void debug_print_register (const char *func, int regno);
static void regcache_thread_ptid_changed (ptid_t old_ptid, ptid_t new_ptid);
protected: protected:
regcache (gdbarch *gdbarch, address_space *aspace_, bool readonly_p_);
static std::forward_list<regcache *> current_regcache;
private:
gdb_byte *register_buffer (int regnum) const; gdb_byte *register_buffer (int regnum) const;
void restore (struct regcache *src); /* Get/Set the cached contents of the regcache. */
void raw_set_cached_reg (int regnum, const gdb_byte *buf);
enum register_status xfer_part (int regnum, int offset, int len, void *in, enum register_status raw_get_cached_reg (int regnum, gdb_byte *buf) const;
const void *out,
decltype (regcache_raw_read) read,
decltype (regcache_raw_write) write);
void transfer_regset (const struct regset *regset,
struct regcache *out_regcache,
int regnum, const void *in_buf,
void *out_buf, size_t size) const;
struct regcache_descr *m_descr; struct regcache_descr *m_descr;
@@ -389,37 +343,86 @@ private:
full [0 .. gdbarch_num_regs + gdbarch_num_pseudo_regs) while a read/write full [0 .. gdbarch_num_regs + gdbarch_num_pseudo_regs) while a read/write
register cache can only hold [0 .. gdbarch_num_regs). */ register cache can only hold [0 .. gdbarch_num_regs). */
gdb_byte *m_registers; gdb_byte *m_registers;
/* Register cache status. */ /* Register cache status. */
signed char *m_register_status; signed char *m_register_status;
/* Is this a read-only cache? A read-only cache is used for saving
the target's register state (e.g, across an inferior function /* A read-only cache can not change it's register contents, except from
call or just before forcing a function return). A read-only an target_regcache via the save () method.
cache can only be updated via the methods regcache_dup() and A target_regcache cache can never be read-only. */
regcache_cpy(). The actual contents are determined by the
reggroup_save and reggroup_restore methods. */
bool m_readonly_p; bool m_readonly_p;
/* If this is a read-write cache, which thread's registers is
it connected to? */
ptid_t m_ptid;
friend struct regcache * private:
get_thread_arch_aspace_regcache (ptid_t ptid, struct gdbarch *gdbarch,
struct address_space *aspace);
friend void enum register_status xfer_part (int regnum, int offset, int len, void *in,
registers_changed_ptid (ptid_t ptid); const void *out,
decltype (regcache_raw_read) read,
decltype (regcache_raw_write) write);
void transfer_regset (const struct regset *regset,
struct regcache *out_regcache,
int regnum, const void *in_buf,
void *out_buf, size_t size) const;
private:
friend void
regcache_cpy (struct regcache *dst, struct regcache *src);
}; };
/* Duplicate the contents of a register cache to a read-only register
cache. The operation is pass-through. */
extern struct regcache *regcache_dup (struct regcache *regcache);
/* Writes to DEST will go through to the target. SRC is a read-only /* A register cache attached to a target. Reads and writes of register values
register cache. */ will be passed through to the target and ptid can be set. */
extern void regcache_cpy (struct regcache *dest, struct regcache *src);
class target_regcache : public regcache
{
public:
target_regcache (const target_regcache &) = delete;
void operator= (const target_regcache &) = delete;
/* Cannot be called on a target_regcache. */
void save (regcache_cooked_read_ftype *cooked_read, void *src) = delete;
void restore_to (target_regcache *dst) = delete;
/* Duplicate self into a new regcache. Result is not a target_regcache. */
regcache* dup (bool readonly_p = true);
/* Overridden regcache methods. These versions will pass the read/write
through to the target. */
enum register_status raw_read (int regnum, gdb_byte *buf);
virtual void raw_write (int regnum, const gdb_byte *buf);
void raw_update (int regnum);
enum register_status get_register_status (int regnum) const;
ptid_t ptid () const
{
return m_ptid;
}
static void regcache_thread_ptid_changed (ptid_t old_ptid,
ptid_t new_ptid);
protected:
/* Constructor is only called via get_thread_arch_aspace_regcache. */
target_regcache (gdbarch *gdbarch, address_space *aspace_);
void set_ptid (const ptid_t ptid)
{
this->m_ptid = ptid;
}
static std::forward_list<target_regcache *> current_regcache;
private:
/* The thread the cache is connected to, or -1 if not attached. */
ptid_t m_ptid;
friend struct target_regcache * get_thread_arch_aspace_regcache
(ptid_t ptid, struct gdbarch *gdbarch, struct address_space *aspace);
friend void registers_changed_ptid (ptid_t ptid);
};
extern void registers_changed (void); extern void registers_changed (void);
extern void registers_changed_ptid (ptid_t); extern void registers_changed_ptid (ptid_t);

View File

@@ -1275,7 +1275,7 @@ spu2ppu_sniffer (const struct frame_unwind *self,
{ {
struct regcache *regcache; struct regcache *regcache;
regcache = get_thread_arch_regcache (inferior_ptid, target_gdbarch ()); regcache = get_thread_arch_regcache (inferior_ptid, target_gdbarch ());
cache->regcache = regcache_dup (regcache); cache->regcache = regcache->dup ();
*this_prologue_cache = cache; *this_prologue_cache = cache;
return 1; return 1;
} }
@@ -1288,7 +1288,7 @@ static void
spu2ppu_dealloc_cache (struct frame_info *self, void *this_cache) spu2ppu_dealloc_cache (struct frame_info *self, void *this_cache)
{ {
struct spu2ppu_cache *cache = (struct spu2ppu_cache *) this_cache; struct spu2ppu_cache *cache = (struct spu2ppu_cache *) this_cache;
regcache_xfree (cache->regcache); delete cache->regcache;
} }
static const struct frame_unwind spu2ppu_unwind = { static const struct frame_unwind spu2ppu_unwind = {