gdbarch_bfd_arch_info (get_current_arch ())->printable_name);
}
+static bool
+default_register_is_variable_size (struct gdbarch *gdbarch, int regno)
+{
+ return false;
+}
+
/* Non-zero if we want to trace architecture code. */
#ifndef GDBARCH_DEBUG
return 1;
}
+static value *
+dwarf2_frame_prev_tdesc_parameter (const frame_info_ptr &this_frame,
+ void **this_prologue_cache,
+ unsigned int parameter_id)
+{
+ /* There's no DWARF concept of target description parameter, so we can't
+ find it. But sometimes we may be asked about it so forward the
+ question to next frame's unwinder. This is analogous to the
+ DWARF2_FRAME_REG_UNSPECIFIED case in dwarf2_frame_prev_register. */
+ frame_info_ptr next_frame = get_next_frame (this_frame);
+ if (next_frame == nullptr)
+ return nullptr;
+ else
+ return frame_unwind_tdesc_parameter_value (next_frame, parameter_id);
+}
+
static const struct frame_unwind_legacy dwarf2_frame_unwind (
"dwarf2",
NORMAL_FRAME,
dwarf2_frame_prev_register,
NULL,
dwarf2_frame_sniffer,
- dwarf2_frame_dealloc_cache
+ dwarf2_frame_dealloc_cache,
+ nullptr, /* prev_arch */
+ dwarf2_frame_prev_tdesc_parameter
);
static const struct frame_unwind_legacy dwarf2_signal_frame_unwind (
frame_unwind_got_memory (const frame_info_ptr &frame, int regnum, CORE_ADDR addr)
{
struct gdbarch *gdbarch = frame_unwind_arch (frame);
- struct value *v = value_at_lazy (register_type (gdbarch, regnum, &frame),
- addr);
+ const frame_info_ptr *prev_frame_ptr = nullptr;
+
+ if (gdbarch_register_is_variable_size (gdbarch, regnum))
+ {
+ /* Resolve type using previous frame, because, that's the context in
+ which the type's dynamic properties need to be resolved. It's not
+ always possible to get the previous frame though (we may be in the
+ process of computing its frame id) so only do it for variable-size
+ registers, which is the case when register_type actually needs the
+ frame argument. */
+ frame_info_ptr prev_frame = get_prev_frame (frame);
+ prev_frame_ptr = &prev_frame;
+ }
+ struct value *v = value_at_lazy (register_type (gdbarch, regnum,
+ prev_frame_ptr), addr);
v->set_stack (true);
return v;
gdbarch_use_target_description_from_corefile_notes_ftype *use_target_description_from_corefile_notes = default_use_target_description_from_corefile_notes;
gdbarch_core_parse_exec_context_ftype *core_parse_exec_context = default_core_parse_exec_context;
gdbarch_fetch_tdesc_parameter_ftype *fetch_tdesc_parameter = default_fetch_tdesc_parameter;
+ gdbarch_register_is_variable_size_ftype *register_is_variable_size = default_register_is_variable_size;
};
/* Create a new ``struct gdbarch'' based on information provided by
/* Skip verify of use_target_description_from_corefile_notes, invalid_p == 0. */
/* Skip verify of core_parse_exec_context, invalid_p == 0. */
/* Skip verify of fetch_tdesc_parameter, invalid_p == 0. */
+ /* Skip verify of register_is_variable_size, invalid_p == 0. */
if (!log.empty ())
internal_error (_("verify_gdbarch: the following are invalid ...%s"),
log.c_str ());
gdb_printf (file,
"gdbarch_dump: fetch_tdesc_parameter = <%s>\n",
host_address_to_string (gdbarch->fetch_tdesc_parameter));
+ gdb_printf (file,
+ "gdbarch_dump: register_is_variable_size = <%s>\n",
+ host_address_to_string (gdbarch->register_is_variable_size));
if (gdbarch->dump_tdep != NULL)
gdbarch->dump_tdep (gdbarch, file);
}
{
gdbarch->fetch_tdesc_parameter = fetch_tdesc_parameter;
}
+
+bool
+gdbarch_register_is_variable_size (struct gdbarch *gdbarch, int regno)
+{
+ gdb_assert (gdbarch != NULL);
+ gdb_assert (gdbarch->register_is_variable_size != NULL);
+ if (gdbarch_debug >= 2)
+ gdb_printf (gdb_stdlog, "gdbarch_register_is_variable_size called\n");
+ return gdbarch->register_is_variable_size (gdbarch, regno);
+}
+
+void
+set_gdbarch_register_is_variable_size (struct gdbarch *gdbarch,
+ gdbarch_register_is_variable_size_ftype register_is_variable_size)
+{
+ gdbarch->register_is_variable_size = register_is_variable_size;
+}
typedef void (gdbarch_fetch_tdesc_parameter_ftype) (struct gdbarch *gdbarch, readable_regcache *regcache, unsigned int parameter_id);
extern void gdbarch_fetch_tdesc_parameter (struct gdbarch *gdbarch, readable_regcache *regcache, unsigned int parameter_id);
extern void set_gdbarch_fetch_tdesc_parameter (struct gdbarch *gdbarch, gdbarch_fetch_tdesc_parameter_ftype *fetch_tdesc_parameter);
+
+/* Can the size of this register change during runtime? */
+
+typedef bool (gdbarch_register_is_variable_size_ftype) (struct gdbarch *gdbarch, int regno);
+extern bool gdbarch_register_is_variable_size (struct gdbarch *gdbarch, int regno);
+extern void set_gdbarch_register_is_variable_size (struct gdbarch *gdbarch, gdbarch_register_is_variable_size_ftype *register_is_variable_size);
predefault="default_fetch_tdesc_parameter",
invalid=False,
)
+
+Method(
+ comment="""
+Can the size of this register change during runtime?
+""",
+ type="bool",
+ name="register_is_variable_size",
+ params=[("int", "regno")],
+ predefault="default_register_is_variable_size",
+ invalid=False,
+)
continue;
}
+ /* Assume the register cache is for the current frame. */
+ frame_info_ptr frame = get_current_frame ();
m_variable_size_register_type[i]
= resolve_dynamic_type (m_descr->register_type[i], {},
- /* Unused address. */ 0, nullptr);
+ /* Unused address. */ 0, &frame);
ULONGEST size = m_variable_size_register_type[i]->length ();
gdb_assert (size != 0);
return arch_reg->type;
}
+static bool
+tdesc_register_is_variable_size (struct gdbarch *gdbarch, int regno)
+{
+ struct tdesc_reg *reg = tdesc_find_register (gdbarch, regno);
+
+ gdb_assert (reg != nullptr);
+
+ return reg->bitsize_parameter != nullptr;
+}
+
static int
tdesc_remote_register_number (struct gdbarch *gdbarch, int regno)
{
set_gdbarch_remote_register_number (gdbarch,
tdesc_remote_register_number);
set_gdbarch_register_reggroup_p (gdbarch, tdesc_register_reggroup_p);
+ set_gdbarch_register_is_variable_size (gdbarch,
+ tdesc_register_is_variable_size);
}
/* See gdbsupport/tdesc.h. */
{
public:
frame_unwind_trampoline (enum frame_type type, const struct frame_data *data,
- frame_prev_arch_ftype *prev_arch_func)
+ frame_prev_arch_ftype *prev_arch_func,
+ frame_prev_tdesc_parameter_ftype *prev_tdesc_parameter_func)
: frame_unwind ("trampoline", type, FRAME_UNWIND_GDB, data),
- m_prev_arch (prev_arch_func)
+ m_prev_arch (prev_arch_func), m_prev_tdesc_parameter (prev_tdesc_parameter_func)
{ }
int sniff (const frame_info_ptr &this_frame,
return m_prev_arch (this_frame, this_prologue_cache);
}
+ /* Get the value of a target description parameter in a previous frame. */
+
+ value *prev_tdesc_parameter (const frame_info_ptr &this_frame,
+ void **this_prologue_cache,
+ unsigned int parameter_id) const override
+ {
+ if (m_prev_tdesc_parameter == nullptr)
+ return frame_unwind::prev_tdesc_parameter (this_frame, this_prologue_cache,
+ parameter_id);
+ return m_prev_tdesc_parameter (this_frame, this_prologue_cache, parameter_id);
+ }
+
private:
frame_prev_arch_ftype *m_prev_arch;
+
+ frame_prev_tdesc_parameter_ftype *m_prev_tdesc_parameter;
};
void
unwinder = obstack_new <frame_unwind_trampoline> (gdbarch_obstack (gdbarch),
tramp_frame->frame_type,
data,
- tramp_frame->prev_arch);
+ tramp_frame->prev_arch,
+ tramp_frame->prev_tdesc_parameter);
frame_unwind_prepend_unwinder (gdbarch, unwinder);
}
/* Given the current frame in THIS_FRAME and a frame cache in FRAME_CACHE,
return the architecture of the previous frame. */
frame_prev_arch_ftype *prev_arch;
+
+ /* FIXME: Document. */
+ frame_prev_tdesc_parameter_ftype *prev_tdesc_parameter;
};
void tramp_frame_prepend_unwinder (struct gdbarch *gdbarch,