From c61a7b56ecdc1a0480fc62800835ab9a539d4469 Mon Sep 17 00:00:00 2001 From: Thiago Jung Bauermann Date: Fri, 4 Oct 2024 23:48:11 -0300 Subject: [PATCH] GDB: Add concept of variable-size registers to the regcache The contents of variable-size registers are placed in a separate buffer, because their size will only be known a while after the buffer is created but some fixed-size registers (particularly the program counter) need to be stored or fetched before then. This is also why the state related to variable-size registers is lazily initialised at the moment it's first needed (by calling the initialize_variable_size_registers () method). Simon suggested placing the variable-size registers at the end of the existing contents buffer to avoid having to use a separate one. I will experiment with that idea and see if it simplifies the code. The regcache now also stores the resolved type and size of the variable-size registers. Some places needed to be changed from calling the register_size () function to calling the register_size () method instead, because they may call them for variable-size registers. The frame-unwinding code doesn't have a regcache readily available, so the register_size () function is changed to optionally accept a frame_info_ptr which it uses to create a readonly_detached_regcache. When debugging a remote target, if the regcache has variable-size registers the maximum packet size may change with new values of expedited registers. Therefore, update the maximum packet size when expedited registers are supplied, or load-early registers are fetched. Finally, there are FIXMEs related to the const_casts needed to remove the const from the "this" pointer when calling reg_buffer::initialize_variable_size_registers (). I'm still thinking about what to do with them. I tried the simple solution of changing the calling methods to be non-const, but the change escalates quickly. --- gdb/aarch64-tdep.c | 9 +- gdb/eval.c | 13 +-- gdb/findvar.c | 5 +- gdb/frame.c | 45 +++++--- gdb/record-full.c | 3 +- gdb/regcache.c | 248 ++++++++++++++++++++++++++++++++++++++------- gdb/regcache.h | 39 ++++++- gdb/remote.c | 55 ++++++++-- gdb/value.c | 16 ++- 9 files changed, 350 insertions(+), 83 deletions(-) diff --git a/gdb/aarch64-tdep.c b/gdb/aarch64-tdep.c index bf5b5d3bcf6..19d9f1d745c 100644 --- a/gdb/aarch64-tdep.c +++ b/gdb/aarch64-tdep.c @@ -1728,7 +1728,7 @@ pass_in_v (struct gdbarch *gdbarch, { int regnum = AARCH64_V0_REGNUM + info->nsrn; /* Enough space for a full vector register. */ - gdb::byte_vector reg (register_size (gdbarch, regnum), 0); + gdb::byte_vector reg (regcache->register_size (regnum), 0); gdb_assert (len <= reg.size ()); info->argnum++; @@ -2543,7 +2543,7 @@ aarch64_extract_return_value (struct type *type, struct regcache *regs, { int regno = AARCH64_V0_REGNUM + i; /* Enough space for a full vector register. */ - gdb::byte_vector buf (register_size (gdbarch, regno)); + gdb::byte_vector buf (regs->register_size (regno)); gdb_assert (len <= buf.size ()); aarch64_debug_printf @@ -2657,7 +2657,7 @@ aarch64_store_return_value (struct type *type, struct regcache *regs, { int regno = AARCH64_V0_REGNUM + i; /* Enough space for a full vector register. */ - gdb::byte_vector tmpbuf (register_size (gdbarch, regno)); + gdb::byte_vector tmpbuf (regs->register_size (regno)); gdb_assert (len <= tmpbuf.size ()); aarch64_debug_printf @@ -3311,7 +3311,8 @@ aarch64_pseudo_write_1 (gdbarch *gdbarch, const frame_info_ptr &next_frame, various 'scalar' pseudo registers to behavior like architectural writes, register width bytes are written the remainder are set to zero. */ - gdb::byte_vector raw_buf (register_size (gdbarch, raw_regnum), 0); + int raw_reg_size = register_size (gdbarch, raw_regnum, &next_frame); + gdb::byte_vector raw_buf (raw_reg_size, 0); static_assert (AARCH64_V0_REGNUM == AARCH64_SVE_Z0_REGNUM); gdb::array_view raw_view (raw_buf); diff --git a/gdb/eval.c b/gdb/eval.c index 95d2532af8f..984515a12c1 100644 --- a/gdb/eval.c +++ b/gdb/eval.c @@ -1137,13 +1137,14 @@ eval_op_register (struct type *expect_type, struct expression *exp, if (regno == -1) error (_("Register $%s not available."), name); - /* In EVAL_AVOID_SIDE_EFFECTS mode, we only need to return - a value with the appropriate register type. Unfortunately, - we don't have easy access to the type of user registers. - So for these registers, we fetch the register value regardless - of the evaluation mode. */ + /* In EVAL_AVOID_SIDE_EFFECTS mode, we only need to return a value with + the appropriate register type. Unfortunately, we don't have easy + access to the type of user registers and variable-size registers. So + for these registers, we fetch the register value regardless of the + evaluation mode. */ if (noside == EVAL_AVOID_SIDE_EFFECTS - && regno < gdbarch_num_cooked_regs (exp->gdbarch)) + && regno < gdbarch_num_cooked_regs (exp->gdbarch) + && !register_is_variable_size (exp->gdbarch, regno)) val = value::zero (register_type (exp->gdbarch, regno), not_lval); else val = value_of_register diff --git a/gdb/findvar.c b/gdb/findvar.c index 29389313f94..94da6ded6e2 100644 --- a/gdb/findvar.c +++ b/gdb/findvar.c @@ -580,11 +580,12 @@ read_frame_register_value (value *value) LONGEST reg_offset = value->offset (); int regnum = value->regnum (); int len = type_length_units (check_typedef (value->type ())); + int reg_size = register_size (gdbarch, regnum, &next_frame); /* Skip registers wholly inside of REG_OFFSET. */ - while (reg_offset >= register_size (gdbarch, regnum)) + while (reg_offset >= reg_size) { - reg_offset -= register_size (gdbarch, regnum); + reg_offset -= reg_size; regnum++; } diff --git a/gdb/frame.c b/gdb/frame.c index fe5336f2401..95151da6120 100644 --- a/gdb/frame.c +++ b/gdb/frame.c @@ -1318,12 +1318,24 @@ frame_unwind_register_value (const frame_info_ptr &next_frame, int regnum) gdb_printf (&debug_file, " lazy"); else if (value->entirely_available ()) { - int i; + int i, reg_size; gdb::array_view buf = value->contents (); gdb_printf (&debug_file, " bytes="); gdb_printf (&debug_file, "["); - for (i = 0; i < register_size (gdbarch, regnum); i++) + + if (register_is_variable_size (gdbarch, regnum)) + /* To get the size of a variable-size register, we need to + call frame_save_as_regcache () so that we can call + regcache::register_size (). Unfortunatlly the former + ends up calling this function so we enter into an + infinite recursion. So just assume that the value has + the correct size. */ + reg_size = buf.size (); + else + reg_size = register_size (gdbarch, regnum); + + for (i = 0; i < reg_size; i++) gdb_printf (&debug_file, "%02x", buf[i]); gdb_printf (&debug_file, "]"); } @@ -1442,7 +1454,7 @@ put_frame_register (const frame_info_ptr &next_frame, int regnum, int unavail; enum lval_type lval; CORE_ADDR addr; - int size = register_size (gdbarch, regnum); + int size = register_size (gdbarch, regnum, &next_frame); gdb_assert (buf.size () == size); @@ -1458,8 +1470,9 @@ put_frame_register (const frame_info_ptr &next_frame, int regnum, break; } case lval_register: - /* Not sure if that's always true... but we have a problem if not. */ - gdb_assert (size == register_size (gdbarch, realnum)); + if (regnum != realnum) + /* Not sure if that's always true... but we have a problem if not. */ + gdb_assert (size == register_size (gdbarch, realnum)); if (realnum < gdbarch_num_regs (gdbarch) || !gdbarch_pseudo_register_write_p (gdbarch)) @@ -1505,9 +1518,9 @@ get_frame_register_bytes (const frame_info_ptr &next_frame, int regnum, gdbarch *gdbarch = frame_unwind_arch (next_frame); /* Skip registers wholly inside of OFFSET. */ - while (offset >= register_size (gdbarch, regnum)) + while (offset >= register_size (gdbarch, regnum, &next_frame)) { - offset -= register_size (gdbarch, regnum); + offset -= register_size (gdbarch, regnum, &next_frame); regnum++; } @@ -1517,7 +1530,7 @@ get_frame_register_bytes (const frame_info_ptr &next_frame, int regnum, int numregs = gdbarch_num_cooked_regs (gdbarch); for (int i = regnum; i < numregs; i++) { - int thissize = register_size (gdbarch, i); + int thissize = register_size (gdbarch, i, &next_frame); if (thissize == 0) break; /* This register is not available on this architecture. */ @@ -1531,10 +1544,10 @@ get_frame_register_bytes (const frame_info_ptr &next_frame, int regnum, /* Copy the data. */ while (!buffer.empty ()) { - int curr_len = std::min (register_size (gdbarch, regnum) - offset, - buffer.size ()); + int reg_size = register_size (gdbarch, regnum, &next_frame); + int curr_len = std::min (reg_size - offset, buffer.size ()); - if (curr_len == register_size (gdbarch, regnum)) + if (curr_len == reg_size) { enum lval_type lval; CORE_ADDR addr; @@ -1582,19 +1595,19 @@ put_frame_register_bytes (const frame_info_ptr &next_frame, int regnum, gdbarch *gdbarch = frame_unwind_arch (next_frame); /* Skip registers wholly inside of OFFSET. */ - while (offset >= register_size (gdbarch, regnum)) + while (offset >= register_size (gdbarch, regnum, &next_frame)) { - offset -= register_size (gdbarch, regnum); + offset -= register_size (gdbarch, regnum, &next_frame); regnum++; } /* Copy the data. */ while (!buffer.empty ()) { - int curr_len = std::min (register_size (gdbarch, regnum) - offset, - buffer.size ()); + int reg_size = register_size (gdbarch, regnum, &next_frame); + int curr_len = std::min (reg_size - offset, buffer.size ()); - if (curr_len == register_size (gdbarch, regnum)) + if (curr_len == reg_size) put_frame_register (next_frame, regnum, buffer.slice (0, curr_len)); else { diff --git a/gdb/record-full.c b/gdb/record-full.c index b52fb062d80..ffedafbbede 100644 --- a/gdb/record-full.c +++ b/gdb/record-full.c @@ -401,12 +401,11 @@ static inline struct record_full_entry * record_full_reg_alloc (struct regcache *regcache, int regnum) { struct record_full_entry *rec; - struct gdbarch *gdbarch = regcache->arch (); rec = XCNEW (struct record_full_entry); rec->type = record_full_reg; rec->u.reg.num = regnum; - rec->u.reg.len = register_size (gdbarch, regnum); + rec->u.reg.len = regcache->register_size (regnum); if (rec->u.reg.len > sizeof (rec->u.reg.u.buf)) rec->u.reg.u.ptr = (gdb_byte *) xmalloc (rec->u.reg.len); diff --git a/gdb/regcache.c b/gdb/regcache.c index e3d435f90d5..2a65be67382 100644 --- a/gdb/regcache.c +++ b/gdb/regcache.c @@ -51,7 +51,7 @@ struct regcache_descr redundant information - if the PC is constructed from two registers then those registers and not the PC lives in the raw cache. */ - long sizeof_raw_registers = 0; + long sizeof_fixed_size_raw_registers = 0; /* The cooked register space. Each cooked register in the range [0..NR_RAW_REGISTERS) is direct-mapped onto the corresponding raw @@ -60,7 +60,7 @@ struct regcache_descr both raw registers and memory by the architecture methods gdbarch_pseudo_register_read and gdbarch_pseudo_register_write. */ int nr_cooked_registers = 0; - long sizeof_cooked_registers = 0; + long sizeof_fixed_size_cooked_registers = 0; /* Offset and size (in 8 bit bytes), of each register in the register cache. All registers (including those in the range @@ -69,6 +69,12 @@ struct regcache_descr long *register_offset = nullptr; long *sizeof_register = nullptr; + /* Vector indicating whether a given register is variable-size. */ + bool *register_is_variable_size = nullptr; + + /* Does the regcache contains any variable-size register? */ + bool has_variable_size_registers = false; + /* Cached table containing the type of each register. */ struct type **register_type = nullptr; }; @@ -116,23 +122,49 @@ init_regcache_descr (struct gdbarch *gdbarch) = GDBARCH_OBSTACK_CALLOC (gdbarch, descr->nr_cooked_registers, long); descr->register_offset = GDBARCH_OBSTACK_CALLOC (gdbarch, descr->nr_cooked_registers, long); + descr->register_is_variable_size + = GDBARCH_OBSTACK_CALLOC (gdbarch, descr->nr_cooked_registers, bool); + for (i = 0; i < gdbarch_num_regs (gdbarch); i++) { - descr->sizeof_register[i] = descr->register_type[i]->length (); - descr->register_offset[i] = offset; - offset += descr->sizeof_register[i]; + descr->register_is_variable_size[i] + = is_dynamic_type (descr->register_type[i]); + if (descr->register_is_variable_size[i]) + { + descr->sizeof_register[i] = -1; + descr->register_offset[i] = -1; + descr->has_variable_size_registers = true; + } + else + { + descr->sizeof_register[i] = descr->register_type[i]->length (); + descr->register_offset[i] = offset; + offset += descr->sizeof_register[i]; + } } + /* Set the real size of the raw register cache buffer. */ - descr->sizeof_raw_registers = offset; + descr->sizeof_fixed_size_raw_registers = offset; for (; i < descr->nr_cooked_registers; i++) { - descr->sizeof_register[i] = descr->register_type[i]->length (); - descr->register_offset[i] = offset; - offset += descr->sizeof_register[i]; + descr->register_is_variable_size[i] + = is_dynamic_type (descr->register_type[i]); + if (descr->register_is_variable_size[i]) + { + descr->sizeof_register[i] = -1; + descr->register_offset[i] = -1; + descr->has_variable_size_registers = true; + } + else + { + descr->sizeof_register[i] = descr->register_type[i]->length (); + descr->register_offset[i] = offset; + offset += descr->sizeof_register[i]; + } } /* Set the real size of the readonly register cache buffer. */ - descr->sizeof_cooked_registers = offset; + descr->sizeof_fixed_size_cooked_registers = offset; } return descr; @@ -154,27 +186,60 @@ regcache_descr (struct gdbarch *gdbarch) /* Utility functions returning useful register attributes stored in the regcache descr. */ +/* See gdb/regcache.h. */ + struct type * register_type (struct gdbarch *gdbarch, int regnum) { struct regcache_descr *descr = regcache_descr (gdbarch); gdb_assert (regnum >= 0 && regnum < descr->nr_cooked_registers); - return descr->register_type[regnum]; + + struct type *type = descr->register_type[regnum]; + + if (descr->register_is_variable_size[regnum]) + { + frame_info_ptr current_frame = get_current_frame (); + type = resolve_dynamic_type (type, {}, 0, ¤t_frame); + } + + return type; } -/* Utility functions returning useful register attributes stored in - the regcache descr. */ +/* See gdb/regcache.h. */ int -register_size (struct gdbarch *gdbarch, int regnum) +register_size (struct gdbarch *gdbarch, int regnum, + const frame_info_ptr *next_frame) { struct regcache_descr *descr = regcache_descr (gdbarch); - int size; - gdb_assert (regnum >= 0 && regnum < gdbarch_num_cooked_regs (gdbarch)); - size = descr->sizeof_register[regnum]; - return size; + gdb_assert (regnum >= 0); + gdb_assert (regnum < descr->nr_cooked_registers); + + if (descr->register_is_variable_size[regnum]) + { + gdb_assert (next_frame != nullptr); + + std::unique_ptr regcache = + frame_save_as_regcache (get_prev_frame (*next_frame)); + return regcache->register_size (regnum); + } + + return descr->sizeof_register[regnum]; +} + +/* See gdb/regcache.h. */ + +bool +register_is_variable_size (struct gdbarch *gdbarch, int regnum) +{ + struct regcache_descr *descr = regcache_descr (gdbarch); + + gdb_assert (regnum >= 0); + gdb_assert (regnum < descr->nr_cooked_registers); + + return descr->register_is_variable_size[regnum]; } /* See gdbsupport/common-regcache.h. */ @@ -182,7 +247,47 @@ register_size (struct gdbarch *gdbarch, int regnum) int reg_buffer::register_size (int regnum) const { - return ::register_size (this->arch (), regnum); + gdb_assert (regnum >= 0); + gdb_assert (regnum < m_descr->nr_cooked_registers); + + int size; + + if (m_descr->register_is_variable_size[regnum]) + { + if (!m_variable_size_registers) + const_cast (this) + ->initialize_variable_size_registers (); // FIXME: Remove cast. + + size = m_variable_size_register_sizeof[regnum]; + } + else + size = m_descr->sizeof_register[regnum]; + + return size; +} + +/* See gdb/regcache.h. */ + +struct type * +reg_buffer::register_type (int regnum) const +{ + gdb_assert (regnum >= 0); + gdb_assert (regnum < m_descr->nr_cooked_registers); + + struct type *type; + + if (m_descr->register_is_variable_size[regnum]) + { + if (!m_variable_size_registers) + const_cast (this) + ->initialize_variable_size_registers (); // FIXME: Remove cast. + + type = m_variable_size_register_type[regnum]; + } + else + type = m_descr->register_type[regnum]; + + return type; } reg_buffer::reg_buffer (gdbarch *gdbarch, bool has_pseudo) @@ -196,13 +301,13 @@ reg_buffer::reg_buffer (gdbarch *gdbarch, bool has_pseudo) REG_VALID. */ if (has_pseudo) { - m_registers.reset (new gdb_byte[m_descr->sizeof_cooked_registers]); + m_fixed_size_registers.reset (new gdb_byte[m_descr->sizeof_fixed_size_cooked_registers]); m_register_status.reset (new register_status[m_descr->nr_cooked_registers] ()); } else { - m_registers.reset (new gdb_byte[m_descr->sizeof_raw_registers]); + m_fixed_size_registers.reset (new gdb_byte[m_descr->sizeof_fixed_size_raw_registers]); m_register_status.reset (new register_status[gdbarch_num_regs (gdbarch)] ()); } @@ -231,6 +336,50 @@ reg_buffer::arch () const return m_descr->gdbarch; } +/* See regcache.h. */ + +void +reg_buffer::initialize_variable_size_registers () +{ + unsigned long total_size = 0; + + m_variable_size_register_type.resize (m_descr->nr_cooked_registers); + m_variable_size_register_sizeof.resize (m_descr->nr_cooked_registers); + m_variable_size_register_offset.resize (m_descr->nr_cooked_registers); + + for (unsigned int i = 0; i < m_descr->nr_cooked_registers; i++) + { + if (!m_descr->register_is_variable_size[i]) + { + m_variable_size_register_type[i] = nullptr; + m_variable_size_register_sizeof[i] = -1; + m_variable_size_register_offset[i] = -1; + continue; + } + + m_variable_size_register_type[i] + = resolve_dynamic_type (m_descr->register_type[i], {}, + /* Unused address. */ 0, nullptr); + + ULONGEST size = m_variable_size_register_type[i]->length (); + gdb_assert (size != 0); + m_variable_size_register_sizeof[i] = size; + m_variable_size_register_offset[i] = total_size; + m_register_status[i] = REG_UNKNOWN; + total_size += size; + } + + m_variable_size_registers.reset (new gdb_byte[total_size]); +} + +/* See regcache.h. */ + +bool +reg_buffer::has_variable_size_registers () +{ + return m_descr->has_variable_size_registers; +} + /* Helper for reg_buffer::register_buffer. */ template @@ -238,8 +387,19 @@ gdb::array_view reg_buffer::register_buffer (int regnum) const { assert_regnum (regnum); - ElemType *start = &m_registers[m_descr->register_offset[regnum]]; - int size = m_descr->sizeof_register[regnum]; + ElemType *start; + + if (m_descr->register_is_variable_size[regnum]) + { + if (!m_variable_size_registers) + const_cast(this)->initialize_variable_size_registers (); // FIXME: Remove cast. + + start = &m_variable_size_registers[m_variable_size_register_offset[regnum]]; + } + else + start = &m_fixed_size_registers[m_descr->register_offset[regnum]]; + + int size = register_size (regnum); return gdb::array_view (start, size); } @@ -267,8 +427,14 @@ reg_buffer::save (register_read_ftype cooked_read) /* It should have pseudo registers. */ gdb_assert (m_has_pseudo); /* Clear the dest. */ - memset (m_registers.get (), 0, m_descr->sizeof_cooked_registers); + memset (m_fixed_size_registers.get (), 0, m_descr->sizeof_fixed_size_cooked_registers); memset (m_register_status.get (), REG_UNKNOWN, m_descr->nr_cooked_registers); + + /* For data related to variable-size registers, we only need to reset + their buffer at this point. Other data will be resized/re-set by + initialize_variable_size_registers (). */ + m_variable_size_registers.reset (); + /* Copy over any registers (identified by their membership in the save_reggroup) and mark them as valid. The full [0 .. gdbarch_num_regs + gdbarch_num_pseudo_regs) range is checked since some architectures need @@ -615,7 +781,7 @@ register_status readable_regcache::raw_read (int regnum, gdb::array_view dst) { assert_regnum (regnum); - gdb_assert (dst.size () == m_descr->sizeof_register[regnum]); + gdb_assert (dst.size () == register_size (regnum)); raw_update (regnum); @@ -631,7 +797,7 @@ register_status readable_regcache::raw_read (int regnum, gdb_byte *dst) { assert_regnum (regnum); - int size = m_descr->sizeof_register[regnum]; + int size = register_size (regnum); return raw_read (regnum, gdb::make_array_view (dst, size)); } @@ -647,7 +813,7 @@ enum register_status readable_regcache::raw_read (int regnum, T *val) { assert_regnum (regnum); - size_t size = m_descr->sizeof_register[regnum]; + size_t size = register_size (regnum); gdb_byte *buf = (gdb_byte *) alloca (size); auto view = gdb::make_array_view (buf, size); register_status status = raw_read (regnum, view); @@ -682,7 +848,7 @@ regcache::raw_write (int regnum, T val) { assert_regnum (regnum); - int size = m_descr->sizeof_register[regnum]; + int size = register_size (regnum); gdb_byte *buf = (gdb_byte *) alloca (size); auto view = gdb::make_array_view (buf, size); store_integer (view, gdbarch_byte_order (m_descr->gdbarch), val); @@ -721,7 +887,7 @@ readable_regcache::cooked_read (int regnum, gdb::array_view dst) if (regnum < num_raw_registers ()) return raw_read (regnum, dst); - gdb_assert (dst.size () == m_descr->sizeof_register[regnum]); + gdb_assert (dst.size () == register_size (regnum)); if (m_has_pseudo && m_register_status[regnum] != REG_UNKNOWN) { @@ -763,7 +929,7 @@ readable_regcache::cooked_read (int regnum, gdb_byte *dst) gdb_assert (regnum >= 0); gdb_assert (regnum < m_descr->nr_cooked_registers); - int size = m_descr->sizeof_register[regnum]; + int size = register_size (regnum); return cooked_read (regnum, gdb::make_array_view (dst, size)); } @@ -777,8 +943,12 @@ readable_regcache::cooked_read_value (int regnum) || (m_has_pseudo && m_register_status[regnum] != REG_UNKNOWN) || !gdbarch_pseudo_register_read_value_p (m_descr->gdbarch)) { + /* Provide the register type if its size is fixed to avoid infinite + recursion in the case of variable-size registers. */ + struct type *type = (m_descr->register_is_variable_size[regnum] ? + nullptr : m_descr->register_type[regnum]); value *result = value::allocate_register - (get_next_frame_sentinel_okay (get_current_frame ()), regnum); + (get_next_frame_sentinel_okay (get_current_frame ()), regnum, type); /* It is more efficient in general to do this delegation in this direction than in the other one, even though the value-based @@ -808,7 +978,7 @@ enum register_status readable_regcache::cooked_read (int regnum, T *val) { gdb_assert (regnum >= 0 && regnum < m_descr->nr_cooked_registers); - size_t size = m_descr->sizeof_register[regnum]; + size_t size = register_size (regnum); gdb_byte *buf = (gdb_byte *) alloca (size); auto view = gdb::make_array_view (buf, size); register_status status = cooked_read (regnum, view); @@ -842,7 +1012,7 @@ regcache::cooked_write (int regnum, T val) gdb_assert (regnum >= 0); gdb_assert (regnum < m_descr->nr_cooked_registers); - int size = m_descr->sizeof_register[regnum]; + int size = register_size (regnum); gdb_byte *buf = (gdb_byte *) alloca (size); auto view = gdb::make_array_view (buf, size); store_integer (view, gdbarch_byte_order (m_descr->gdbarch), val); @@ -861,7 +1031,7 @@ void regcache::raw_write (int regnum, gdb::array_view src) { assert_regnum (regnum); - gdb_assert (src.size () == m_descr->sizeof_register[regnum]); + gdb_assert (src.size () == register_size (regnum)); /* 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. */ @@ -898,7 +1068,7 @@ regcache::raw_write (int regnum, const gdb_byte *src) { assert_regnum (regnum); - int size = m_descr->sizeof_register[regnum]; + int size = register_size (regnum); raw_write (regnum, gdb::make_array_view (src, size)); } @@ -929,7 +1099,7 @@ regcache::cooked_write (int regnum, const gdb_byte *src) gdb_assert (regnum >= 0); gdb_assert (regnum < m_descr->nr_cooked_registers); - int size = m_descr->sizeof_register[regnum]; + int size = register_size (regnum); return cooked_write (regnum, gdb::make_array_view (src, size)); } @@ -1159,7 +1329,7 @@ reg_buffer::raw_supply (int regnum, const void *src) { assert_regnum (regnum); - int size = m_descr->sizeof_register[regnum]; + int size = register_size (regnum); raw_supply (regnum, gdb::make_array_view ((const gdb_byte *) src, size)); } @@ -1213,7 +1383,7 @@ reg_buffer::raw_collect (int regnum, void *dst) const { assert_regnum (regnum); - int size = m_descr->sizeof_register[regnum]; + int size = register_size (regnum); return raw_collect (regnum, gdb::make_array_view ((gdb_byte *) dst, size)); } @@ -1288,7 +1458,7 @@ regcache::transfer_regset (const struct regset *regset, int regbase, regno += regbase; if (slot_size == 0 && regno != REGCACHE_MAP_SKIP) - slot_size = m_descr->sizeof_register[regno]; + slot_size = register_size (regnum); if (regno == REGCACHE_MAP_SKIP || (regnum != -1 diff --git a/gdb/regcache.h b/gdb/regcache.h index 7eb49b3ae66..1da162f2f74 100644 --- a/gdb/regcache.h +++ b/gdb/regcache.h @@ -165,10 +165,15 @@ extern bool regcache_map_supplies (const struct regcache_map_entry *map, extern struct type *register_type (struct gdbarch *gdbarch, int regnum); -/* Return the size of register REGNUM. All registers should have only - one size. */ +/* Return the size of register REGNUM. FRAME is needed in case regnum is a + variable-size register. */ -extern int register_size (struct gdbarch *gdbarch, int regnum); +extern int register_size (struct gdbarch *gdbarch, int regnum, + const frame_info_ptr *next_frame = nullptr); + +/* Return whether REGNUM is a variable-size register. */ + +extern bool register_is_variable_size (struct gdbarch *gdbarch, int regnum); using register_read_ftype = gdb::function_view)>; @@ -257,6 +262,12 @@ public: /* See gdbsupport/common-regcache.h. */ bool raw_compare (int regnum, const void *buf, int offset) const override; + /* Whether any register in this regcache has a dynamic type. */ + bool has_variable_size_registers (); + + /* Return type of register REGNUM. */ + struct type *register_type (int regnum) const; + /* See gdbsupport/common-regcache.h. */ int register_size (int regnum) const override; @@ -266,6 +277,10 @@ protected: int num_raw_registers () const; + /* Initialize (or reset) information about variable-size registers in this + reg_buffer. */ + void initialize_variable_size_registers (); + /* Return a view on register REGNUM's buffer cache. */ template gdb::array_view register_buffer (int regnum) const; @@ -280,11 +295,25 @@ protected: struct regcache_descr *m_descr; bool m_has_pseudo; - /* The register buffers. */ - std::unique_ptr m_registers; + + /* The fixed-size register buffers. */ + std::unique_ptr m_fixed_size_registers; + + /* The variable-size register buffers (if any). */ + std::unique_ptr m_variable_size_registers; + /* Register cache status. */ std::unique_ptr m_register_status; + /* The resolved types for variable-size registers (if any). */ + std::vector m_variable_size_register_type; + + /* The size of resolved types for variable-size registers (if any). */ + std::vector m_variable_size_register_sizeof; + + /* The offset of resolved types for variable-size registers (if any). */ + std::vector m_variable_size_register_offset; + friend class regcache; friend class detached_regcache; }; diff --git a/gdb/remote.c b/gdb/remote.c index 7dc057c0568..ea3c254a770 100644 --- a/gdb/remote.c +++ b/gdb/remote.c @@ -472,6 +472,8 @@ struct packet_reg at present. */ }; +struct remote_state; + struct remote_arch_state { explicit remote_arch_state (struct gdbarch *gdbarch); @@ -494,6 +496,10 @@ struct remote_arch_state /* This is the maximum size (in chars) of a non read/write packet. It is also used as a cap on the size of read/write packets. */ long remote_packet_size; + + /* Make sure the maximum packet size reflects current size of variable-size + registers. */ + void update_packet_size (const struct regcache *regcache, remote_state *rs); }; /* Description of the remote protocol state for the currently @@ -1894,7 +1900,8 @@ show_remote_exec_file (struct ui_file *file, int from_tty, } static int -map_regcache_remote_table (struct gdbarch *gdbarch, struct packet_reg *regs) +map_regcache_remote_table (struct gdbarch *gdbarch, struct packet_reg *regs, + const struct regcache *regcache = nullptr) { int regnum, num_remote_regs, offset; struct packet_reg **remote_regs; @@ -1902,8 +1909,15 @@ map_regcache_remote_table (struct gdbarch *gdbarch, struct packet_reg *regs) for (regnum = 0; regnum < gdbarch_num_regs (gdbarch); regnum++) { struct packet_reg *r = ®s[regnum]; + bool skip_register; - if (register_size (gdbarch, regnum) == 0) + if (regcache == nullptr) + skip_register = (register_is_variable_size (gdbarch, regnum) + || register_size (gdbarch, regnum) == 0); + else + skip_register = regcache->register_size (regnum) == 0; + + if (skip_register) /* Do not try to fetch zero-sized (placeholder) registers. */ r->pnum = -1; else @@ -1931,7 +1945,10 @@ map_regcache_remote_table (struct gdbarch *gdbarch, struct packet_reg *regs) { remote_regs[regnum]->in_g_packet = true; remote_regs[regnum]->offset = offset; - offset += register_size (gdbarch, remote_regs[regnum]->regnum); + if (regcache == nullptr) + offset += register_size (gdbarch, remote_regs[regnum]->regnum); + else + offset += regcache->register_size (remote_regs[regnum]->regnum); } return offset; @@ -1992,6 +2009,29 @@ remote_arch_state::remote_arch_state (struct gdbarch *gdbarch) this->remote_packet_size = (this->sizeof_g_packet * 2 + 32); } +/* See remote_arch_state class declaration. */ + +void +remote_arch_state::update_packet_size (const struct regcache *regcache, + remote_state *rs) +{ + /* Record the maximum possible size of the g packet - it may turn out + to be smaller. */ + this->sizeof_g_packet + = map_regcache_remote_table (regcache->arch (), this->regs.get (), + regcache); + + this->remote_packet_size = 400 - 1; + + if (this->sizeof_g_packet > (this->remote_packet_size - 32) / 2) + this->remote_packet_size = this->sizeof_g_packet * 2 + 32; + + /* Make sure that the packet buffer is plenty big enough for + this architecture. */ + if (rs->buf.size () < this->remote_packet_size) + rs->buf.resize (2 * this->remote_packet_size); +} + /* Get a pointer to the current remote target. If not connected to a remote target, return NULL. */ @@ -9006,7 +9046,7 @@ remote_target::process_g_packet (struct regcache *regcache) for (i = 0; i < gdbarch_num_regs (gdbarch); i++) { long offset = rsa->regs[i].offset; - long reg_size = register_size (gdbarch, i); + long reg_size = regcache->register_size (i); if (rsa->regs[i].pnum == -1) continue; @@ -9054,7 +9094,7 @@ remote_target::process_g_packet (struct regcache *regcache) for (i = 0; i < gdbarch_num_regs (gdbarch); i++) { struct packet_reg *r = &rsa->regs[i]; - long reg_size = register_size (gdbarch, i); + long reg_size = regcache->register_size (i); if (r->in_g_packet) { @@ -9189,7 +9229,8 @@ remote_target::store_register_using_P (const struct regcache *regcache, struct remote_state *rs = get_remote_state (); /* Try storing a single register. */ char *buf = rs->buf.data (); - gdb_byte *regp = (gdb_byte *) alloca (register_size (gdbarch, reg->regnum)); + int reg_size = regcache->register_size (reg->regnum); + gdb_byte *regp = (gdb_byte *) alloca (reg_size); char *p; if (m_features.packet_support (PACKET_P) == PACKET_DISABLE) @@ -9201,7 +9242,7 @@ remote_target::store_register_using_P (const struct regcache *regcache, xsnprintf (buf, get_remote_packet_size (), "P%s=", phex_nz (reg->pnum, 0)); p = buf + strlen (buf); regcache->raw_collect (reg->regnum, regp); - bin2hex (regp, p, register_size (gdbarch, reg->regnum)); + bin2hex (regp, p, reg_size); putpkt (rs->buf); getpkt (&rs->buf); diff --git a/gdb/value.c b/gdb/value.c index 0f1be2e5d12..5c0e5d83518 100644 --- a/gdb/value.c +++ b/gdb/value.c @@ -4083,12 +4083,24 @@ value::fetch_lazy_register () if (new_val->entirely_available ()) { - int i; + int i, reg_size; gdb::array_view buf = new_val->contents (); gdb_printf (&debug_file, " bytes="); gdb_printf (&debug_file, "["); - for (i = 0; i < register_size (gdbarch, regnum); i++) + + if (register_is_variable_size (gdbarch, regnum)) + /* To get the size of a variable-size register, we need to + call frame_save_as_regcache () so that we can call + regcache::register_size (). Unfortunatlly the former + ends up calling this function so we enter into an + infinite recursion. So just assume that the value has + the correct size. */ + reg_size = buf.size (); + else + reg_size = register_size (gdbarch, regnum); + + for (i = 0; i < reg_size; i++) gdb_printf (&debug_file, "%02x", buf[i]); gdb_printf (&debug_file, "]"); } -- 2.47.2