]> git.ipfire.org Git - thirdparty/binutils-gdb.git/commitdiff
Beginning of support for target description parameters
authorThiago Jung Bauermann <thiago.bauermann@linaro.org>
Mon, 14 Apr 2025 22:40:23 +0000 (19:40 -0300)
committerThiago Jung Bauermann <thiago.bauermann@linaro.org>
Sat, 19 Apr 2025 01:30:01 +0000 (22:30 -0300)
With this commit, it's possible to reference to a parameter in a bitsize
attribute in a <reg/> or <vector/> element.

It's not possible yet to declare parameters in a feature, nor to create a
a functioning target description with them yet.

The parameter is stored in a dynamic_prop and used to define a dynamic
range for an array.  GDB can't yet resolve the dynamic type.

gdb/features/gdb-target.dtd
gdb/gdbtypes.c
gdb/gdbtypes.h
gdb/target-descriptions.c
gdb/xml-tdesc.c
gdbsupport/tdesc.cc
gdbsupport/tdesc.h

index 2ecc41eb1fa28c928a89ab6b6956721c7cf39d66..f619573f2412e8420129156c8b9f6afefb548341 100644 (file)
@@ -38,7 +38,8 @@
 <!ATTLIST vector
        id              CDATA   #REQUIRED
        type            CDATA   #REQUIRED
-       count           CDATA   #REQUIRED>
+       count           CDATA   #IMPLIED
+       bitsize         CDATA   #IMPLIED>
 
 <!ELEMENT flags                (field+)>
 <!ATTLIST flags
index 5713eac7ffed39dddd7bdcf5fcc3d08641c00269..f2333d97ea78a521fc0bbb93b144754976e9c6b9 100644 (file)
@@ -1031,6 +1031,32 @@ create_static_range_type (type_allocator &alloc, struct type *index_type,
   return result_type;
 }
 
+/* Create a range type using ALLOC.
+
+   Indices will be of type INDEX_TYPE, and will range from 0 to the value
+   calculated from the array length given by the given target description
+   parameter.  */
+
+static struct type *
+create_dynamic_range_type (type_allocator &alloc, struct type *index_type,
+                          const char *parameter_feature,
+                          const char *length_parameter)
+{
+  struct dynamic_prop low, high;
+
+  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;
+  high.set_tdesc_parameter (parameter);
+
+  return create_range_type (alloc, index_type, &low, &high, 0);
+}
+
 /* Predicate tests whether BOUNDS are static.  Returns 1 if all bounds values
    are static, otherwise returns 0.  */
 
@@ -1410,6 +1436,24 @@ lookup_array_range_type (struct type *element_type,
   return create_array_type (alloc, element_type, range_type);
 }
 
+/* Create type for array ranges where the low bound is 0 and the high bound is
+   calculated from the array length found in the given target description
+   parameter.  */
+
+static struct type *
+lookup_array_range_type (struct type *element_type,
+                        const char *parameter_feature,
+                        const char *length_parameter)
+{
+  type_allocator alloc (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,
+                                         length_parameter);
+  return create_array_type (alloc, element_type, range_type);
+}
+
 /* See gdbtypes.h.  */
 
 struct type *
@@ -1498,6 +1542,20 @@ init_vector_type (struct type *elt_type, int n)
   return array_type;
 }
 
+/* Create vector type of elements of type ELT_TYPE, where its total length is
+   given by the given target description parameter.  */
+
+struct type *
+init_vector_type (struct type *elt_type, const char *parameter_feature,
+                 const char *length_parameter)
+{
+  struct type *array_type = lookup_array_range_type (elt_type,
+                                                    parameter_feature,
+                                                    length_parameter);
+  make_vector_type (array_type);
+  return array_type;
+}
+
 /* Internal routine called by TYPE_SELF_TYPE to return the type that TYPE
    belongs to.  In c++ this is the class of "this", but TYPE_THIS_TYPE is too
    confusing.  "self" is a common enough replacement for "this".
index 5ee9deb07ad1c4e497ed7047e0d6b1192e007723..98732614d365d4d239c78eb8cd678ff4c24ad669 100644 (file)
@@ -266,6 +266,7 @@ enum dynamic_prop_kind
   PROP_TYPE,      /* Type.  */
   PROP_VARIABLE_NAME, /* Variable name.  */
   PROP_OPTIMIZED_OUT, /* Optimized out.  */
+  PROP_TDESC_PARAMETER, /* Parameter from target description.  */
 };
 
 union dynamic_prop_data
@@ -297,6 +298,10 @@ union dynamic_prop_data
      this property.  */
 
   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;
 };
 
 /* * Used to store a dynamic property.  */
@@ -412,6 +417,18 @@ struct dynamic_prop
     m_data.variable_name = name;
   }
 
+  std::pair<const char *, const char *> 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)
+  {
+    m_kind = PROP_TDESC_PARAMETER;
+    m_data.tdesc_parameter = parameter;
+  }
+
   /* Determine which field of the union dynamic_prop.data is used.  */
   enum dynamic_prop_kind m_kind;
 
@@ -2421,6 +2438,9 @@ extern void append_flags_type_flag (struct type *type, int bitpos,
 
 extern void make_vector_type (struct type *array_type);
 extern struct type *init_vector_type (struct type *elt_type, int n);
+extern struct type *init_vector_type (struct type *elt_type,
+                                     const char *parameter_feature,
+                                     const char *length_parameter);
 
 extern struct type *lookup_reference_type (struct type *, enum type_code);
 extern struct type *lookup_lvalue_reference_type (struct type *);
index 8042d25d89381703e00623d9fc1416e1cf89cc9d..aa0017a252fddb79ac73218d3428162d63e0edde 100644 (file)
@@ -160,7 +160,13 @@ make_gdb_type (struct gdbarch *gdbarch, struct tdesc_type *ttype)
        return;
 
       type *element_gdb_type = make_gdb_type (m_gdbarch, e->element_type);
-      m_type = init_vector_type (element_gdb_type, e->count);
+      if (e->bitsize_parameter.length () == 0)
+       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 ());
       m_type->set_name (xstrdup (e->name.c_str ()));
       return;
     }
@@ -1361,9 +1367,14 @@ public:
     gdb_printf
       ("  element_type = tdesc_named_type (feature, \"%s\");\n",
        type->element_type->name.c_str ());
-    gdb_printf
-      ("  tdesc_create_vector (feature, \"%s\", element_type, %d);\n",
-       type->name.c_str (), type->count);
+    if (type->bitsize_parameter.length () != 0)
+      gdb_printf
+       ("  tdesc_create_vector (feature, \"%s\", element_type, \"%s\");\n",
+        type->name.c_str (), type->bitsize_parameter.c_str ());
+    else
+      gdb_printf
+       ("  tdesc_create_vector (feature, \"%s\", element_type, %d);\n",
+        type->name.c_str (), type->count);
 
     gdb_printf ("\n");
   }
@@ -1483,7 +1494,11 @@ public:
       gdb_printf ("\"%s\", ", reg->group.c_str ());
     else
       gdb_printf ("NULL, ");
-    gdb_printf ("%d, \"%s\");\n", reg->bitsize, reg->type.c_str ());
+    if (reg->bitsize_parameter.length () != 0)
+      gdb_printf ("\"%s\", \"%s\");\n", reg->bitsize_parameter.c_str (),
+                 reg->type.c_str ());
+    else
+      gdb_printf ("%d, \"%s\");\n", reg->bitsize, reg->type.c_str ());
   }
 
 protected:
@@ -1626,7 +1641,11 @@ public:
       gdb_printf ("\"%s\", ", reg->group.c_str ());
     else
       gdb_printf ("NULL, ");
-    gdb_printf ("%d, \"%s\");\n", reg->bitsize, reg->type.c_str ());
+    if (reg->bitsize_parameter.length () != 0)
+      gdb_printf ("\"%s\", \"%s\");\n", reg->bitsize_parameter.c_str (),
+                 reg->type.c_str ());
+    else
+      gdb_printf ("%d, \"%s\");\n", reg->bitsize, reg->type.c_str ());
 
     m_next_regnum++;
   }
index 6c095afa699895f03be538259419070ee3f1e00c..64aef110e7e05ecbee4304ed40b8d98247df05b4 100644 (file)
@@ -176,14 +176,14 @@ tdesc_start_reg (struct gdb_xml_parser *parser,
 {
   struct tdesc_parsing_data *data = (struct tdesc_parsing_data *) user_data;
   int ix = 0;
-  char *name, *group;
+  char *name, *group, *bitsize_attr;
   const char *type;
-  int bitsize, regnum, save_restore;
+  int regnum, save_restore;
 
   int length = attributes.size ();
 
   name = (char *) attributes[ix++].value.get ();
-  bitsize = * (ULONGEST *) attributes[ix++].value.get ();
+  bitsize_attr = (char *) attributes[ix++].value.get ();
 
   if (ix < length && strcmp (attributes[ix].name, "regnum") == 0)
     regnum = * (ULONGEST *) attributes[ix++].value.get ();
@@ -211,8 +211,19 @@ tdesc_start_reg (struct gdb_xml_parser *parser,
     gdb_xml_error (parser, _("Register \"%s\" has unknown type \"%s\""),
                   name, type);
 
-  tdesc_create_reg (data->current_feature, name, regnum, save_restore, group,
-                   bitsize, type);
+  if (bitsize_attr[0] == '$')
+    {
+      // FIXME: Check whether the bitsize parameter is valid.
+      tdesc_create_reg (data->current_feature, name, regnum, save_restore,
+                       group, &bitsize_attr[1], type);
+    }
+  else
+    {
+      int bitsize = (int) gdb_xml_parse_ulongest (parser, bitsize_attr);
+
+      tdesc_create_reg (data->current_feature, name, regnum, save_restore,
+                       group, bitsize, type);
+    }
 
   data->next_regnum = regnum + 1;
 }
@@ -476,25 +487,38 @@ tdesc_start_vector (struct gdb_xml_parser *parser,
   struct tdesc_parsing_data *data = (struct tdesc_parsing_data *) user_data;
   struct tdesc_type *field_type;
   char *id, *field_type_id;
-  ULONGEST count;
 
   id = (char *) attributes[0].value.get ();
   field_type_id = (char *) attributes[1].value.get ();
-  count = * (ULONGEST *) attributes[2].value.get ();
-
-  if (count > MAX_VECTOR_SIZE)
-    {
-      gdb_xml_error (parser,
-                    _("Vector size %s is larger than maximum (%d)"),
-                    pulongest (count), MAX_VECTOR_SIZE);
-    }
 
   field_type = tdesc_named_type (data->current_feature, field_type_id);
   if (field_type == NULL)
     gdb_xml_error (parser, _("Vector \"%s\" references undefined type \"%s\""),
                   id, field_type_id);
 
-  tdesc_create_vector (data->current_feature, id, field_type, count);
+  if (!strcmp (attributes[2].name, "count"))
+    {
+      ULONGEST count = * (ULONGEST *) attributes[2].value.get ();
+
+      if (count > MAX_VECTOR_SIZE)
+       gdb_xml_error (parser, _ ("Vector size %s is larger than maximum (%d)"),
+                      pulongest (count), MAX_VECTOR_SIZE);
+
+      tdesc_create_vector (data->current_feature, id, field_type, count);
+    }
+  else if (!strcmp (attributes[2].name, "bitsize"))
+    {
+      char *bitsize = (char *) attributes[2].value.get ();
+
+      if (bitsize[0] != '$')
+       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]);
+    }
+  else
+    gdb_xml_error (parser, _ ("Vector doesn't have count nor size attribute"));
 }
 
 /* The elements and attributes of an XML target description.  */
@@ -527,7 +551,7 @@ static const struct gdb_xml_element enum_children[] = {
 
 static const struct gdb_xml_attribute reg_attributes[] = {
   { "name", GDB_XML_AF_NONE, NULL, NULL },
-  { "bitsize", GDB_XML_AF_NONE, gdb_xml_parse_attr_ulongest, NULL },
+  { "bitsize", GDB_XML_AF_NONE, NULL, NULL },
   { "regnum", GDB_XML_AF_OPTIONAL, gdb_xml_parse_attr_ulongest, NULL },
   { "type", GDB_XML_AF_OPTIONAL, NULL, NULL },
   { "group", GDB_XML_AF_OPTIONAL, NULL, NULL },
@@ -557,7 +581,8 @@ static const struct gdb_xml_attribute enum_attributes[] = {
 static const struct gdb_xml_attribute vector_attributes[] = {
   { "id", GDB_XML_AF_NONE, NULL, NULL },
   { "type", GDB_XML_AF_NONE, NULL, NULL },
-  { "count", GDB_XML_AF_NONE, gdb_xml_parse_attr_ulongest, NULL },
+  { "count", GDB_XML_AF_OPTIONAL, gdb_xml_parse_attr_ulongest, NULL },
+  { "bitsize", GDB_XML_AF_OPTIONAL, NULL, NULL },
   { NULL, GDB_XML_AF_NONE, NULL, NULL }
 };
 
index ed92c864732e61fa12c4ebae85454c29e0ba9b3d..186354aef8512b7838df6f90bd298cbb5bc8bc72 100644 (file)
@@ -33,6 +33,22 @@ tdesc_reg::tdesc_reg (struct tdesc_feature *feature, const std::string &name_,
   tdesc_type = tdesc_named_type (feature, type.c_str ());
 }
 
+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_)
+  : name (name_), target_regnum (regnum),
+    save_restore (save_restore_),
+    group (group_ != NULL ? group_ : ""),
+    bitsize (TDESC_REG_VARIABLE_SIZE),
+    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.  */
 static tdesc_type_builtin tdesc_predefined_types[] =
 {
@@ -147,6 +163,19 @@ tdesc_create_reg (struct tdesc_feature *feature, const char *name,
 
 /* See gdbsupport/tdesc.h.  */
 
+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)
+{
+  tdesc_reg *reg = new tdesc_reg (feature, name, regnum, save_restore,
+                                 group, bitsize_parameter, type);
+
+  feature->registers.emplace_back (reg);
+}
+
+/* See gdbsupport/tdesc.h.  */
+
 struct tdesc_type *
 tdesc_create_vector (struct tdesc_feature *feature, const char *name,
                     struct tdesc_type *field_type, int count)
@@ -159,6 +188,21 @@ tdesc_create_vector (struct tdesc_feature *feature, const char *name,
 
 /* See gdbsupport/tdesc.h.  */
 
+struct tdesc_type *
+tdesc_create_vector (struct tdesc_feature *feature, const char *name,
+                    struct tdesc_type *field_type,
+                    const char *bitsize_parameter)
+{
+  tdesc_type_vector *type = new tdesc_type_vector (name, field_type,
+                                                  feature->name,
+                                                  bitsize_parameter);
+  feature->types.emplace_back (type);
+
+  return type;
+}
+
+/* See gdbsupport/tdesc.h.  */
+
 tdesc_type_with_fields *
 tdesc_create_struct (struct tdesc_feature *feature, const char *name)
 {
@@ -311,8 +355,12 @@ void print_xml_feature::visit (const tdesc_type_builtin *t)
 
 void print_xml_feature::visit (const tdesc_type_vector *t)
 {
-  add_line ("<vector id=\"%s\" type=\"%s\" count=\"%d\"/>",
-           t->name.c_str (), t->element_type->name.c_str (), t->count);
+  if (t->bitsize_parameter.length () != 0)
+    add_line ("<vector id=\"%s\" type=\"%s\" bitsize=\"$%s\"/>", t->name.c_str (),
+             t->element_type->name.c_str (), t->bitsize_parameter.c_str ());
+  else
+    add_line ("<vector id=\"%s\" type=\"%s\" count=\"%d\"/>", t->name.c_str (),
+             t->element_type->name.c_str (), t->count);
 }
 
 void print_xml_feature::visit (const tdesc_type_with_fields *t)
@@ -381,10 +429,16 @@ void print_xml_feature::visit (const tdesc_reg *r)
 {
   std::string tmp;
 
-  string_appendf (tmp,
-                 "<reg name=\"%s\" bitsize=\"%d\" type=\"%s\" regnum=\"%ld\"",
-                 r->name.c_str (), r->bitsize, r->type.c_str (),
-                 r->target_regnum);
+  if (r->bitsize_parameter.length () != 0)
+    string_appendf (tmp,
+                   "<reg name=\"%s\" bitsize=\"$%s\" type=\"%s\" regnum=\"%ld\"",
+                   r->name.c_str (), r->bitsize_parameter.c_str(),
+                   r->type.c_str (), r->target_regnum);
+  else
+    string_appendf (tmp,
+                   "<reg name=\"%s\" bitsize=\"%d\" type=\"%s\" regnum=\"%ld\"",
+                   r->name.c_str (), r->bitsize, r->type.c_str (),
+                   r->target_regnum);
 
   if (r->group.length () > 0)
     string_appendf (tmp, " group=\"%s\"", r->group.c_str ());
index 6bf66ad3dcdcb9148fddf3a462bad2c0ce549ab7..4ecee683e0988193adf67f997365042ecd3ce603 100644 (file)
@@ -64,6 +64,11 @@ public:
   virtual void accept (tdesc_element_visitor &v) const = 0;
 };
 
+/* Used in vector type element count or register bitsize to indicate that the
+   corresponding value is derived from a target description parameter.  */
+
+#define TDESC_REG_VARIABLE_SIZE -1
+
 /* An individual register from a target description.  */
 
 struct tdesc_reg : tdesc_element
@@ -72,6 +77,10 @@ struct tdesc_reg : tdesc_element
             int regnum, int save_restore_, const char *group_,
             int bitsize_, const char *type_);
 
+  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_);
+
   virtual ~tdesc_reg () = default;
 
   DISABLE_COPY_AND_ASSIGN (tdesc_reg);
@@ -99,9 +108,12 @@ struct tdesc_reg : tdesc_element
      strings are ignored (treated as empty).  */
   std::string group;
 
-  /* The size of the register, in bits.  */
+  /* The size of the register, in bits.
+     Ignored if BITSIZE_PARAMETER isn't empty.  */
   int bitsize;
 
+  std::string feature, bitsize_parameter;
+
   /* The type of the register.  This string corresponds to either
      a named type from the target description or a predefined
      type from GDB.  */
@@ -236,13 +248,26 @@ struct tdesc_type_vector : tdesc_type
     element_type (element_type_), count (count_)
   {}
 
+  tdesc_type_vector (const std::string &name, tdesc_type *element_type_,
+                    const std::string &feature_,
+                    const std::string &bitsize_parameter_)
+      : tdesc_type (name, TDESC_TYPE_VECTOR), element_type (element_type_),
+       count (TDESC_REG_VARIABLE_SIZE), feature (feature_),
+       bitsize_parameter (bitsize_parameter_)
+  {}
+
   void accept (tdesc_element_visitor &v) const override
   {
     v.visit (this);
   }
 
   struct tdesc_type *element_type;
+
+  /* Ignored if BITSIZE_PARAMETER isn't empty. */
   int count;
+
+  /* Target description parameter  providing total vector size.  */
+  std::string feature, bitsize_parameter;
 };
 
 /* A named type from a target description.  */
@@ -362,6 +387,13 @@ struct tdesc_type *tdesc_create_vector (struct tdesc_feature *feature,
                                        struct tdesc_type *field_type,
                                        int count);
 
+/* Return the created vector tdesc_type named NAME in FEATURE,
+   with number of elements derived by the given BITSIZE_PARAMETER.  */
+struct tdesc_type *tdesc_create_vector (struct tdesc_feature *feature,
+                                       const char *name,
+                                       struct tdesc_type *field_type,
+                                       const char *bitsize_parameter);
+
 /* Return the created struct tdesc_type named NAME in FEATURE.  */
 tdesc_type_with_fields *tdesc_create_struct (struct tdesc_feature *feature,
                                             const char *name);
@@ -417,6 +449,12 @@ void tdesc_create_reg (struct tdesc_feature *feature, const char *name,
                       int regnum, int save_restore, const char *group,
                       int bitsize, const char *type);
 
+/* Create a register in feature FEATURE with size given by
+   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);
+
 /* Return the tdesc in string XML format.  */
 
 const char *tdesc_get_features_xml (const target_desc *tdesc);