]> git.ipfire.org Git - thirdparty/binutils-gdb.git/commitdiff
Support unwinding tdesc parameters in the signal trampoline unwinder
authorThiago Jung Bauermann <thiago.bauermann@linaro.org>
Sun, 20 Apr 2025 23:31:33 +0000 (20:31 -0300)
committerThiago Jung Bauermann <thiago.bauermann@linaro.org>
Mon, 21 Apr 2025 03:16:45 +0000 (00:16 -0300)
gdb/arch-utils.c
gdb/dwarf2/frame.c
gdb/frame-unwind.c
gdb/gdbarch-gen.c
gdb/gdbarch-gen.h
gdb/gdbarch_components.py
gdb/regcache.c
gdb/target-descriptions.c
gdb/tramp-frame.c
gdb/tramp-frame.h

index 20469e85017267d5ddef285e7209a549f8906869..6fe727fa021fc148424d6ac4e84349e2f1703b8d 100644 (file)
@@ -1139,6 +1139,12 @@ default_fetch_tdesc_parameter (struct gdbarch *gdbarch,
         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
index 1b4de0da2f6736dbe83f35bf72f53b7e5df828ec..1cf5f5302492e9e434e2aa404c429b6d5b523554 100644 (file)
@@ -1331,6 +1331,22 @@ dwarf2_frame_sniffer (const struct frame_unwind *self,
   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,
@@ -1340,7 +1356,9 @@ static const struct frame_unwind_legacy dwarf2_frame_unwind (
   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 (
index d8cfd66e07a7249f75a6ccc1e8a7117e44a00e06..c03e24e9b396de4ec4723d8bb20fafaf2a79b6dd 100644 (file)
@@ -306,8 +306,21 @@ struct value *
 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;
index e82972a34730f93d232810a6464b1ff4864f955d..275145d69a0e12303bea02b0ce8b0fdaf459f905 100644 (file)
@@ -263,6 +263,7 @@ struct gdbarch
   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
@@ -537,6 +538,7 @@ verify_gdbarch (struct gdbarch *gdbarch)
   /* 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 ());
@@ -1411,6 +1413,9 @@ gdbarch_dump (struct gdbarch *gdbarch, struct ui_file *file)
   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);
 }
@@ -5573,3 +5578,20 @@ set_gdbarch_fetch_tdesc_parameter (struct gdbarch *gdbarch,
 {
   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;
+}
index 7371c400e5f59dbc9d00e110dd873826e3e46025..d6058da93be9763c8284c3082f13960939385a85 100644 (file)
@@ -1807,3 +1807,9 @@ extern void set_gdbarch_core_parse_exec_context (struct gdbarch *gdbarch, gdbarc
 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);
index 87694eb82b47906432993aa193d70cd1a0dd695e..c893d5c941a6339475d29899eb9327ddf91ddf63 100644 (file)
@@ -2862,3 +2862,14 @@ Obtain or calculate target description parameter.
     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,
+)
index ab98db02109a8016a9959eb52ed68ae34b5b5c0e..fd0824da5b81572f96a6b987c5bdcdd11c33fda8 100644 (file)
@@ -375,9 +375,11 @@ reg_buffer::initialize_variable_size_registers ()
          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);
index d1d55ad82902ec7f9545f95ac709c3177f48c778..06b65d59059d9eaf57dc183a11021535ae52b870 100644 (file)
@@ -1045,6 +1045,16 @@ tdesc_register_type (struct gdbarch *gdbarch, int regno)
   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)
 {
@@ -1238,6 +1248,8 @@ tdesc_use_registers (struct gdbarch *gdbarch,
   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.  */
index 0e31ad37daea4dd7b6c169325303a12e07070587..4936de7740a17501dc81b608e8d1b38c44767c21 100644 (file)
@@ -61,9 +61,10 @@ class frame_unwind_trampoline : public frame_unwind
 {
 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,
@@ -84,8 +85,22 @@ public:
     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
@@ -196,6 +211,7 @@ tramp_frame_prepend_unwinder (struct gdbarch *gdbarch,
   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);
 }
index 204444150a08e1fc2c90d82d1f0483d780b71d57..43c8119f7e8b8262e578b38bd89cedd2ee55de44 100644 (file)
@@ -80,6 +80,9 @@ struct tramp_frame
   /* 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,