]> git.ipfire.org Git - thirdparty/binutils-gdb.git/commitdiff
Continuation of support for target description parameters
authorThiago Jung Bauermann <thiago.bauermann@linaro.org>
Fri, 18 Apr 2025 01:36:21 +0000 (22:36 -0300)
committerThiago Jung Bauermann <thiago.bauermann@linaro.org>
Sun, 20 Apr 2025 02:48:48 +0000 (23:48 -0300)
With this commit, it's possible to declare parameters in a feature, and
generate C and XML feature files.

The regcache also supports using parameters for variable-size registers,
and they can be "unwound" from the sentinel frame.

There's a new gdbarch_fetch_tdesc_parameter hook to request the value of
a parameter from the architecture. Maybe a target hook will be needed
too, for remote debugging.

There's generic support for unwinding parameters from a frame, but for
now only the sentinel frame allows it.

Remote debugging a target which uses parameters in the target
description isn't yet supported.

20 files changed:
gdb/arch-utils.c
gdb/dwarf2/loc.c
gdb/features/gdb-target.dtd
gdb/frame-unwind.c
gdb/frame-unwind.h
gdb/frame.c
gdb/frame.h
gdb/gdbarch-gen.c
gdb/gdbarch-gen.h
gdb/gdbarch_components.py
gdb/gdbtypes.c
gdb/gdbtypes.h
gdb/regcache.c
gdb/regcache.h
gdb/sentinel-frame.c
gdb/target-descriptions.c
gdb/target-descriptions.h
gdb/xml-tdesc.c
gdbsupport/tdesc.cc
gdbsupport/tdesc.h

index be0494fba1e3ab3c386462ca916d06ab6a1e3273..20469e85017267d5ddef285e7209a549f8906869 100644 (file)
@@ -1130,6 +1130,15 @@ default_update_call_site_pc (struct gdbarch *gdbarch, CORE_ADDR pc)
   return pc;
 }
 
+static void
+default_fetch_tdesc_parameter (struct gdbarch *gdbarch,
+                              readable_regcache *regcache,
+                              unsigned int parameter_id)
+{
+  error (_("Architecture \"%s\" doesn't support target description parameters"),
+        gdbarch_bfd_arch_info (get_current_arch ())->printable_name);
+}
+
 /* Non-zero if we want to trace architecture code.  */
 
 #ifndef GDBARCH_DEBUG
index e1a5fdd5b8d266c8c4e6adeffa7d2696370d0495..9df9a453240c1190cb746681830ec6f3e011d0d6 100644 (file)
@@ -46,6 +46,7 @@
 #include "gdbsupport/underlying.h"
 #include "gdbsupport/byte-vector.h"
 #include "extract-store-integer.h"
+#include "target-descriptions.h"
 
 static struct value *dwarf2_evaluate_loc_desc_full
   (struct type *type, const frame_info_ptr &frame, const gdb_byte *data,
@@ -1768,6 +1769,20 @@ dwarf2_evaluate_property (const dynamic_prop *prop,
          }
       }
       break;
+
+      case PROP_TDESC_PARAMETER:
+       {
+         gdbarch *gdbarch = get_frame_arch (frame);
+         auto [feature, param_name, element_length] = prop->tdesc_parameter ();
+         std::optional<unsigned int> param_id = tdesc_parameter_id (gdbarch,
+                                                                    feature,
+                                                                    param_name);
+         if (!param_id.has_value ())
+           return false;
+
+         return read_frame_tdesc_parameter_unsigned (frame, *param_id, value);
+       }
+       break;
     }
 
   return false;
index f619573f2412e8420129156c8b9f6afefb548341..ae7038d55e2130443f4cdc5a9a7494786e19cde9 100644 (file)
 <!ELEMENT compatible   (#PCDATA)>
 
 <!ELEMENT feature
-       ((vector | flags | struct | union )*, reg*)>
+       (parameter*, (vector | flags | struct | union )*, reg*)>
 <!ATTLIST feature
        name            ID      #REQUIRED>
 
+<!ELEMENT parameter    EMPTY>
+<!ATTLIST parameter
+       name            CDATA   #REQUIRED
+       type            CDATA   #REQUIRED>
+
 <!ELEMENT reg          (description*)>
 <!ATTLIST reg
        name            CDATA   #REQUIRED
index 9ed2dee714eceb08de1a6a7c949df672c5342d42..f035b9b860e7ce57a2b857742c7ffe48f5019c87 100644 (file)
@@ -401,6 +401,19 @@ frame_unwind_legacy::prev_register (const frame_info_ptr &this_frame,
 
 /* See frame-unwind.h.  */
 
+struct value *
+frame_unwind_legacy::prev_tdesc_parameter (const frame_info_ptr &this_frame,
+                                          void **this_prologue_cache,
+                                          unsigned int parameter_id) const
+{
+  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);
+}
+
+/* See frame-unwind.h.  */
+
 int
 frame_unwind_legacy::sniff (const frame_info_ptr &this_frame,
                            void **this_prologue_cache) const
index a967b7c4d3784c241374a8e181252c46e6c175d1..864a89bae3839a7df2b9281a006693dd879149e8 100644 (file)
@@ -144,6 +144,10 @@ typedef value *(frame_prev_register_ftype) (const frame_info_ptr &this_frame,
                                            void **this_prologue_cache,
                                            int regnum);
 
+typedef value *(frame_prev_tdesc_parameter_ftype)
+  (const frame_info_ptr &this_frame, void **this_prologue_cache,
+   unsigned int parameter);
+
 /* Deallocate extra memory associated with the frame cache if any.  */
 
 typedef void (frame_dealloc_cache_ftype) (frame_info *self,
@@ -226,6 +230,13 @@ public:
                                       void **this_prologue_cache,
                                       int regnum) const = 0;
 
+  /* Get the value of a target description parameter in a previous frame.  */
+
+  virtual value *prev_tdesc_parameter (const frame_info_ptr &this_frame,
+                                      void **this_prologue_cache,
+                                      unsigned int parameter) const
+  { return nullptr; }
+
   /* Properly deallocate the cache.  */
 
   virtual void dealloc_cache (frame_info *self, void *this_cache) const
@@ -274,11 +285,13 @@ struct frame_unwind_legacy : public frame_unwind
                       const struct frame_data *data,
                       frame_sniffer_ftype *sniffer_func,
                       frame_dealloc_cache_ftype *dealloc_cache_func = nullptr,
-                      frame_prev_arch_ftype *prev_arch_func = nullptr)
+                      frame_prev_arch_ftype *prev_arch_func = nullptr,
+                      frame_prev_tdesc_parameter_ftype *prev_tdesc_parameter_func = nullptr)
   : frame_unwind (name, type, uclass, data), m_stop_reason (stop_reason_func),
     m_this_id (this_id_func), m_prev_register (prev_register_func),
     m_sniffer (sniffer_func), m_dealloc_cache (dealloc_cache_func),
-    m_prev_arch (prev_arch_func)
+    m_prev_arch (prev_arch_func),
+    m_prev_tdesc_parameter (prev_tdesc_parameter_func)
   { }
 
   /* This method just passes the parameters to the callback pointer.  */
@@ -313,6 +326,12 @@ struct frame_unwind_legacy : public frame_unwind
   struct gdbarch *prev_arch (const frame_info_ptr &this_frame,
                             void **this_prologue_cache) const override;
 
+  /* This method just passes the parameters to the callback pointer.  */
+
+  value *prev_tdesc_parameter (const frame_info_ptr &this_frame,
+                              void **this_prologue_cache,
+                              unsigned int parameter) const override;
+
 private:
 
   frame_unwind_stop_reason_ftype *m_stop_reason;
@@ -321,6 +340,7 @@ private:
   frame_sniffer_ftype *m_sniffer;
   frame_dealloc_cache_ftype *m_dealloc_cache;
   frame_prev_arch_ftype *m_prev_arch;
+  frame_prev_tdesc_parameter_ftype *m_prev_tdesc_parameter;
 };
 
 /* Register a frame unwinder, _prepending_ it to the front of the
index 95151da6120bf828365542f4259a51e2c27ec0fa..960e68844563c1a007f8813a626f6e35c81b61cc 100644 (file)
@@ -44,6 +44,7 @@
 #include "valprint.h"
 #include "cli/cli-option.h"
 #include "dwarf2/loc.h"
+#include "target-descriptions.h"
 
 /* The sentinel frame terminates the innermost end of the frame chain.
    If unwound, it returns the information needed to construct an
@@ -1626,6 +1627,70 @@ put_frame_register_bytes (const frame_info_ptr &next_frame, int regnum,
     }
 }
 
+value *
+frame_unwind_tdesc_parameter_value (const frame_info_ptr &next_frame,
+                                   unsigned int parameter)
+{
+  FRAME_SCOPED_DEBUG_ENTER_EXIT;
+
+  gdb_assert (next_frame != nullptr);
+  gdbarch *gdbarch = frame_unwind_arch (next_frame);
+
+  /* Find the unwinder.  */
+  if (next_frame->unwind == NULL)
+    frame_unwind_find_by_frame (next_frame, &next_frame->prologue_cache);
+
+  /* Ask this frame to unwind its register.  */
+  value *value
+    = next_frame->unwind->prev_tdesc_parameter (next_frame,
+                                               &next_frame->prologue_cache,
+                                               parameter);
+  if (value == nullptr)
+    {
+      auto maybe_param_name = tdesc_parameter_name (gdbarch, parameter);
+      const char *feature, *param_name;
+      if (maybe_param_name.has_value ())
+       {
+         feature = maybe_param_name->first;
+         param_name = maybe_param_name->second;
+       }
+      else
+       {
+         feature = "unknown";
+         param_name = "unknown";
+       }
+
+      error (_("Can't unwind value of parameter %d (%s:%s)"), parameter,
+            feature, param_name);
+    }
+
+  return value;
+}
+
+value *
+get_frame_tdesc_parameter_value (const frame_info_ptr &frame,
+                                unsigned int parameter)
+{
+  return frame_unwind_tdesc_parameter_value (frame_info_ptr (frame->next),
+                                            parameter);
+}
+
+bool
+read_frame_tdesc_parameter_unsigned (const frame_info_ptr &frame,
+                                    unsigned int parameter, ULONGEST *val)
+{
+  value *value = get_frame_tdesc_parameter_value (frame, parameter);
+
+  if (!value->entirely_available ())
+    return false;
+
+  struct gdbarch *gdbarch = get_frame_arch (frame);
+  enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
+
+  *val = extract_unsigned_integer (value->contents (), byte_order);
+  return true;
+}
+
 /* Create a sentinel frame.
 
    See frame_id_build_sentinel for the description of STACK_ADDR and
index b240662bd73b885ed71f8f2c40398ca763e62157..3ac3d72125fb71d057f02cb8546e3d6eb4506797 100644 (file)
@@ -748,6 +748,19 @@ extern void put_frame_register_bytes (const frame_info_ptr &next_frame,
                                      int regnum, CORE_ADDR offset,
                                      gdb::array_view<const gdb_byte> buffer);
 
+/* FIXME: Document.  */
+extern value *frame_unwind_tdesc_parameter_value
+  (const frame_info_ptr &next_frame, unsigned int parameter);
+
+/* FIXME: Document.  */
+extern value *get_frame_tdesc_parameter_value (const frame_info_ptr &frame,
+                                              unsigned int parameter);
+
+/* FIXME: Document.  */
+extern bool read_frame_tdesc_parameter_unsigned (const frame_info_ptr &frame,
+                                                unsigned int parameter,
+                                                ULONGEST *val);
+
 /* Unwind the PC.  Strictly speaking return the resume address of the
    calling frame.  For GDB, `pc' is the resume address and not a
    specific register.  */
index 32d16598940b8a6cc7674d007fe5f00adb6ffc68..e82972a34730f93d232810a6464b1ff4864f955d 100644 (file)
@@ -262,6 +262,7 @@ struct gdbarch
   gdbarch_read_core_file_mappings_ftype *read_core_file_mappings = default_read_core_file_mappings;
   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;
 };
 
 /* Create a new ``struct gdbarch'' based on information provided by
@@ -535,6 +536,7 @@ verify_gdbarch (struct gdbarch *gdbarch)
   /* Skip verify of read_core_file_mappings, invalid_p == 0.  */
   /* 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.  */
   if (!log.empty ())
     internal_error (_("verify_gdbarch: the following are invalid ...%s"),
                    log.c_str ());
@@ -1406,6 +1408,9 @@ gdbarch_dump (struct gdbarch *gdbarch, struct ui_file *file)
   gdb_printf (file,
              "gdbarch_dump: core_parse_exec_context = <%s>\n",
              host_address_to_string (gdbarch->core_parse_exec_context));
+  gdb_printf (file,
+             "gdbarch_dump: fetch_tdesc_parameter = <%s>\n",
+             host_address_to_string (gdbarch->fetch_tdesc_parameter));
   if (gdbarch->dump_tdep != NULL)
     gdbarch->dump_tdep (gdbarch, file);
 }
@@ -5551,3 +5556,20 @@ set_gdbarch_core_parse_exec_context (struct gdbarch *gdbarch,
 {
   gdbarch->core_parse_exec_context = core_parse_exec_context;
 }
+
+void
+gdbarch_fetch_tdesc_parameter (struct gdbarch *gdbarch, readable_regcache *regcache, unsigned int parameter_id)
+{
+  gdb_assert (gdbarch != NULL);
+  gdb_assert (gdbarch->fetch_tdesc_parameter != NULL);
+  if (gdbarch_debug >= 2)
+    gdb_printf (gdb_stdlog, "gdbarch_fetch_tdesc_parameter called\n");
+  gdbarch->fetch_tdesc_parameter (gdbarch, regcache, parameter_id);
+}
+
+void
+set_gdbarch_fetch_tdesc_parameter (struct gdbarch *gdbarch,
+                                  gdbarch_fetch_tdesc_parameter_ftype fetch_tdesc_parameter)
+{
+  gdbarch->fetch_tdesc_parameter = fetch_tdesc_parameter;
+}
index 313a8f198fdbcf5cc94d534d647bf4a3f5f6b07f..7371c400e5f59dbc9d00e110dd873826e3e46025 100644 (file)
@@ -1801,3 +1801,9 @@ extern void set_gdbarch_use_target_description_from_corefile_notes (struct gdbar
 typedef core_file_exec_context (gdbarch_core_parse_exec_context_ftype) (struct gdbarch *gdbarch, bfd *cbfd);
 extern core_file_exec_context gdbarch_core_parse_exec_context (struct gdbarch *gdbarch, bfd *cbfd);
 extern void set_gdbarch_core_parse_exec_context (struct gdbarch *gdbarch, gdbarch_core_parse_exec_context_ftype *core_parse_exec_context);
+
+/* Obtain or calculate target description parameter. */
+
+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);
index ec09d95508891855dd923a116e049b285a86797d..87694eb82b47906432993aa193d70cd1a0dd695e 100644 (file)
@@ -2848,3 +2848,17 @@ which all assume current_inferior() is the one to read from.
     predefault="default_core_parse_exec_context",
     invalid=False,
 )
+
+Method(
+    comment="""
+Obtain or calculate target description parameter.
+""",
+    type="void",
+    name="fetch_tdesc_parameter",
+    params=[
+        ("readable_regcache *", "regcache"),
+        ("unsigned int", "parameter_id"),
+    ],
+    predefault="default_fetch_tdesc_parameter",
+    invalid=False,
+)
index f2333d97ea78a521fc0bbb93b144754976e9c6b9..e6dd6d64e25b66d894302d324610aadc7779eb92 100644 (file)
@@ -1039,6 +1039,7 @@ create_static_range_type (type_allocator &alloc, struct type *index_type,
 
 static struct type *
 create_dynamic_range_type (type_allocator &alloc, struct type *index_type,
+                          ULONGEST element_length,
                           const char *parameter_feature,
                           const char *length_parameter)
 {
@@ -1046,12 +1047,12 @@ create_dynamic_range_type (type_allocator &alloc, struct type *index_type,
 
   low.set_const_val (0);
   // FIXME: Leaks memory.
-  std::pair<const char *, const char *> *parameter
-    = new std::pair<const char *, const char *>;
   // FIXME: Is the lifetime of the following strings longer than of this
   // object?
-  parameter->first = parameter_feature;
-  parameter->second = length_parameter;
+  std::tuple<const char *, const char *, ULONGEST> *parameter
+    = new std::tuple<const char *, const char *, ULONGEST> (parameter_feature,
+                                                           length_parameter,
+                                                           element_length);
   high.set_tdesc_parameter (parameter);
 
   return create_range_type (alloc, index_type, &low, &high, 0);
@@ -1449,7 +1450,8 @@ lookup_array_range_type (struct type *element_type,
   struct type *index_type, *range_type;
 
   index_type = builtin_type (element_type->arch ())->builtin_unsigned_int;
-  range_type = create_dynamic_range_type (alloc, index_type, parameter_feature,
+  range_type = create_dynamic_range_type (alloc, index_type, element_type->length (),
+                                         parameter_feature,
                                          length_parameter);
   return create_array_type (alloc, element_type, range_type);
 }
@@ -2256,6 +2258,19 @@ resolve_dynamic_range (struct type *dyn_range_type,
       if (dwarf2_evaluate_property (prop, frame, addr_stack, &value,
                                    { (CORE_ADDR) rank }))
        {
+         /* In the case of a vector with tdesc parameter in the range, we
+            should evaluate it to the number of elements in the vector.  */
+         if (prop->kind () == PROP_TDESC_PARAMETER)
+           {
+             ULONGEST element_length = std::get<ULONGEST> (prop->tdesc_parameter ());
+
+             if (element_length != ULONGEST_MAX)
+               value /= element_length;
+             value -= 1;
+
+             if (low_bound.kind () == PROP_CONST)
+               value += low_bound.const_val ();
+           }
          high_bound.set_const_val (value);
 
          if (dyn_range_type->bounds ()->flag_upper_bound_is_count)
index 98732614d365d4d239c78eb8cd678ff4c24ad669..3132e4478f092636344756ee31916a515a1bbce2 100644 (file)
@@ -299,9 +299,10 @@ union dynamic_prop_data
 
   const char *variable_name;
 
-  /* The first element is the feature name and the second is the parameter
-     name.  */
-  std::pair<const char *, const char *> *tdesc_parameter;
+  /* The first element is the feature name, the second is the parameter
+     name and the third is the size of an element in the vector,
+     or ULONGEST_MAX if it should be ignored.  */
+  std::tuple<const char *,const char *,ULONGEST> *tdesc_parameter;
 };
 
 /* * Used to store a dynamic property.  */
@@ -417,13 +418,13 @@ struct dynamic_prop
     m_data.variable_name = name;
   }
 
-  std::pair<const char *, const char *> tdesc_parameter () const
+  std::tuple<const char *,const char *,ULONGEST> tdesc_parameter () const
   {
     gdb_assert (m_kind == PROP_TDESC_PARAMETER);
     return *m_data.tdesc_parameter;
   }
 
-  void set_tdesc_parameter (std::pair<const char *,const char *> *parameter)
+  void set_tdesc_parameter (std::tuple<const char *,const char *,ULONGEST> *parameter)
   {
     m_kind = PROP_TDESC_PARAMETER;
     m_data.tdesc_parameter = parameter;
index 2a65be67382face287b8ea52d858993d4dfc966e..fb1a0d1597c3889df975a44b4ba31cc05d39913c 100644 (file)
@@ -31,6 +31,7 @@
 #include "gdbsupport/unordered_map.h"
 #include <unordered_map>
 #include "cli/cli-cmds.h"
+#include "target-descriptions.h"
 
 /*
  * DATA STRUCTURE
@@ -77,6 +78,12 @@ struct regcache_descr
 
   /* Cached table containing the type of each register.  */
   struct type **register_type = nullptr;
+
+  /* Offset of each target description parameter.  */
+  std::vector<long> tdesc_parameter_offset;
+
+  /* Size of target description parameters buffer.  */
+  long sizeof_tdesc_parameters = 0;
 };
 
 static const registry<gdbarch>::key<struct regcache_descr>
@@ -167,6 +174,16 @@ init_regcache_descr (struct gdbarch *gdbarch)
     descr->sizeof_fixed_size_cooked_registers = offset;
   }
 
+  /* Initialize list of target description parameter offsets.  */
+  long offset = 0;
+  descr->tdesc_parameter_offset.resize (tdesc_num_parameters (gdbarch));
+  for (i = 0; i < descr->tdesc_parameter_offset.size (); i++)
+    {
+      descr->tdesc_parameter_offset[i] = offset;
+      offset += tdesc_parameter_size (gdbarch, i);
+    }
+  descr->sizeof_tdesc_parameters = offset;
+
   return descr;
 }
 
@@ -311,6 +328,9 @@ reg_buffer::reg_buffer (gdbarch *gdbarch, bool has_pseudo)
       m_register_status.reset
        (new register_status[gdbarch_num_regs (gdbarch)] ());
     }
+
+  m_tdesc_parameter_status.resize (tdesc_num_parameters (gdbarch), REG_UNKNOWN);
+  m_tdesc_parameters.resize (m_descr->sizeof_tdesc_parameters, 0);
 }
 
 regcache::regcache (inferior *inf_for_target_calls, gdbarch *gdbarch)
@@ -380,6 +400,63 @@ reg_buffer::has_variable_size_registers ()
   return m_descr->has_variable_size_registers;
 }
 
+/* See regcache.h.  */
+
+gdb::array_view<gdb_byte>
+reg_buffer::tdesc_parameter_buffer (unsigned int param_id)
+{
+  gdb_assert (param_id < m_descr->tdesc_parameter_offset.size ());
+  gdb_byte *start;
+
+  start = &m_tdesc_parameters[m_descr->tdesc_parameter_offset[param_id]];
+
+  ULONGEST size = tdesc_parameter_size (m_descr->gdbarch, param_id);
+  return gdb::array_view<gdb_byte> (start, size);
+}
+
+/* See regcache.h.  */
+
+enum register_status
+reg_buffer::get_tdesc_parameter_status (unsigned int param_id) const
+{
+  gdb_assert (param_id < m_tdesc_parameter_status.size ());
+  return m_tdesc_parameter_status[param_id];
+}
+
+/* See regcache.h.  */
+
+void
+reg_buffer::invalidate_tdesc_parameter (unsigned int param_id)
+{
+  gdb_assert (param_id < m_tdesc_parameter_status.size ());
+  m_tdesc_parameter_status[param_id] = REG_UNKNOWN;
+}
+
+/* See regcache.h.  */
+
+void
+reg_buffer::supply_parameter (unsigned int param_id,
+                             gdb::array_view<const gdb_byte> src)
+{
+  gdb_assert (param_id < m_tdesc_parameter_status.size ());
+
+  gdb::array_view<gdb_byte> dst = tdesc_parameter_buffer (param_id);
+
+  if (src.data () != nullptr)
+    {
+      copy (src, dst);
+      m_tdesc_parameter_status[param_id] = REG_VALID;
+    }
+  else
+    {
+      /* This memset not strictly necessary, but better than garbage
+        in case the parameter value manages to escape somewhere (due
+        to a bug, no less).  */
+      memset (dst.data (), 0, dst.size ());
+      m_tdesc_parameter_status[param_id] = REG_UNAVAILABLE;
+    }
+}
+
 /* Helper for reg_buffer::register_buffer.  */
 
 template<typename ElemType>
@@ -1292,6 +1369,56 @@ readable_regcache::cooked_read_part (int regnum, int offset,
 
 /* See regcache.h.  */
 
+void
+readable_regcache::update_tdesc_parameter (unsigned int param_id)
+{
+  gdb_assert (param_id < m_tdesc_parameter_status.size ());
+
+  if (get_tdesc_parameter_status (param_id) == REG_UNKNOWN)
+    {
+      gdbarch_fetch_tdesc_parameter (m_descr->gdbarch, this, param_id);
+
+      if (m_tdesc_parameter_status[param_id] == REG_UNKNOWN)
+       m_tdesc_parameter_status[param_id] = REG_UNAVAILABLE;
+    }
+}
+
+/* See regcache.h.  */
+
+register_status
+readable_regcache::tdesc_parameter_value (unsigned int param_id,
+                                         gdb::array_view<gdb_byte> dst)
+{
+  gdb_assert (param_id < m_tdesc_parameter_status.size ());
+
+  ULONGEST size = tdesc_parameter_size (m_descr->gdbarch, param_id);
+  gdb_assert (dst.size () == size);
+
+  update_tdesc_parameter (param_id);
+
+  if (m_tdesc_parameter_status[param_id] == REG_VALID)
+    copy (tdesc_parameter_buffer (param_id), dst);
+  else
+    memset (dst.data (), 0, dst.size ());
+
+  return m_tdesc_parameter_status[param_id];
+}
+
+value *
+readable_regcache::tdesc_parameter_value (unsigned int param_id)
+{
+  value *result = value::allocate (tdesc_parameter_type (m_descr->gdbarch,
+                                                        param_id));
+
+  if (tdesc_parameter_value (param_id,
+                            result->contents_raw ()) == REG_UNAVAILABLE)
+    result->mark_bytes_unavailable (0, result->type ()->length ());
+
+  return result;
+}
+
+/* See regcache.h.  */
+
 void
 regcache::cooked_write_part (int regnum, int offset,
                             gdb::array_view<const gdb_byte> src)
index 1da162f2f7493fcebcc42d615c749e6b87bfebce..ce7362b65ef7d5fbd07b4af022222c3803ebb045 100644 (file)
@@ -271,6 +271,17 @@ public:
   /* See gdbsupport/common-regcache.h.  */
   int register_size (int regnum) const override;
 
+  /* FIXME: Document.
+     Assumes SRC contains an integer in target byte order.  */
+  void supply_parameter (unsigned int param_id,
+                        gdb::array_view<const gdb_byte> src);
+
+  /* FIXME: Document.  */
+  enum register_status get_tdesc_parameter_status (unsigned int param_id) const;
+
+  /* FIXME: Document.  */
+  void invalidate_tdesc_parameter (unsigned int param_id);
+
 protected:
   /* Assert on the range of REGNUM.  */
   void assert_regnum (int regnum) const;
@@ -287,6 +298,9 @@ protected:
   gdb::array_view<const gdb_byte> register_buffer (int regnum) const;
   gdb::array_view<gdb_byte> register_buffer (int regnum);
 
+  /* Return a view on target desc parameter PARAM_ID's buffer cache.  */
+  gdb::array_view<gdb_byte> tdesc_parameter_buffer (unsigned int param_id_id);
+
   /* Save a register cache.  The set of registers saved into the
      regcache determined by the save_reggroup.  COOKED_READ returns
      zero iff the register's value can't be returned.  */
@@ -314,6 +328,12 @@ protected:
   /* The offset of resolved types for variable-size registers (if any).  */
   std::vector<long> m_variable_size_register_offset;
 
+  /* The target description parameters buffers (if any).  */
+  std::vector<gdb_byte> m_tdesc_parameters;
+
+  /* Target description parameter cache status.  */
+  std::vector<register_status> m_tdesc_parameter_status;
+
   friend class regcache;
   friend class detached_regcache;
 };
@@ -369,6 +389,16 @@ public:
      will call mark_value_bytes_unavailable as appropriate.  */
   struct value *cooked_read_value (int regnum);
 
+  /* FIXME: Document.  */
+  void update_tdesc_parameter (unsigned int param_id);
+
+  /* FIXME: Document.  */
+  register_status tdesc_parameter_value (unsigned int param_id,
+                                        gdb::array_view<gdb_byte> dst);
+
+  /* FIXME: Document.  */
+  value *tdesc_parameter_value (unsigned int param_id);
+
 protected:
 
   /* Perform a partial register transfer using a read, modify, write
index 410a6f496b75daefced7848a1c099a9ae31a85bc..48131cc0a8e08ba97bd7371136d8b43ccc211286 100644 (file)
@@ -78,6 +78,16 @@ sentinel_frame_prev_arch (const frame_info_ptr &this_frame,
   return cache->regcache->arch ();
 }
 
+static value *
+sentinel_frame_prev_tdesc_parameter (const frame_info_ptr &this_frame,
+                                    void **this_prologue_cache,
+                                    unsigned int parameter)
+{
+  frame_unwind_cache *cache = (frame_unwind_cache *) *this_prologue_cache;
+
+  return cache->regcache->tdesc_parameter_value (parameter);
+}
+
 const struct frame_unwind_legacy sentinel_frame_unwind (
   "sentinel",
   SENTINEL_FRAME,
@@ -88,5 +98,6 @@ const struct frame_unwind_legacy sentinel_frame_unwind (
   NULL,
   NULL,
   NULL,
-  sentinel_frame_prev_arch
+  sentinel_frame_prev_arch,
+  sentinel_frame_prev_tdesc_parameter
 );
index aa0017a252fddb79ac73218d3428162d63e0edde..d1d55ad82902ec7f9545f95ac709c3177f48c778 100644 (file)
@@ -160,13 +160,15 @@ make_gdb_type (struct gdbarch *gdbarch, struct tdesc_type *ttype)
        return;
 
       type *element_gdb_type = make_gdb_type (m_gdbarch, e->element_type);
-      if (e->bitsize_parameter.length () == 0)
+      if (e->bitsize_parameter == nullptr)
        m_type = init_vector_type (element_gdb_type, e->count);
       else
        // FIXME: Is the lifetime of feature and tdesc_parameter correct?
-       // Probably not. e->name is duplicated below.
-       m_type = init_vector_type (element_gdb_type, e->feature.c_str (),
-                                  e->bitsize_parameter.c_str ());
+       // Probably not. e->name is duplicated below. OTOH, I think target
+       // descriptions and their associated objects are never destroyed.
+       m_type = init_vector_type (element_gdb_type,
+                                  e->bitsize_parameter->feature.c_str (),
+                                  e->bitsize_parameter->name.c_str ());
       m_type->set_name (xstrdup (e->name.c_str ()));
       return;
     }
@@ -427,6 +429,17 @@ struct tdesc_arch_reg
   struct type *type;
 };
 
+struct tdesc_arch_parameter
+{
+  tdesc_arch_parameter (const tdesc_parameter *parameter_)
+    : parameter (parameter_)
+  {}
+
+  const tdesc_parameter *parameter;
+
+  struct type *type = nullptr;
+};
+
 struct tdesc_arch_data
 {
   /* A list of register/type pairs, indexed by GDB's internal register number.
@@ -442,6 +455,8 @@ struct tdesc_arch_data
   gdbarch_register_name_ftype *pseudo_register_name = NULL;
   gdbarch_register_type_ftype *pseudo_register_type = NULL;
   gdbarch_register_reggroup_p_ftype *pseudo_register_reggroup_p = NULL;
+
+  std::vector<tdesc_arch_parameter> parameters;
 };
 
 /* A handle for architecture-specific data associated with the
@@ -687,6 +702,106 @@ tdesc_feature_name (const struct tdesc_feature *feature)
   return feature->name.c_str ();
 }
 
+/* See target-descriptions.h.  */
+
+std::optional<unsigned int>
+tdesc_parameter_id (gdbarch *gdbarch, const char *feature,
+                   const char *param_name)
+{
+  struct tdesc_arch_data *data = get_arch_data (gdbarch);
+
+  for (int i = 0; i < data->parameters.size (); i++)
+    {
+      const tdesc_arch_parameter &arch_param = data->parameters[i];
+      if (arch_param.parameter->feature == feature
+         && arch_param.parameter->name == param_name)
+       return i;
+    }
+
+  return {};
+}
+
+/* See target-descriptions.h.  */
+
+const tdesc_parameter *
+tdesc_feature_parameter (const tdesc_feature &feature, const char *parameter)
+{
+  for (int i = 0; i < feature.parameters.size (); i++)
+    if (feature.parameters[i]->name == parameter)
+      return feature.parameters[i].get ();
+
+  return nullptr;
+}
+
+/* See target-descriptions.h.  */
+
+std::optional<std::pair<const char *,const char *>>
+tdesc_parameter_name (gdbarch *gdbarch, unsigned int param_id)
+{
+  struct tdesc_arch_data *data = get_arch_data (gdbarch);
+
+  if (param_id < data->parameters.size ())
+    {
+      const tdesc_arch_parameter &param = data->parameters[param_id];
+      return std::pair<const char *,const char *>
+       { param.parameter->feature.c_str (), param.parameter->name.c_str () };
+    }
+  else
+    return {};
+}
+
+/* See target-descriptions.h.  */
+
+type *
+tdesc_parameter_type (gdbarch *gdbarch, unsigned int param_id)
+{
+  tdesc_arch_data *data = get_arch_data (gdbarch);
+
+  gdb_assert (param_id < data->parameters.size ());
+  tdesc_arch_parameter &arch_parameter = data->parameters[param_id];
+  const tdesc_parameter *parameter = arch_parameter.parameter;
+
+  if (arch_parameter.type == nullptr)
+    {
+      arch_parameter.type = make_gdb_type (gdbarch, parameter->type);
+      if (arch_parameter.type == nullptr)
+       internal_error ("Register \"%s\" has an unknown type \"%s\"",
+                       parameter->name.c_str (),
+                       parameter->type->name.c_str ());
+    }
+
+  return arch_parameter.type;
+}
+
+/* See target-descriptions.h.  */
+
+ULONGEST
+tdesc_parameter_size (gdbarch *gdbarch, unsigned int param_id)
+{
+  return tdesc_parameter_type (gdbarch, param_id)->length ();
+}
+
+unsigned int
+tdesc_num_parameters (gdbarch *gdbarch)
+{
+  return get_arch_data (gdbarch)->parameters.size ();
+}
+
+/* See target-descriptions.h.  */
+
+void
+tdesc_setup_parameters (gdbarch *gdbarch, const target_desc *target_desc)
+{
+  struct tdesc_arch_data *data = get_arch_data (gdbarch);
+
+  /* Ensure this is done only once.  */
+  gdb_assert (data->parameters.size () == 0);
+
+  for (const tdesc_feature_up &feature : target_desc->features)
+    for (const tdesc_parameter_up &parameter: feature->parameters)
+      data->parameters.emplace_back (parameter.get ());
+}
+
 /* Lookup type associated with ID.  */
 
 struct type *
@@ -1367,10 +1482,10 @@ public:
     gdb_printf
       ("  element_type = tdesc_named_type (feature, \"%s\");\n",
        type->element_type->name.c_str ());
-    if (type->bitsize_parameter.length () != 0)
+    if (type->bitsize_parameter != nullptr)
       gdb_printf
-       ("  tdesc_create_vector (feature, \"%s\", element_type, \"%s\");\n",
-        type->name.c_str (), type->bitsize_parameter.c_str ());
+       ("  tdesc_create_vector (feature, \"%s\", element_type, param_%s);\n",
+        type->name.c_str (), type->bitsize_parameter->name.c_str ());
     else
       gdb_printf
        ("  tdesc_create_vector (feature, \"%s\", element_type, %d);\n",
@@ -1494,11 +1609,26 @@ public:
       gdb_printf ("\"%s\", ", reg->group.c_str ());
     else
       gdb_printf ("NULL, ");
-    if (reg->bitsize_parameter.length () != 0)
-      gdb_printf ("\"%s\", \"%s\");\n", reg->bitsize_parameter.c_str (),
-                 reg->type.c_str ());
+    if (reg->bitsize_parameter != nullptr)
+      gdb_printf ("param_%s, ", reg->bitsize_parameter->name.c_str ());
     else
-      gdb_printf ("%d, \"%s\");\n", reg->bitsize, reg->type.c_str ());
+      gdb_printf ("%d, ", reg->bitsize);
+    gdb_printf ("\"%s\");\n", reg->type.c_str ());
+  }
+
+  void visit (const tdesc_parameter *p) override
+  {
+    if (!m_printed_param_type)
+      {
+       gdb_printf ("  tdesc_type *param_type;\n");
+       m_printed_param_type = true;
+      }
+
+    gdb_printf ("  param_type = tdesc_named_type (feature, \"%s\");\n",
+               p->type->name.c_str ());
+    gdb_printf
+      ("  const tdesc_parameter &param_%s = tdesc_create_parameter (*feature, \"%s\", param_type);\n",
+       p->name.c_str (), p->name.c_str ());
   }
 
 protected:
@@ -1535,6 +1665,9 @@ private:
 
   /* Did we print "struct tdesc_type *field_type;" yet?  */
   bool m_printed_field_type = false;
+
+  /* Did we print "struct tdesc_type *param_type;" yet?  */
+  bool m_printed_param_type = false;
 };
 
 /* Print target description feature in C.  */
@@ -1641,11 +1774,11 @@ public:
       gdb_printf ("\"%s\", ", reg->group.c_str ());
     else
       gdb_printf ("NULL, ");
-    if (reg->bitsize_parameter.length () != 0)
-      gdb_printf ("\"%s\", \"%s\");\n", reg->bitsize_parameter.c_str (),
-                 reg->type.c_str ());
+    if (reg->bitsize_parameter != nullptr)
+      gdb_printf ("param_%s, ", reg->bitsize_parameter->name.c_str ());
     else
-      gdb_printf ("%d, \"%s\");\n", reg->bitsize, reg->type.c_str ());
+      gdb_printf ("%d, ", reg->bitsize);
+    gdb_printf ("\"%s\");\n", reg->type.c_str ());
 
     m_next_regnum++;
   }
index 7481c87a4e9ccb63e84ea59150e0df3cade88e7b..494d04ec702e99d76e52d5dcf6d77f6b9530faf3 100644 (file)
@@ -194,6 +194,39 @@ const struct tdesc_feature *tdesc_find_feature (const struct target_desc *,
 
 const char *tdesc_feature_name (const struct tdesc_feature *feature);
 
+/* FIXME: Document.  */
+
+std::optional<unsigned int> tdesc_parameter_id (gdbarch *gdbarch,
+                                               const char *feature,
+                                               const char *param_name);
+
+/* FIXME: Document.  */
+
+const tdesc_parameter *tdesc_feature_parameter (const tdesc_feature &feature,
+                                               const char *parameter);
+
+/* FIXME: Document.  */
+
+std::optional<std::pair<const char *,const char *>> tdesc_parameter_name
+  (gdbarch *gdbarch, unsigned int param_id);
+
+/* FIXME: Document.  */
+
+type *tdesc_parameter_type (gdbarch *gdbarch, unsigned int param_id);
+
+/* FIXME: Document.  */
+
+ULONGEST tdesc_parameter_size (gdbarch *gdbarch, unsigned int param_id);
+
+/* FIXME: Document.  */
+
+unsigned int tdesc_num_parameters (gdbarch *gdbarch);
+
+/* Update TARGET_DESC to use parameters with GDBARCH.  */
+
+void tdesc_setup_parameters (struct gdbarch *gdbarch,
+                            const struct target_desc *target_desc);
+
 /* Return the name of register REGNO, from the target description or
    from an architecture-provided pseudo_register_name method.  */
 
index 64aef110e7e05ecbee4304ed40b8d98247df05b4..9b740649de38bb6cc87b287d09091948aa9eef66 100644 (file)
@@ -213,9 +213,17 @@ tdesc_start_reg (struct gdb_xml_parser *parser,
 
   if (bitsize_attr[0] == '$')
     {
-      // FIXME: Check whether the bitsize parameter is valid.
+      const char *parameter_name = &bitsize_attr[1];
+      const tdesc_parameter *parameter
+       = tdesc_feature_parameter (*data->current_feature, parameter_name);
+
+      if (parameter == nullptr)
+       gdb_xml_error (parser,
+                      _("Register bitsize references non-existent parameter \"%s\""),
+                      parameter_name);
+
       tdesc_create_reg (data->current_feature, name, regnum, save_restore,
-                       group, &bitsize_attr[1], type);
+                       group, *parameter, type);
     }
   else
     {
@@ -508,17 +516,50 @@ tdesc_start_vector (struct gdb_xml_parser *parser,
     }
   else if (!strcmp (attributes[2].name, "bitsize"))
     {
-      char *bitsize = (char *) attributes[2].value.get ();
+      const char *bitsize = (const char *) attributes[2].value.get ();
 
       if (bitsize[0] != '$')
-       gdb_xml_error (parser, _ ("Vector bitsize \"%s\" isn't a parameter"),
+       gdb_xml_error (parser, _("Vector bitsize \"%s\" isn't a parameter"),
                       bitsize);
 
-      // FIXME: Check whether the parameter exists.
-      tdesc_create_vector (data->current_feature, id, field_type, &bitsize[1]);
+      const char *parameter_name = &bitsize[1];
+      const tdesc_parameter *parameter
+       = tdesc_feature_parameter (*data->current_feature, parameter_name);
+
+      if (parameter == nullptr)
+       gdb_xml_error (parser,
+                      _("Vector bitsize references non-existent parameter \"%s\""),
+                      parameter_name);
+
+      tdesc_create_vector (data->current_feature, id, field_type, *parameter);
     }
   else
-    gdb_xml_error (parser, _ ("Vector doesn't have count nor size attribute"));
+    gdb_xml_error (parser, _("Vector doesn't have count nor bitsize attribute"));
+}
+
+/* Handle the start of a <parameter> element.  Initialize the type and
+   record it with the current feature.  */
+
+static void
+tdesc_start_parameter (struct gdb_xml_parser *parser,
+                      const struct gdb_xml_element *element, void *user_data,
+                      std::vector<gdb_xml_value> &attributes)
+{
+  struct tdesc_parsing_data *data = (struct tdesc_parsing_data *) user_data;
+
+  const char *name = (const char *) attributes[0].value.get ();
+  const char *type_id = (const char *) attributes[1].value.get ();
+
+  tdesc_type *type = tdesc_named_type (data->current_feature, type_id);
+  if (type == nullptr)
+    gdb_xml_error (parser, _("Parameter \"%s\" references undefined type \"%s\""),
+                  name, type_id);
+
+  if (data->current_feature->has_parameter (name))
+    gdb_xml_error (parser, _("Parameter \"%s\" duplicated in feature \"%s\""),
+                  name, data->current_feature->name.c_str ());
+
+  tdesc_create_parameter (*data->current_feature, name, type);
 }
 
 /* The elements and attributes of an XML target description.  */
@@ -586,6 +627,12 @@ static const struct gdb_xml_attribute vector_attributes[] = {
   { NULL, GDB_XML_AF_NONE, NULL, NULL }
 };
 
+static const struct gdb_xml_attribute parameter_attributes[] = {
+  { "name", GDB_XML_AF_NONE, NULL, NULL },
+  { "type", GDB_XML_AF_NONE, NULL, NULL },
+  { NULL, GDB_XML_AF_NONE, NULL, NULL }
+};
+
 static const struct gdb_xml_attribute feature_attributes[] = {
   { "name", GDB_XML_AF_NONE, NULL, NULL },
   { NULL, GDB_XML_AF_NONE, NULL, NULL }
@@ -610,6 +657,9 @@ static const struct gdb_xml_element feature_children[] = {
   { "vector", vector_attributes, NULL,
     GDB_XML_EF_OPTIONAL | GDB_XML_EF_REPEATABLE,
     tdesc_start_vector, NULL },
+  { "parameter", parameter_attributes, NULL,
+    GDB_XML_EF_OPTIONAL | GDB_XML_EF_REPEATABLE,
+    tdesc_start_parameter, NULL },
   { NULL, NULL, NULL, GDB_XML_EF_NONE, NULL, NULL }
 };
 
index 186354aef8512b7838df6f90bd298cbb5bc8bc72..f332c79be3b94a61269a6a0ef48f7fd742396fdf 100644 (file)
@@ -35,18 +35,18 @@ tdesc_reg::tdesc_reg (struct tdesc_feature *feature, const std::string &name_,
 
 tdesc_reg::tdesc_reg (struct tdesc_feature *feature_, const std::string &name_,
                      int regnum, int save_restore_, const char *group_,
-                     const std::string &bitsize_parameter_, const char *type_)
+                     const tdesc_parameter &bitsize_parameter_,
+                     const char *type_)
   : name (name_), target_regnum (regnum),
     save_restore (save_restore_),
     group (group_ != NULL ? group_ : ""),
     bitsize (TDESC_REG_VARIABLE_SIZE),
-    bitsize_parameter (bitsize_parameter_),
+    bitsize_parameter (&bitsize_parameter_),
     type (type_ != NULL ? type_ : "<unknown>")
 {
   /* If the register's type is target-defined, look it up now.  We may not
      have easy access to the containing feature when we want it later.  */
   tdesc_type = tdesc_named_type (feature_, type.c_str ());
-  feature = feature_->name;
 }
 
 /* Predefined types.  */
@@ -77,6 +77,9 @@ void tdesc_feature::accept (tdesc_element_visitor &v) const
 {
   v.visit_pre (this);
 
+  for (const tdesc_parameter_up &parameter : parameters)
+    parameter->accept (v);
+
   for (const tdesc_type_up &type : types)
     type->accept (v);
 
@@ -150,6 +153,32 @@ tdesc_named_type (const struct tdesc_feature *feature, const char *id)
 
 /* See gdbsupport/tdesc.h.  */
 
+bool
+tdesc_feature::has_parameter (const char *parameter) const
+{
+  for (int i = 0; i < this->parameters.size (); i++)
+    if (this->parameters[i]->name == parameter)
+      return true;
+
+  return false;
+}
+
+/* See gdbsupport/tdesc.h.  */
+
+const tdesc_parameter &
+tdesc_create_parameter (tdesc_feature &feature, const char *parameter,
+                       tdesc_type *type)
+{
+  gdb_assert (!feature.has_parameter (parameter));
+
+  feature.parameters.emplace_back (new tdesc_parameter (feature.name,
+                                                       parameter, type));
+
+  return *feature.parameters.back ().get ();
+}
+
+/* See gdbsupport/tdesc.h.  */
+
 void
 tdesc_create_reg (struct tdesc_feature *feature, const char *name,
                  int regnum, int save_restore, const char *group,
@@ -166,7 +195,7 @@ tdesc_create_reg (struct tdesc_feature *feature, const char *name,
 void
 tdesc_create_reg (struct tdesc_feature *feature, const char *name,
                  int regnum, int save_restore, const char *group,
-                 const char *bitsize_parameter, const char *type)
+                 const tdesc_parameter &bitsize_parameter, const char *type)
 {
   tdesc_reg *reg = new tdesc_reg (feature, name, regnum, save_restore,
                                  group, bitsize_parameter, type);
@@ -191,10 +220,9 @@ tdesc_create_vector (struct tdesc_feature *feature, const char *name,
 struct tdesc_type *
 tdesc_create_vector (struct tdesc_feature *feature, const char *name,
                     struct tdesc_type *field_type,
-                    const char *bitsize_parameter)
+                    const tdesc_parameter &bitsize_parameter)
 {
   tdesc_type_vector *type = new tdesc_type_vector (name, field_type,
-                                                  feature->name,
                                                   bitsize_parameter);
   feature->types.emplace_back (type);
 
@@ -355,9 +383,9 @@ void print_xml_feature::visit (const tdesc_type_builtin *t)
 
 void print_xml_feature::visit (const tdesc_type_vector *t)
 {
-  if (t->bitsize_parameter.length () != 0)
+  if (t->bitsize_parameter != nullptr)
     add_line ("<vector id=\"%s\" type=\"%s\" bitsize=\"$%s\"/>", t->name.c_str (),
-             t->element_type->name.c_str (), t->bitsize_parameter.c_str ());
+             t->element_type->name.c_str (), t->bitsize_parameter->name.c_str ());
   else
     add_line ("<vector id=\"%s\" type=\"%s\" count=\"%d\"/>", t->name.c_str (),
              t->element_type->name.c_str (), t->count);
@@ -429,10 +457,10 @@ void print_xml_feature::visit (const tdesc_reg *r)
 {
   std::string tmp;
 
-  if (r->bitsize_parameter.length () != 0)
+  if (r->bitsize_parameter != nullptr)
     string_appendf (tmp,
                    "<reg name=\"%s\" bitsize=\"$%s\" type=\"%s\" regnum=\"%ld\"",
-                   r->name.c_str (), r->bitsize_parameter.c_str(),
+                   r->name.c_str (), r->bitsize_parameter->name.c_str(),
                    r->type.c_str (), r->target_regnum);
   else
     string_appendf (tmp,
@@ -480,6 +508,12 @@ void print_xml_feature::visit_post (const target_desc *e)
   add_line ("</target>");
 }
 
+void print_xml_feature::visit (const tdesc_parameter *p)
+{
+  add_line ("<parameter name=\"%s\" type=\"%s\"/>", p->name.c_str (),
+           p->type->name.c_str ());
+}
+
 /* See gdbsupport/tdesc.h.  */
 
 void
index 4ecee683e0988193adf67f997365042ecd3ce603..b7b8bca5c10a2b94a6fe1223ca3b4ea23f656f7b 100644 (file)
@@ -26,6 +26,7 @@ struct tdesc_type_builtin;
 struct tdesc_type_vector;
 struct tdesc_type_with_fields;
 struct tdesc_reg;
+struct tdesc_parameter;
 struct target_desc;
 
 /* The interface to visit different elements of target description.  */
@@ -56,6 +57,9 @@ public:
 
   virtual void visit (const tdesc_reg *e)
   {}
+
+  virtual void visit (const tdesc_parameter *e)
+  {}
 };
 
 class tdesc_element
@@ -79,7 +83,7 @@ struct tdesc_reg : tdesc_element
 
   tdesc_reg (struct tdesc_feature *feature, const std::string &name_,
             int regnum, int save_restore_, const char *group_,
-            const std::string &bitsize_parameter_, const char *type_);
+            const tdesc_parameter &bitsize_parameter_, const char *type_);
 
   virtual ~tdesc_reg () = default;
 
@@ -109,10 +113,11 @@ struct tdesc_reg : tdesc_element
   std::string group;
 
   /* The size of the register, in bits.
-     Ignored if BITSIZE_PARAMETER isn't empty.  */
+     Ignored if BITSIZE_PARAMETER isn't nullptr.  */
   int bitsize;
 
-  std::string feature, bitsize_parameter;
+  /* FIXME: Document.  */
+  const tdesc_parameter *bitsize_parameter = nullptr;
 
   /* The type of the register.  This string corresponds to either
      a named type from the target description or a predefined
@@ -134,6 +139,7 @@ struct tdesc_reg : tdesc_element
        && save_restore == other.save_restore
        && bitsize == other.bitsize
        && group == other.group
+       && bitsize_parameter == other.bitsize_parameter
        && type == other.type);
   }
 
@@ -203,6 +209,9 @@ struct tdesc_type : tdesc_element
     : name (name_), kind (kind_)
   {}
 
+  tdesc_type (tdesc_type &&other)
+  { *this = std::move (other); }
+
   virtual ~tdesc_type () = default;
 
   DISABLE_COPY_AND_ASSIGN (tdesc_type);
@@ -222,10 +231,78 @@ struct tdesc_type : tdesc_element
   {
     return !(*this == other);
   }
+
+  tdesc_type &operator= (tdesc_type &&other)
+  {
+    this->name = std::move (other.name);
+    this->kind = other.kind;
+    return *this;
+  }
 };
 
 typedef std::unique_ptr<tdesc_type> tdesc_type_up;
 
+/* A parameter from a target description.  */
+
+struct tdesc_parameter : tdesc_element
+{
+  tdesc_parameter (const std::string &feature_, const std::string &name_,
+                  tdesc_type *type_)
+    : feature (feature_), name (name_), type (type_)
+  {}
+
+  tdesc_parameter (tdesc_parameter &&other)
+    : type (other.type)
+  {
+    *this = std::move (other);
+  }
+
+  virtual ~tdesc_parameter () = default;
+
+  DISABLE_COPY_AND_ASSIGN (tdesc_parameter);
+
+  /* FIXME: Document.  */
+  std::string feature;
+
+  /* The name of this parameter.  In standard features, it may be
+     recognized by the architecture support code.  */
+  std::string name;
+
+  /* The type of the parameter.  */
+  tdesc_type *type;
+
+  void accept (tdesc_element_visitor &v) const override
+  {
+    v.visit (this);
+  }
+
+  bool operator== (const tdesc_parameter &other) const
+  {
+    return (name == other.name
+           && feature == other.feature
+           && type == other.type);
+  }
+
+  bool operator!= (const tdesc_parameter &other) const
+  {
+    return !(*this == other);
+  }
+
+  tdesc_parameter &operator= (tdesc_parameter &&other)
+  {
+    if (this != &other)
+      {
+       this->feature = std::move (other.feature);
+       this->name = std::move (other.name);
+       this->type = other.type;
+      }
+
+    return *this;
+  }
+};
+
+typedef std::unique_ptr<tdesc_parameter> tdesc_parameter_up;
+
 struct tdesc_type_builtin : tdesc_type
 {
   tdesc_type_builtin (const std::string &name, enum tdesc_type_kind kind)
@@ -245,15 +322,13 @@ struct tdesc_type_vector : tdesc_type
   tdesc_type_vector (const std::string &name, tdesc_type *element_type_,
                     int count_)
   : tdesc_type (name, TDESC_TYPE_VECTOR),
-    element_type (element_type_), count (count_)
+    element_type (element_type_), count (count_), bitsize_parameter (nullptr)
   {}
 
   tdesc_type_vector (const std::string &name, tdesc_type *element_type_,
-                    const std::string &feature_,
-                    const std::string &bitsize_parameter_)
+                    const tdesc_parameter &bitsize_parameter_)
       : tdesc_type (name, TDESC_TYPE_VECTOR), element_type (element_type_),
-       count (TDESC_REG_VARIABLE_SIZE), feature (feature_),
-       bitsize_parameter (bitsize_parameter_)
+       count (TDESC_REG_VARIABLE_SIZE), bitsize_parameter (&bitsize_parameter_)
   {}
 
   void accept (tdesc_element_visitor &v) const override
@@ -263,11 +338,11 @@ struct tdesc_type_vector : tdesc_type
 
   struct tdesc_type *element_type;
 
-  /* Ignored if BITSIZE_PARAMETER isn't empty. */
+  /* Ignored if BITSIZE_PARAMETER isn't nullptr. */
   int count;
 
   /* Target description parameter  providing total vector size.  */
-  std::string feature, bitsize_parameter;
+  const tdesc_parameter *bitsize_parameter;
 };
 
 /* A named type from a target description.  */
@@ -328,8 +403,13 @@ struct tdesc_feature : tdesc_element
   /* The types associated with this feature.  */
   std::vector<tdesc_type_up> types;
 
+  /* Paremeters defined in this feature.  */
+  std::vector<tdesc_parameter_up> parameters;
+
   void accept (tdesc_element_visitor &v) const override;
 
+  bool has_parameter (const char *parameter) const;
+
   bool operator== (const tdesc_feature &other) const;
 
   bool operator!= (const tdesc_feature &other) const
@@ -392,7 +472,7 @@ struct tdesc_type *tdesc_create_vector (struct tdesc_feature *feature,
 struct tdesc_type *tdesc_create_vector (struct tdesc_feature *feature,
                                        const char *name,
                                        struct tdesc_type *field_type,
-                                       const char *bitsize_parameter);
+                                       const tdesc_parameter &bitsize_parameter);
 
 /* Return the created struct tdesc_type named NAME in FEATURE.  */
 tdesc_type_with_fields *tdesc_create_struct (struct tdesc_feature *feature,
@@ -453,7 +533,20 @@ void tdesc_create_reg (struct tdesc_feature *feature, const char *name,
    BITSIZE_PARAMETER.  */
 void tdesc_create_reg (struct tdesc_feature *feature, const char *name,
                       int regnum, int save_restore, const char *group,
-                      const char *bitsize_parameter, const char *type);
+                      const tdesc_parameter &bitsize_parameter,
+                      const char *type);
+
+/* Return internal ID of PARAMETER from FEATURE.  */
+
+std::optional<unsigned int> tdesc_parameter_id (const target_desc *target_desc,
+                                               const char *feature,
+                                               const char *parameter);
+
+/* Add PARAMETER to FEATURE.  */
+
+const tdesc_parameter & tdesc_create_parameter (tdesc_feature &feature,
+                                               const char *parameter,
+                                               tdesc_type *type);
 
 /* Return the tdesc in string XML format.  */
 
@@ -477,6 +570,7 @@ public:
   void visit (const tdesc_type_vector *type) override;
   void visit (const tdesc_type_with_fields *type) override;
   void visit (const tdesc_reg *reg) override;
+  void visit (const tdesc_parameter *p) override;
 
 private: