[PATCH 13/15] No longer create readonly regcache

Yao Qi
2017-12-01T10:48:40Z

Nowadays, we create a readonly regcache in get_return_value, and pass it
to gdbarch_return_value to get the return value. In theory, we can pass a
regcache_readonly instance and get the return value, because we don't need
to modify the regcache. Unfortunately, gdbarch_return_value is designed
to multiplex regcache, according to READBUF and WRITEBUF.

# If READBUF is not NULL, extract the return value and save it in this
# buffer.
#
# If WRITEBUF is not NULL, it contains a return value which will be
# stored into the appropriate register.

In fact, gdbarch_return_value should be split to three functions, 1) only
return return_value_convention, 2) pass regcache_readonly and readbuf, 3)
pass regcache and writebuf. These changes are out of the scope of this
patch series, so I pass regcache to gdbarch_return_value even for read,
and trust each gdbarch backend doesn't modify regcache.

gdb:

2017-11-02 Yao Qi <yao.qi@linaro.org>

* infcmd.c (get_return_value): Let stop_regs point to
get_current_regcache.
* regcache.c (regcache::regcache): Remove.
(register_dump_reg_buffer): New class.
(regcache_print): Adjust.
* regcache.h (regcache): Remove constructors.
---
gdb/infcmd.c | 6 ++---
gdb/regcache.c | 71 +++++++++++++++++++++++++++++++++++++++++++++-------------
gdb/regcache.h | 10 ---------
3 files changed, 58 insertions(+), 29 deletions(-)

diff --git a/gdb/infcmd.c b/gdb/infcmd.c
index 9cee174..ee60ce9 100644
--- a/gdb/infcmd.c
+++ b/gdb/infcmd.c
@@ -1627,8 +1627,8 @@ advance_command (const char *arg, int from_tty)
struct value *
get_return_value (struct value *function, struct type *value_type)
{
- regcache stop_regs (regcache::readonly, *get_current_regcache ());
- struct gdbarch *gdbarch = stop_regs.arch ();
+ regcache *stop_regs = get_current_regcache ();
+ struct gdbarch *gdbarch = stop_regs->arch ();
struct value *value;

value_type = check_typedef (value_type);
@@ -1648,7 +1648,7 @@ get_return_value (struct value *function, struct type *value_type)
case RETURN_VALUE_ABI_RETURNS_ADDRESS:
case RETURN_VALUE_ABI_PRESERVES_ADDRESS:
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);
break;
case RETURN_VALUE_STRUCT_CONVENTION:
diff --git a/gdb/regcache.c b/gdb/regcache.c
index 9195bff..4286f36 100644
--- a/gdb/regcache.c
+++ b/gdb/regcache.c
@@ -219,13 +219,6 @@ do_cooked_read (void *src, int regnum, gdb_byte *buf)
return regcache_cooked_read (regcache, regnum, buf);
}

-regcache::regcache (readonly_t, const regcache &src)
- : regcache (src.arch (), nullptr, true)
-{
- gdb_assert (!src.m_readonly_p);
- save (do_cooked_read, (void *) &src);
-}
-
regcache_readonly::regcache_readonly (const regcache &src)
: regcache_readonly (src.arch (), do_cooked_read, (void *) &src)
{
@@ -1512,6 +1505,55 @@ private:
const bool m_dump_pseudo;
};

+/* Dump from reg_buffer, used when there is no thread or
+ registers. */
+
+class register_dump_reg_buffer : public register_dump, reg_buffer
+{
+public:
+ register_dump_reg_buffer (gdbarch *gdbarch, bool dump_pseudo)
+ : register_dump (gdbarch), reg_buffer (gdbarch, dump_pseudo)
+ {
+ }
+
+protected:
+ void dump_reg (ui_file *file, int regnum) override
+ {
+ if (regnum < 0)
+ {
+ if (m_has_pseudo)
+ fprintf_unfiltered (file, "Cooked value");
+ else
+ fprintf_unfiltered (file, "Raw value");
+ }
+ else
+ {
+ if (regnum < gdbarch_num_regs (m_gdbarch) || m_has_pseudo)
+ {
+ auto size = register_size (m_gdbarch, regnum);
+
+ if (size == 0)
+ return;
+
+ auto status = get_register_status (regnum);
+
+ gdb_assert (status != REG_VALID);
+
+ if (status == REG_UNKNOWN)
+ fprintf_unfiltered (file, "<invalid>");
+ else
+ fprintf_unfiltered (file, "<unavailable>");
+ }
+ else
+ {
+ /* Just print "<cooked>" for pseudo register when
+ regcache_dump_raw. */
+ fprintf_unfiltered (file, "<cooked>");
+ }
+ }
+ }
+};
+
/* For "maint print registers". */

class register_dump_none : public register_dump
@@ -1633,22 +1675,19 @@ regcache_print (const char *args, enum regcache_dump_what what_to_dump)
case regcache_dump_raw:
case regcache_dump_cooked:
{
- regcache *reg;
+ auto dump_pseudo = (what_to_dump == regcache_dump_cooked);

if (target_has_registers)
- reg = get_current_regcache ();
+ dump.reset (new register_dump_regcache (get_current_regcache (),
+ dump_pseudo));
else
{
/* For the benefit of "maint print registers" & co when
debugging an executable, allow dumping a regcache even when
there is no thread selected / no registers. */
- reg = new regcache (target_gdbarch ());
- regs.reset (reg);
+ dump.reset (new register_dump_reg_buffer (target_gdbarch (),
+ dump_pseudo));
}
-
- auto dump_pseudo = (what_to_dump == regcache_dump_cooked);
-
- dump.reset (new register_dump_regcache (reg, dump_pseudo));
}
break;
}
@@ -1937,7 +1976,7 @@ cooked_read_test (struct gdbarch *gdbarch)
mock_target.reset ();
}

- regcache readonly (regcache::readonly, readwrite);
+ regcache_readonly readonly (readwrite);

/* GDB may go to target layer to fetch all registers and memory for
readonly regcache. */
diff --git a/gdb/regcache.h b/gdb/regcache.h
index 5c0850d..fc645c4 100644
--- a/gdb/regcache.h
+++ b/gdb/regcache.h
@@ -305,16 +305,6 @@ class regcache_readonly;
class regcache : public reg_buffer_rw
{
public:
- regcache (gdbarch *gdbarch)
- : regcache (gdbarch, nullptr, true)
- {}
-
- struct readonly_t {};
- static constexpr readonly_t readonly {};
-
- /* Create a readonly regcache from a non-readonly regcache. */
- regcache (readonly_t, const regcache &src);
-
DISABLE_COPY_AND_ASSIGN (regcache);

/* Return REGCACHE's address space. */
--
1.9.1