forked from Imagelibrary/binutils-gdb
Compare commits
7 Commits
gdb-10-bra
...
users/alah
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8cc29a6ace | ||
|
|
a20c2452a4 | ||
|
|
4ac8135dd8 | ||
|
|
e9a5485336 | ||
|
|
5c7af491c5 | ||
|
|
c14731f7e9 | ||
|
|
15587be5bd |
16
gdb/frame.c
16
gdb/frame.c
@@ -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
|
||||||
|
|||||||
@@ -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);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -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;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -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);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -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;
|
||||||
|
|||||||
@@ -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)
|
||||||
|
|||||||
@@ -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
|
||||||
|
|||||||
@@ -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 = {
|
||||||
|
|||||||
287
gdb/regcache.c
287
gdb/regcache.c
@@ -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 ®cache : regcache::current_regcache)
|
for (const auto ®cache : 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 ®cache : regcache::current_regcache)
|
for (auto ®cache : 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)"));
|
||||||
|
|||||||
201
gdb/regcache.h
201
gdb/regcache.h
@@ -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);
|
||||||
|
|||||||
@@ -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 = {
|
||||||
|
|||||||
Reference in New Issue
Block a user