public inbox for gdb-patches@sourceware.org
 help / color / mirror / Atom feed
* [PATCH 0/8] Handle array- and string-like types in DAP
@ 2023-08-22 15:25 Tom Tromey
  2023-08-22 15:25 ` [PATCH 1/8] Move rust_language::lookup_symbol_nonlocal Tom Tromey
                   ` (8 more replies)
  0 siblings, 9 replies; 11+ messages in thread
From: Tom Tromey @ 2023-08-22 15:25 UTC (permalink / raw)
  To: gdb-patches

A co-worker noticed that some Ada array types did not display properly
via DAP.  Looking into this, I found a couple related problems.

In Ada, some arrays are represented as structures.  The Ada code in
gdb (ada-valprint.c and ada-varobj.c) know how to display these as
arrays, instead.

Also, in Ada, a String is just an array of characters, and again the
Ada code in gdb understands this and displays them more naturally.

Similar cases occur in Rust.

After thinking about this for a while, I decided to try to take a
relatively generic approach to fixing this.  This series adds some
Python API so that Python code can know if a type is "array-like" or
"string-like", and then changes the no-op value-printers to use this
information.

All the tests are deferred until the end of the series.

---
Tom Tromey (8):
      Move rust_language::lookup_symbol_nonlocal
      Refactor Rust code for slice-to-array operation
      Introduce TYPE_SPECIFIC_RUST_STUFF
      Use ada_value_subscript in valpy_getitem
      Introduce type::is_array_like and value_to_array
      Select frame when fetching a frame variable in DAP
      Add new Python APIs to support DAP value display
      Handle array- and string-like values in no-op pretty printers

 gdb/NEWS                                  |   8 ++
 gdb/ada-lang.c                            |   1 +
 gdb/doc/python.texi                       |  24 ++++++
 gdb/dwarf2/read.c                         |   9 ++-
 gdb/gdbtypes.c                            |  24 ++++++
 gdb/gdbtypes.h                            |  16 +++-
 gdb/python/lib/gdb/dap/next.py            |  11 ++-
 gdb/python/lib/gdb/dap/scopes.py          |   4 +
 gdb/python/lib/gdb/printing.py            |  26 ++++++-
 gdb/python/py-type.c                      |  57 ++++++++++++++
 gdb/python/py-value.c                     |  40 ++++++++++
 gdb/rust-lang.c                           |  74 +++++++++++++++---
 gdb/rust-lang.h                           |  39 ++--------
 gdb/testsuite/gdb.dap/ada-arrays.exp      | 123 ++++++++++++++++++++++++++++++
 gdb/testsuite/gdb.dap/ada-arrays/cstuff.c |  22 ++++++
 gdb/testsuite/gdb.dap/ada-arrays/main.adb |  24 ++++++
 gdb/testsuite/gdb.dap/ada-arrays/pck.adb  |  21 +++++
 gdb/testsuite/gdb.dap/ada-arrays/pck.ads  |  51 +++++++++++++
 gdb/testsuite/gdb.dap/rust-slices.exp     | 119 +++++++++++++++++++++++++++++
 gdb/testsuite/gdb.dap/rust-slices.rs      |  29 +++++++
 gdb/valarith.c                            |  21 +++++
 gdb/value.h                               |   4 +
 22 files changed, 699 insertions(+), 48 deletions(-)
---
base-commit: 8032f75b2994816e87e9d2ab7c46ad86601c999b
change-id: 20230822-array-and-string-like-f2a941d78802

Best regards,
-- 
Tom Tromey <tromey@adacore.com>


^ permalink raw reply	[flat|nested] 11+ messages in thread

* [PATCH 1/8] Move rust_language::lookup_symbol_nonlocal
  2023-08-22 15:25 [PATCH 0/8] Handle array- and string-like types in DAP Tom Tromey
@ 2023-08-22 15:25 ` Tom Tromey
  2023-08-22 15:25 ` [PATCH 2/8] Refactor Rust code for slice-to-array operation Tom Tromey
                   ` (7 subsequent siblings)
  8 siblings, 0 replies; 11+ messages in thread
From: Tom Tromey @ 2023-08-22 15:25 UTC (permalink / raw)
  To: gdb-patches

This moves rust_language::lookup_symbol_nonlocal to rust-lang.c.
There's no need to have it in rust-lang.h and moving it lets us avoid
adding new includes in a later patch.
---
 gdb/rust-lang.c | 37 +++++++++++++++++++++++++++++++++++++
 gdb/rust-lang.h | 32 +-------------------------------
 2 files changed, 38 insertions(+), 31 deletions(-)

diff --git a/gdb/rust-lang.c b/gdb/rust-lang.c
index 5eb33d0d3b7..f56aa94a48a 100644
--- a/gdb/rust-lang.c
+++ b/gdb/rust-lang.c
@@ -1684,6 +1684,43 @@ rust_language::is_string_type_p (struct type *type) const
 	      && strcmp (type->name (), "&str") == 0));
 }
 
+/* See language.h.  */
+
+struct block_symbol
+rust_language::lookup_symbol_nonlocal
+     (const char *name, const struct block *block,
+      const domain_enum domain) const
+{
+  struct block_symbol result = {};
+
+  const char *scope = block == nullptr ? "" : block->scope ();
+  symbol_lookup_debug_printf
+    ("rust_lookup_symbol_non_local (%s, %s (scope %s), %s)",
+     name, host_address_to_string (block), scope,
+     domain_name (domain));
+
+  /* Look up bare names in the block's scope.  */
+  std::string scopedname;
+  if (name[cp_find_first_component (name)] == '\0')
+    {
+      if (scope[0] != '\0')
+	{
+	  scopedname = std::string (scope) + "::" + name;
+	  name = scopedname.c_str ();
+	}
+      else
+	name = NULL;
+    }
+
+  if (name != NULL)
+    {
+      result = lookup_symbol_in_static_block (name, block, domain);
+      if (result.symbol == NULL)
+	result = lookup_global_symbol (name, block, domain);
+    }
+  return result;
+}
+
 /* Single instance of the Rust language class.  */
 
 static rust_language rust_language_defn;
diff --git a/gdb/rust-lang.h b/gdb/rust-lang.h
index efe721c5707..85c93a9dcec 100644
--- a/gdb/rust-lang.h
+++ b/gdb/rust-lang.h
@@ -144,37 +144,7 @@ class rust_language : public language_defn
 
   struct block_symbol lookup_symbol_nonlocal
 	(const char *name, const struct block *block,
-	 const domain_enum domain) const override
-  {
-    struct block_symbol result = {};
-
-    const char *scope = block == nullptr ? "" : block->scope ();
-    symbol_lookup_debug_printf
-      ("rust_lookup_symbol_non_local (%s, %s (scope %s), %s)",
-       name, host_address_to_string (block), scope,
-       domain_name (domain));
-
-    /* Look up bare names in the block's scope.  */
-    std::string scopedname;
-    if (name[cp_find_first_component (name)] == '\0')
-      {
-	if (scope[0] != '\0')
-	  {
-	    scopedname = std::string (scope) + "::" + name;
-	    name = scopedname.c_str ();
-	  }
-	else
-	  name = NULL;
-      }
-
-    if (name != NULL)
-      {
-	result = lookup_symbol_in_static_block (name, block, domain);
-	if (result.symbol == NULL)
-	  result = lookup_global_symbol (name, block, domain);
-      }
-    return result;
-  }
+	 const domain_enum domain) const override;
 
   /* See language.h.  */
 

-- 
2.40.1


^ permalink raw reply	[flat|nested] 11+ messages in thread

* [PATCH 2/8] Refactor Rust code for slice-to-array operation
  2023-08-22 15:25 [PATCH 0/8] Handle array- and string-like types in DAP Tom Tromey
  2023-08-22 15:25 ` [PATCH 1/8] Move rust_language::lookup_symbol_nonlocal Tom Tromey
@ 2023-08-22 15:25 ` Tom Tromey
  2023-08-22 15:25 ` [PATCH 3/8] Introduce TYPE_SPECIFIC_RUST_STUFF Tom Tromey
                   ` (6 subsequent siblings)
  8 siblings, 0 replies; 11+ messages in thread
From: Tom Tromey @ 2023-08-22 15:25 UTC (permalink / raw)
  To: gdb-patches

This patch exposes rust_slice_type_p and introduces
rust_slice_to_array, in preparation for subsequent patches that will
need these.
---
 gdb/rust-lang.c | 37 ++++++++++++++++++++++++++++---------
 gdb/rust-lang.h |  7 +++++++
 2 files changed, 35 insertions(+), 9 deletions(-)

diff --git a/gdb/rust-lang.c b/gdb/rust-lang.c
index f56aa94a48a..41afe2f67ab 100644
--- a/gdb/rust-lang.c
+++ b/gdb/rust-lang.c
@@ -153,10 +153,10 @@ rust_tuple_struct_type_p (struct type *type)
   return type->num_fields () > 0 && rust_underscore_fields (type);
 }
 
-/* Return true if TYPE is a slice type, otherwise false.  */
+/* See rust-lang.h.  */
 
-static bool
-rust_slice_type_p (struct type *type)
+bool
+rust_slice_type_p (const struct type *type)
 {
   if (type->code () == TYPE_CODE_STRUCT
       && type->name () != NULL
@@ -319,6 +319,30 @@ static const struct generic_val_print_decorations rust_decorations =
   "]"
 };
 
+/* See rust-lang.h.  */
+
+struct value *
+rust_slice_to_array (struct value *val)
+{
+  struct type *type = check_typedef (val->type ());
+  /* This must have been checked by the caller.  */
+  gdb_assert (rust_slice_type_p (type));
+
+  struct value *base = value_struct_elt (&val, {}, "data_ptr", NULL,
+					 "slice");
+  struct value *len = value_struct_elt (&val, {}, "length", NULL, "slice");
+  LONGEST llen = value_as_long (len);
+
+  struct type *elt_type = base->type ()->target_type ();
+  struct type *array_type = lookup_array_range_type (elt_type, 0,
+						     llen - 1);
+  struct value *array = value::allocate_lazy (array_type);
+  array->set_lval (lval_memory);
+  array->set_address (value_as_address (base));
+
+  return array;
+}
+
 /* Helper function to print a slice.  */
 
 static void
@@ -345,12 +369,7 @@ rust_val_print_slice (struct value *val, struct ui_file *stream, int recurse,
 	gdb_printf (stream, "[]");
       else
 	{
-	  struct type *elt_type = base->type ()->target_type ();
-	  struct type *array_type = lookup_array_range_type (elt_type, 0,
-							     llen - 1);
-	  struct value *array = value::allocate_lazy (array_type);
-	  array->set_lval (lval_memory);
-	  array->set_address (value_as_address (base));
+	  struct value *array = rust_slice_to_array (val);
 	  array->fetch_lazy ();
 	  generic_value_print (array, stream, recurse, options,
 			       &rust_decorations);
diff --git a/gdb/rust-lang.h b/gdb/rust-lang.h
index 85c93a9dcec..2c7ccb93bcf 100644
--- a/gdb/rust-lang.h
+++ b/gdb/rust-lang.h
@@ -34,6 +34,9 @@ extern bool rust_tuple_type_p (struct type *type);
 /* Return true if TYPE is a tuple struct type; otherwise false.  */
 extern bool rust_tuple_struct_type_p (struct type *type);
 
+/* Return true if TYPE is a slice type, otherwise false.  */
+extern bool rust_slice_type_p (const struct type *type);
+
 /* Given a block, find the name of the block's crate. Returns an empty
    stringif no crate name can be found.  */
 extern std::string rust_crate_for_block (const struct block *block);
@@ -50,6 +53,10 @@ extern const char *rust_last_path_segment (const char *path);
 extern struct type *rust_slice_type (const char *name, struct type *elt_type,
 				     struct type *usize_type);
 
+/* Return a new array that holds the contents of the given slice,
+   VAL.  */
+extern struct value *rust_slice_to_array (struct value *val);
+
 /* Class representing the Rust language.  */
 
 class rust_language : public language_defn

-- 
2.40.1


^ permalink raw reply	[flat|nested] 11+ messages in thread

* [PATCH 3/8] Introduce TYPE_SPECIFIC_RUST_STUFF
  2023-08-22 15:25 [PATCH 0/8] Handle array- and string-like types in DAP Tom Tromey
  2023-08-22 15:25 ` [PATCH 1/8] Move rust_language::lookup_symbol_nonlocal Tom Tromey
  2023-08-22 15:25 ` [PATCH 2/8] Refactor Rust code for slice-to-array operation Tom Tromey
@ 2023-08-22 15:25 ` Tom Tromey
  2023-08-22 15:25 ` [PATCH 4/8] Use ada_value_subscript in valpy_getitem Tom Tromey
                   ` (5 subsequent siblings)
  8 siblings, 0 replies; 11+ messages in thread
From: Tom Tromey @ 2023-08-22 15:25 UTC (permalink / raw)
  To: gdb-patches

This adds a new enum constant, TYPE_SPECIFIC_RUST_STUFF, and changes
the DWARF reader to set this on Rust types.  This will be used as a
flag in a later patch.

Note that the size of the type_specific_field bitfield had to be
increased.  I checked that this did not impact the size of main_type.
---
 gdb/dwarf2/read.c |  9 ++++++++-
 gdb/gdbtypes.c    |  7 +++++++
 gdb/gdbtypes.h    | 11 ++++++++++-
 3 files changed, 25 insertions(+), 2 deletions(-)

diff --git a/gdb/dwarf2/read.c b/gdb/dwarf2/read.c
index f1d7bfdfdec..c9f0a18feb5 100644
--- a/gdb/dwarf2/read.c
+++ b/gdb/dwarf2/read.c
@@ -12689,7 +12689,14 @@ read_structure_type (struct die_info *die, struct dwarf2_cu *cu)
     }
 
   type = type_allocator (objfile).new_type ();
-  INIT_CPLUS_SPECIFIC (type);
+  if (cu->lang () == language_rust)
+    {
+      /* This is currently only needed for types that might be
+	 slices.  */
+      INIT_RUST_SPECIFIC (type);
+    }
+  else
+    INIT_CPLUS_SPECIFIC (type);
 
   name = dwarf2_name (die, cu);
   if (name != NULL)
diff --git a/gdb/gdbtypes.c b/gdb/gdbtypes.c
index d7db7beb554..082d85bb4fc 100644
--- a/gdb/gdbtypes.c
+++ b/gdb/gdbtypes.c
@@ -5403,6 +5403,10 @@ recursive_dump_type (struct type *type, int spaces)
       print_gnat_stuff (type, spaces);
       break;
 
+    case TYPE_SPECIFIC_RUST_STUFF:
+      gdb_printf ("%*srust\n", spaces, "");
+      break;
+
     case TYPE_SPECIFIC_FLOATFORMAT:
       gdb_printf ("%*sfloatformat ", spaces, "");
       if (TYPE_FLOATFORMAT (type) == NULL
@@ -5645,6 +5649,9 @@ copy_type_recursive (struct type *type, htab_t copied_types)
     case TYPE_SPECIFIC_GNAT_STUFF:
       INIT_GNAT_SPECIFIC (new_type);
       break;
+    case TYPE_SPECIFIC_RUST_STUFF:
+      INIT_RUST_SPECIFIC (new_type);
+      break;
     case TYPE_SPECIFIC_SELF_TYPE:
       set_type_self_type (new_type,
 			  copy_type_recursive (TYPE_SELF_TYPE (type),
diff --git a/gdb/gdbtypes.h b/gdb/gdbtypes.h
index aedaf53cd5d..389cd6c5757 100644
--- a/gdb/gdbtypes.h
+++ b/gdb/gdbtypes.h
@@ -501,6 +501,7 @@ enum type_specific_kind
   TYPE_SPECIFIC_NONE,
   TYPE_SPECIFIC_CPLUS_STUFF,
   TYPE_SPECIFIC_GNAT_STUFF,
+  TYPE_SPECIFIC_RUST_STUFF,
   TYPE_SPECIFIC_FLOATFORMAT,
   /* Note: This is used by TYPE_CODE_FUNC and TYPE_CODE_METHOD.  */
   TYPE_SPECIFIC_FUNC,
@@ -831,7 +832,7 @@ struct main_type
   /* * A discriminant telling us which field of the type_specific
      union is being used for this type, if any.  */
 
-  ENUM_BITFIELD(type_specific_kind) type_specific_field : 3;
+  ENUM_BITFIELD(type_specific_kind) type_specific_field : 4;
 
   /* * Number of fields described for this type.  This field appears
      at this location because it packs nicely here.  */
@@ -1800,6 +1801,14 @@ extern void allocate_gnat_aux_type (struct type *);
     || (TYPE_SPECIFIC_FIELD (type) == TYPE_SPECIFIC_NONE	\
 	&& (type)->is_fixed_instance ()))
 
+/* Currently there isn't any associated data -- this is just a
+   marker.  */
+#define INIT_RUST_SPECIFIC(type) \
+  TYPE_SPECIFIC_FIELD (type) = TYPE_SPECIFIC_RUST_STUFF
+
+#define HAVE_RUST_SPECIFIC(type) \
+  (TYPE_SPECIFIC_FIELD (type) == TYPE_SPECIFIC_RUST_STUFF)
+
 #define INIT_FUNC_SPECIFIC(type)					       \
   (TYPE_SPECIFIC_FIELD (type) = TYPE_SPECIFIC_FUNC,			       \
    TYPE_MAIN_TYPE (type)->type_specific.func_stuff = (struct func_type *)      \

-- 
2.40.1


^ permalink raw reply	[flat|nested] 11+ messages in thread

* [PATCH 4/8] Use ada_value_subscript in valpy_getitem
  2023-08-22 15:25 [PATCH 0/8] Handle array- and string-like types in DAP Tom Tromey
                   ` (2 preceding siblings ...)
  2023-08-22 15:25 ` [PATCH 3/8] Introduce TYPE_SPECIFIC_RUST_STUFF Tom Tromey
@ 2023-08-22 15:25 ` Tom Tromey
  2023-08-22 15:25 ` [PATCH 5/8] Introduce type::is_array_like and value_to_array Tom Tromey
                   ` (4 subsequent siblings)
  8 siblings, 0 replies; 11+ messages in thread
From: Tom Tromey @ 2023-08-22 15:25 UTC (permalink / raw)
  To: gdb-patches

Ada has a few complexities when it comes to array handling.  Currently
these are all handled in Ada-specific code -- but unfortunately that
means they aren't really accessible to Python.

This patch changes the Python code to defer to Ada when given an Ada
array.  In order to make this work, one spot in ada-lang.c had to be
updated to set the "GNAT-specific" flag on an array type.

The test case for this will come in a later patch.
---
 gdb/ada-lang.c        | 1 +
 gdb/python/py-value.c | 3 +++
 2 files changed, 4 insertions(+)

diff --git a/gdb/ada-lang.c b/gdb/ada-lang.c
index 575568cffb5..4d2c94b9044 100644
--- a/gdb/ada-lang.c
+++ b/gdb/ada-lang.c
@@ -2134,6 +2134,7 @@ ada_type_of_array (struct value *arr, int bounds)
 					longest_to_int (value_as_long (low)),
 					longest_to_int (value_as_long (high)));
 	  elt_type = create_array_type (alloc, elt_type, range_type);
+	  INIT_GNAT_SPECIFIC (elt_type);
 
 	  if (ada_is_unconstrained_packed_array_type (arr->type ()))
 	    {
diff --git a/gdb/python/py-value.c b/gdb/python/py-value.c
index 069560742cf..e1178de89e9 100644
--- a/gdb/python/py-value.c
+++ b/gdb/python/py-value.c
@@ -28,6 +28,7 @@
 #include "expression.h"
 #include "cp-abi.h"
 #include "python.h"
+#include "ada-lang.h"
 
 #include "python-internal.h"
 
@@ -1096,6 +1097,8 @@ valpy_getitem (PyObject *self, PyObject *key)
 	      if (type->code () != TYPE_CODE_ARRAY
 		  && type->code () != TYPE_CODE_PTR)
 		  error (_("Cannot subscript requested type."));
+	      else if (ADA_TYPE_P (type))
+		res_val = ada_value_subscript (tmp, 1, &idx);
 	      else
 		res_val = value_subscript (tmp, value_as_long (idx));
 	    }

-- 
2.40.1


^ permalink raw reply	[flat|nested] 11+ messages in thread

* [PATCH 5/8] Introduce type::is_array_like and value_to_array
  2023-08-22 15:25 [PATCH 0/8] Handle array- and string-like types in DAP Tom Tromey
                   ` (3 preceding siblings ...)
  2023-08-22 15:25 ` [PATCH 4/8] Use ada_value_subscript in valpy_getitem Tom Tromey
@ 2023-08-22 15:25 ` Tom Tromey
  2023-08-22 15:25 ` [PATCH 6/8] Select frame when fetching a frame variable in DAP Tom Tromey
                   ` (3 subsequent siblings)
  8 siblings, 0 replies; 11+ messages in thread
From: Tom Tromey @ 2023-08-22 15:25 UTC (permalink / raw)
  To: gdb-patches

This adds the type::is_array_like method and the value_to_array
function.

The former can be used to see whether a given type is known to be
"array-like".  This is the currently the case for certain
compiler-generated structure types; in particular both the Ada and
Rust compilers do this.
---
 gdb/gdbtypes.c | 17 +++++++++++++++++
 gdb/gdbtypes.h |  5 +++++
 gdb/valarith.c | 21 +++++++++++++++++++++
 gdb/value.h    |  4 ++++
 4 files changed, 47 insertions(+)

diff --git a/gdb/gdbtypes.c b/gdb/gdbtypes.c
index 082d85bb4fc..8b69a06748a 100644
--- a/gdb/gdbtypes.c
+++ b/gdb/gdbtypes.c
@@ -43,6 +43,8 @@
 #include "f-lang.h"
 #include <algorithm>
 #include "gmp-utils.h"
+#include "rust-lang.h"
+#include "ada-lang.h"
 
 /* The value of an invalid conversion badness.  */
 #define INVALID_CONVERSION 100
@@ -5919,6 +5921,21 @@ type::fixed_point_scaling_factor ()
   return type->fixed_point_info ().scaling_factor;
 }
 
+/* See gdbtypes.h.  */
+
+bool
+type::is_array_like ()
+{
+  if (code () == TYPE_CODE_ARRAY)
+    return true;
+  if (HAVE_GNAT_AUX_INFO (this))
+    return (ada_is_constrained_packed_array_type (this)
+	    || ada_is_array_descriptor_type (this));
+  if (HAVE_RUST_SPECIFIC (this))
+    return rust_slice_type_p (this);
+  return false;
+}
+
 \f
 
 static const registry<gdbarch>::key<struct builtin_type> gdbtypes_data;
diff --git a/gdb/gdbtypes.h b/gdb/gdbtypes.h
index 389cd6c5757..153ecb4ed5c 100644
--- a/gdb/gdbtypes.h
+++ b/gdb/gdbtypes.h
@@ -1397,6 +1397,11 @@ struct type
     return this->code () == TYPE_CODE_PTR || TYPE_IS_REFERENCE (this);
   }
 
+  /* Return true if this type is "array-like".  This includes arrays,
+     but also some forms of structure type that are recognized as
+     representations of arrays by the type's language.  */
+  bool is_array_like ();
+
   /* * Type that is a pointer to this type.
      NULL if no such pointer-to type is known yet.
      The debugger may add the address of such a type
diff --git a/gdb/valarith.c b/gdb/valarith.c
index 637047fd853..ef376f05936 100644
--- a/gdb/valarith.c
+++ b/gdb/valarith.c
@@ -28,6 +28,8 @@
 #include "infcall.h"
 #include "gdbsupport/byte-vector.h"
 #include "gdbarch.h"
+#include "rust-lang.h"
+#include "ada-lang.h"
 
 /* Forward declarations.  */
 static struct value *value_subscripted_rvalue (struct value *array,
@@ -249,6 +251,25 @@ value_subscripted_rvalue (struct value *array, LONGEST index,
   return value_from_component (array, elt_type, elt_offs);
 }
 
+/* See value.h.  */
+
+struct value *
+value_to_array (struct value *val)
+{
+  struct type *type = check_typedef (val->type ());
+  if (type->code () == TYPE_CODE_ARRAY)
+    return val;
+
+  if (type->is_array_like ())
+    {
+      if (HAVE_GNAT_AUX_INFO (type))
+	return ada_coerce_to_simple_array (val);
+      if (HAVE_RUST_SPECIFIC (type))
+	return rust_slice_to_array (val);
+    }
+  return nullptr;
+}
+
 \f
 /* Check to see if either argument is a structure, or a reference to
    one.  This is called so we know whether to go ahead with the normal
diff --git a/gdb/value.h b/gdb/value.h
index e5c63dccbe2..bf0bd7dde7b 100644
--- a/gdb/value.h
+++ b/gdb/value.h
@@ -1319,6 +1319,10 @@ extern struct value *value_repeat (struct value *arg1, int count);
 
 extern struct value *value_subscript (struct value *array, LONGEST index);
 
+/* Assuming VAL is array-like (see type::is_array_like), return an
+   array form of VAL.  */
+extern struct value *value_to_array (struct value *val);
+
 extern struct value *value_bitstring_subscript (struct type *type,
 						struct value *bitstring,
 						LONGEST index);

-- 
2.40.1


^ permalink raw reply	[flat|nested] 11+ messages in thread

* [PATCH 6/8] Select frame when fetching a frame variable in DAP
  2023-08-22 15:25 [PATCH 0/8] Handle array- and string-like types in DAP Tom Tromey
                   ` (4 preceding siblings ...)
  2023-08-22 15:25 ` [PATCH 5/8] Introduce type::is_array_like and value_to_array Tom Tromey
@ 2023-08-22 15:25 ` Tom Tromey
  2023-08-22 15:25 ` [PATCH 7/8] Add new Python APIs to support DAP value display Tom Tromey
                   ` (2 subsequent siblings)
  8 siblings, 0 replies; 11+ messages in thread
From: Tom Tromey @ 2023-08-22 15:25 UTC (permalink / raw)
  To: gdb-patches

Right now, if a program uses multiple languages, DAP value formatting
will always use the language of the innermost frame.  However, it is
better to use the variable's defining frame instead.  This patch does
this by selecting the frame first.

This also fixes a possibly latent bug in the "stepOut" command --
"finish" is sensitive to the selected frame, but the DAP code may
already select other frames when convenient.  The DAP stepOut request
only works on the newest frame, so be sure to select it before
invoking "finish".
---
 gdb/python/lib/gdb/dap/next.py   | 11 ++++++++---
 gdb/python/lib/gdb/dap/scopes.py |  4 ++++
 2 files changed, 12 insertions(+), 3 deletions(-)

diff --git a/gdb/python/lib/gdb/dap/next.py b/gdb/python/lib/gdb/dap/next.py
index 8b112770a0c..5046963cb81 100644
--- a/gdb/python/lib/gdb/dap/next.py
+++ b/gdb/python/lib/gdb/dap/next.py
@@ -23,9 +23,10 @@ from .state import set_thread
 
 # Helper function to set the current thread and the scheduler-locking
 # mode.  Returns True if scheduler-locking was successfully set to
-# 'on', False in all other cases, including error.
+# 'on', False in all other cases, including error.  When SELECT is
+# True, also select that thread's newest frame.
 @in_gdb_thread
-def _handle_thread_step(thread_id, single_thread):
+def _handle_thread_step(thread_id, single_thread, select=False):
     # Ensure we're going to step the correct thread.
     set_thread(thread_id)
     if single_thread:
@@ -41,6 +42,10 @@ def _handle_thread_step(thread_id, single_thread):
         gdb.execute("set scheduler-locking " + arg, from_tty=True, to_string=True)
     except gdb.error:
         result = False
+    # Other DAP code may select a frame, and the "finish" command uses
+    # the selected frame.
+    if select:
+        gdb.newest_frame().select()
     return result
 
 
@@ -70,7 +75,7 @@ def step_in(
 
 @request("stepOut")
 def step_out(*, threadId: int, singleThread: bool = False):
-    send_gdb(lambda: _handle_thread_step(threadId, singleThread))
+    send_gdb(lambda: _handle_thread_step(threadId, singleThread, True))
     send_gdb(ExecutionInvoker("finish", StopKinds.STEP))
 
 
diff --git a/gdb/python/lib/gdb/dap/scopes.py b/gdb/python/lib/gdb/dap/scopes.py
index 1687094c4ce..4874d001216 100644
--- a/gdb/python/lib/gdb/dap/scopes.py
+++ b/gdb/python/lib/gdb/dap/scopes.py
@@ -49,6 +49,10 @@ class _ScopeReference(BaseReference):
 
     @in_gdb_thread
     def fetch_one_child(self, idx):
+        # Make sure to select the frame first.  Ideally this would not
+        # be needed, but this is a way to set the current language
+        # properly so that language-dependent APIs will work.
+        self.inf_frame.select()
         # Here SYM will conform to the SymValueWrapper interface.
         sym = self.var_list[idx]
         name = str(sym.symbol())

-- 
2.40.1


^ permalink raw reply	[flat|nested] 11+ messages in thread

* [PATCH 7/8] Add new Python APIs to support DAP value display
  2023-08-22 15:25 [PATCH 0/8] Handle array- and string-like types in DAP Tom Tromey
                   ` (5 preceding siblings ...)
  2023-08-22 15:25 ` [PATCH 6/8] Select frame when fetching a frame variable in DAP Tom Tromey
@ 2023-08-22 15:25 ` Tom Tromey
  2023-08-22 15:46   ` Eli Zaretskii
  2023-08-22 15:25 ` [PATCH 8/8] Handle array- and string-like values in no-op pretty printers Tom Tromey
  2023-09-05 17:22 ` [PATCH 0/8] Handle array- and string-like types in DAP Tom Tromey
  8 siblings, 1 reply; 11+ messages in thread
From: Tom Tromey @ 2023-08-22 15:25 UTC (permalink / raw)
  To: gdb-patches

gdb's language code may know how to display values specially.  For
example, the Rust code understands that &str is a string-like type, or
Ada knows how to handle unconstrained arrays.  This knowledge is
exposed via val-print, and via varobj -- but currently not via DAP.

This patch adds some support code to let DAP also handle these cases,
though in a somewhat more generic way.

Type.is_array_like and Value.to_array are added to make Python aware
of the cases where gdb knows that a structure type is really
"array-like".

Type.is_string_like is added to make Python aware of cases where gdb's
language code knows that a type is string-like.

Unlike Value.string, these cases are handled by the type's language,
rather than the current language.
---
 gdb/NEWS              |  8 ++++++++
 gdb/doc/python.texi   | 24 ++++++++++++++++++++++
 gdb/python/py-type.c  | 57 +++++++++++++++++++++++++++++++++++++++++++++++++++
 gdb/python/py-value.c | 37 +++++++++++++++++++++++++++++++++
 4 files changed, 126 insertions(+)

diff --git a/gdb/NEWS b/gdb/NEWS
index c4b1f7a7e3b..98ff00d5efc 100644
--- a/gdb/NEWS
+++ b/gdb/NEWS
@@ -269,6 +269,9 @@ info main
 
   ** gdb.Value now has the 'assign' method.
 
+  ** gdb.Value now has the 'to_array' method.  This converts an
+     array-like Value to an array.
+
   ** gdb.Progspace now has the new method "objfile_for_address".  This
      returns the gdb.Objfile, if any, that covers a given address.
 
@@ -278,6 +281,11 @@ info main
      inferior specific, then this field contains None.  This field can
      be written too.
 
+  ** gdb.Type now has the "is_array_like" and "is_string_like"
+     methods.  These reflect GDB's internal idea of whether a type
+     might be array- or string-like, even if they do not have the
+     corresponding type code.
+
 *** Changes in GDB 13
 
 * MI version 1 is deprecated, and will be removed in GDB 14.
diff --git a/gdb/doc/python.texi b/gdb/doc/python.texi
index 7460d6c8e31..e9936991c49 100644
--- a/gdb/doc/python.texi
+++ b/gdb/doc/python.texi
@@ -1206,6 +1206,13 @@ print frame-arguments scalars} (@pxref{Print Settings}).
 @end table
 @end defun
 
+@defun Value.to_array ()
+If this value is array-like (@pxref{Type.is_array_like}), then this
+method converts it to an array, which is returned.  If this value is
+already an array, it is simply returned.  Otherwise, an exception is
+throw.
+@end defun
+
 @defun Value.string (@r{[}encoding@r{[}, errors@r{[}, length@r{]]]})
 If this @code{gdb.Value} represents a string, then this method
 converts the contents to a Python string.  Otherwise, this method will
@@ -1392,6 +1399,23 @@ which @code{Type.is_scalar} is @code{False}), will raise a
 @code{ValueError}.
 @end defvar
 
+@defvar Type.is_array_like
+@anchor{Type.is_array_like}
+A boolean indicating whether this type is array-like.
+
+Some languages have array-like objects that are represented internally
+as structures.  For example, this is true for a Rust slice type, or
+for an Ada unconstrained array.  @value{GDBN} may know about these
+types.  This determination is done based on the language from which
+the type originated.
+@end defvar
+
+@defvar Type.is_string_like
+A boolean indicating whether this type is string-like.  Like
+@code{Type.is_array_like}, this is determined based on the originating
+language of the type.
+@end defvar
+
 The following methods are provided:
 
 @defun Type.fields ()
diff --git a/gdb/python/py-type.c b/gdb/python/py-type.c
index b60875c792e..1fc1308af8e 100644
--- a/gdb/python/py-type.c
+++ b/gdb/python/py-type.c
@@ -442,6 +442,59 @@ typy_is_signed (PyObject *self, void *closure)
     Py_RETURN_TRUE;
 }
 
+/* Return true if this type is array-like.  */
+
+static PyObject *
+typy_is_array_like (PyObject *self, void *closure)
+{
+  struct type *type = ((type_object *) self)->type;
+
+  try
+    {
+      type = check_typedef (type);
+    }
+  catch (const gdb_exception &except)
+    {
+      GDB_PY_HANDLE_EXCEPTION (except);
+    }
+
+  if (type->is_array_like ())
+    Py_RETURN_TRUE;
+  else
+    Py_RETURN_FALSE;
+}
+
+/* Return true if this type is string-like.  */
+
+static PyObject *
+typy_is_string_like (PyObject *self, void *closure)
+{
+  struct type *type = ((type_object *) self)->type;
+  bool result = false;
+
+  try
+    {
+      type = check_typedef (type);
+
+      const language_defn *lang = nullptr;
+      if (HAVE_GNAT_AUX_INFO (type))
+	lang = language_def (language_ada);
+      else if (HAVE_RUST_SPECIFIC (type))
+	lang = language_def (language_rust);
+      if (lang != nullptr)
+	result = lang->is_string_type_p (type);
+    }
+  catch (const gdb_exception &except)
+    {
+      GDB_PY_HANDLE_EXCEPTION (except);
+    }
+
+  if (result)
+    Py_RETURN_TRUE;
+  else
+    Py_RETURN_FALSE;
+}
+
 /* Return the type, stripped of typedefs. */
 static PyObject *
 typy_strip_typedefs (PyObject *self, PyObject *args)
@@ -1525,6 +1578,10 @@ static gdb_PyGetSetDef type_object_getset[] =
     "Is this a scalar type?", nullptr },
   { "is_signed", typy_is_signed, nullptr,
     "Is this a signed type?", nullptr },
+  { "is_array_like", typy_is_array_like, nullptr,
+    "Is this an array-like type?", nullptr },
+  { "is_string_like", typy_is_string_like, nullptr,
+    "Is this a string-like type?", nullptr },
   { NULL }
 };
 
diff --git a/gdb/python/py-value.c b/gdb/python/py-value.c
index e1178de89e9..ee492fd9af6 100644
--- a/gdb/python/py-value.c
+++ b/gdb/python/py-value.c
@@ -330,6 +330,40 @@ valpy_rvalue_reference_value (PyObject *self, PyObject *args)
   return valpy_reference_value (self, args, TYPE_CODE_RVALUE_REF);
 }
 
+/* Implement Value.to_array.  */
+
+static PyObject *
+valpy_to_array (PyObject *self, PyObject *args)
+{
+  PyObject *result = nullptr;
+
+  try
+    {
+      struct value *val = ((value_object *) self)->value;
+      struct type *type = check_typedef (val->type ());
+
+      if (type->code () == TYPE_CODE_ARRAY)
+	{
+	  result = self;
+	  Py_INCREF (result);
+	}
+      else
+	{
+	  val = value_to_array (val);
+	  if (val == nullptr)
+	    PyErr_SetString (PyExc_TypeError, _("Value is not array-like."));
+	  else
+	    result = value_to_value_object (val);
+	}
+    }
+  catch (const gdb_exception &except)
+    {
+      GDB_PY_HANDLE_EXCEPTION (except);
+    }
+
+  return result;
+}
+
 /* Return a "const" qualified version of the value.  */
 
 static PyObject *
@@ -2152,6 +2186,9 @@ formatting options" },
   { "assign", (PyCFunction) valpy_assign, METH_VARARGS,
     "assign (VAL) -> None\n\
 Assign VAL to this value." },
+  { "to_array", valpy_to_array, METH_NOARGS,
+    "to_array () -> Value\n\
+Return value as an array, if possible." },
   {NULL}  /* Sentinel */
 };
 

-- 
2.40.1


^ permalink raw reply	[flat|nested] 11+ messages in thread

* [PATCH 8/8] Handle array- and string-like values in no-op pretty printers
  2023-08-22 15:25 [PATCH 0/8] Handle array- and string-like types in DAP Tom Tromey
                   ` (6 preceding siblings ...)
  2023-08-22 15:25 ` [PATCH 7/8] Add new Python APIs to support DAP value display Tom Tromey
@ 2023-08-22 15:25 ` Tom Tromey
  2023-09-05 17:22 ` [PATCH 0/8] Handle array- and string-like types in DAP Tom Tromey
  8 siblings, 0 replies; 11+ messages in thread
From: Tom Tromey @ 2023-08-22 15:25 UTC (permalink / raw)
  To: gdb-patches

This changes the no-op pretty printers -- used by DAP -- to handle
array- and string-like objects known by the gdb core.  Two new tests
are added, one for Ada and one for Rust.
---
 gdb/python/lib/gdb/printing.py            |  26 ++++++-
 gdb/testsuite/gdb.dap/ada-arrays.exp      | 123 ++++++++++++++++++++++++++++++
 gdb/testsuite/gdb.dap/ada-arrays/cstuff.c |  22 ++++++
 gdb/testsuite/gdb.dap/ada-arrays/main.adb |  24 ++++++
 gdb/testsuite/gdb.dap/ada-arrays/pck.adb  |  21 +++++
 gdb/testsuite/gdb.dap/ada-arrays/pck.ads  |  51 +++++++++++++
 gdb/testsuite/gdb.dap/rust-slices.exp     | 119 +++++++++++++++++++++++++++++
 gdb/testsuite/gdb.dap/rust-slices.rs      |  29 +++++++
 8 files changed, 412 insertions(+), 3 deletions(-)

diff --git a/gdb/python/lib/gdb/printing.py b/gdb/python/lib/gdb/printing.py
index a668bd0e3fc..1a761a6aa57 100644
--- a/gdb/python/lib/gdb/printing.py
+++ b/gdb/python/lib/gdb/printing.py
@@ -18,6 +18,7 @@
 
 import gdb
 import gdb.types
+import itertools
 import re
 
 
@@ -285,11 +286,24 @@ class NoOpArrayPrinter:
     def __init__(self, ty, value):
         self.value = value
         (low, high) = ty.range()
-        self.low = low
-        self.high = high
+        # In Ada, an array can have an index type that is a
+        # non-contiguous enum.  In this case the indexing must be done
+        # by using the indices into the enum type, not the underlying
+        # integer values.
+        range_type = ty.fields()[0].type
+        if range_type.target().code == gdb.TYPE_CODE_ENUM:
+            e_values = range_type.target().fields()
+            # Drop any values before LOW.
+            e_values = itertools.dropwhile(lambda x: x.enumval < low, e_values)
+            # Drop any values after HIGH.
+            e_values = itertools.takewhile(lambda x: x.enumval <= high, e_values)
+            low = 0
+            high = len(list(e_values)) - 1
         # This is a convenience to the DAP code and perhaps other
         # users.
         self.num_children = high - low + 1
+        self.low = low
+        self.high = high
 
     def to_string(self):
         return ""
@@ -330,7 +344,13 @@ def make_visualizer(value):
         pass
     else:
         ty = value.type.strip_typedefs()
-        if ty.code == gdb.TYPE_CODE_ARRAY:
+        if ty.is_string_like:
+            result = gdb.printing.NoOpScalarPrinter(value)
+        elif ty.code == gdb.TYPE_CODE_ARRAY:
+            result = gdb.printing.NoOpArrayPrinter(ty, value)
+        elif ty.is_array_like:
+            value = value.to_array()
+            ty = value.type.strip_typedefs()
             result = gdb.printing.NoOpArrayPrinter(ty, value)
         elif ty.code in (gdb.TYPE_CODE_STRUCT, gdb.TYPE_CODE_UNION):
             result = gdb.printing.NoOpStructPrinter(ty, value)
diff --git a/gdb/testsuite/gdb.dap/ada-arrays.exp b/gdb/testsuite/gdb.dap/ada-arrays.exp
new file mode 100644
index 00000000000..13b5425ded4
--- /dev/null
+++ b/gdb/testsuite/gdb.dap/ada-arrays.exp
@@ -0,0 +1,123 @@
+# Copyright 2023 Free Software Foundation, Inc.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+load_lib "ada.exp"
+load_lib dap-support.exp
+
+require allow_dap_tests
+require allow_ada_tests
+
+standard_ada_testfile main
+set cfile "cstuff"
+set csrcfile ${srcdir}/${subdir}/${testdir}/${cfile}.c
+set cobject [standard_output_file ${cfile}.o]
+
+gdb_compile "${csrcfile}" "${cobject}" object [list debug]
+if {[gdb_compile_ada "${srcfile}" "${binfile}" executable debug] != ""} {
+  return -1
+}
+
+if {[dap_launch $testfile] == ""} {
+    return
+}
+
+# Stop in a C frame, but examine values in an Ada frame, to make sure
+# cross-language scenarios work correctly.
+set line [gdb_get_line_number "STOP" $testdir/cstuff.c]
+set obj [dap_check_request_and_response "set breakpoint by line number" \
+	     setBreakpoints \
+	     [format {o source [o path [%s]] breakpoints [a [o line [i %d]]]} \
+		  [list s cstuff.c] $line]]
+set line_bpno [dap_get_breakpoint_number $obj]
+
+dap_check_request_and_response "start inferior" configurationDone
+dap_wait_for_event_and_check "inferior started" thread "body reason" started
+
+dap_wait_for_event_and_check "stopped at line breakpoint" stopped \
+    "body reason" breakpoint \
+    "body hitBreakpointIds" $line_bpno
+
+set bt [lindex [dap_check_request_and_response "backtrace" stackTrace \
+		    {o threadId [i 1]}] \
+	    0]
+# The Ada frame is frame 1.
+set frame_id [dict get [lindex [dict get $bt body stackFrames] 1] id]
+
+set scopes [dap_check_request_and_response "get scopes" scopes \
+		[format {o frameId [i %d]} $frame_id]]
+set scopes [dict get [lindex $scopes 0] body scopes]
+
+gdb_assert {[llength $scopes] == 2} "two scopes"
+
+lassign $scopes scope ignore
+gdb_assert {[dict get $scope name] == "Arguments"} "scope is arguments"
+gdb_assert {[dict get $scope presentationHint] == "arguments"} \
+    "arguments presentation hint"
+gdb_assert {[dict get $scope namedVariables] == 3} "three vars in scope"
+
+set num [dict get $scope variablesReference]
+set refs [lindex [dap_check_request_and_response "fetch arguments" \
+		      "variables" \
+		      [format {o variablesReference [i %d]} $num]] \
+	      0]
+
+# Helper to check the contents of a single array-like object.  VAR is
+# the variable entry.  NAME is the name of the variable, pulled out
+# for convenience.# ARGS are the expected child values.
+proc check_array_contents {var name args} {
+    set len [llength $args]
+    gdb_assert {[dict get $var indexedVariables] == $len} \
+	"check length of $name variable"
+
+    set num [dict get $var variablesReference]
+    set refs [lindex [dap_check_request_and_response \
+			  "fetch contents of $name" \
+			  "variables" \
+			  [format {o variablesReference [i %d]} $num]] \
+		  0]
+
+    foreach subvar [dict get $refs body variables] subvalue $args {
+	set subname [dict get $subvar name]
+	gdb_assert {[dict get $subvar value] == $subvalue} \
+	    "check value of $name entry $subname"
+    }
+}
+
+foreach var [dict get $refs body variables] {
+    set name [dict get $var name]
+    switch $name {
+	"the_buffer" {
+	    check_array_contents $var $name 1 2 3 4
+	}
+
+	"the_ar" {
+	    check_array_contents $var $name 5 6 7 8 9
+	}
+
+	"hello" {
+	    # Note that the expected value looks strange here -- there
+	    # are too many backslashes.  This is a TON issue, as the
+	    # JSON looks ok: "value": "\"hello\"".
+	    gdb_assert {[dict get $var value] == "\\\"hello\\\""} \
+		"value of hello variable"
+	}
+
+	default {
+	    fail "unknown variable $name"
+	}
+    }
+}
+
+dap_shutdown
diff --git a/gdb/testsuite/gdb.dap/ada-arrays/cstuff.c b/gdb/testsuite/gdb.dap/ada-arrays/cstuff.c
new file mode 100644
index 00000000000..af87082401c
--- /dev/null
+++ b/gdb/testsuite/gdb.dap/ada-arrays/cstuff.c
@@ -0,0 +1,22 @@
+/* Copyright 2023 Free Software Foundation, Inc.
+
+   This file is part of GDB.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+void
+c_procedure (int x)
+{
+  /* STOP */
+}
diff --git a/gdb/testsuite/gdb.dap/ada-arrays/main.adb b/gdb/testsuite/gdb.dap/ada-arrays/main.adb
new file mode 100644
index 00000000000..c9e98c4a249
--- /dev/null
+++ b/gdb/testsuite/gdb.dap/ada-arrays/main.adb
@@ -0,0 +1,24 @@
+--  Copyright 2023 Free Software Foundation, Inc.
+--
+--  This program is free software; you can redistribute it and/or modify
+--  it under the terms of the GNU General Public License as published by
+--  the Free Software Foundation; either version 3 of the License, or
+--  (at your option) any later version.
+--
+--  This program is distributed in the hope that it will be useful,
+--  but WITHOUT ANY WARRANTY; without even the implied warranty of
+--  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+--  GNU General Public License for more details.
+--
+--  You should have received a copy of the GNU General Public License
+--  along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+with Pck; use Pck;
+
+procedure Main is
+   Value : Buffer (1 .. 4) := (1, 2, 3, 4);
+   Another_Value : AR := (5, 6, 7, 8, 9);
+   Hello: String := "hello";
+begin
+   Do_Nothing (Value, Another_Value, Hello);
+end Main;
diff --git a/gdb/testsuite/gdb.dap/ada-arrays/pck.adb b/gdb/testsuite/gdb.dap/ada-arrays/pck.adb
new file mode 100644
index 00000000000..7efa8930af8
--- /dev/null
+++ b/gdb/testsuite/gdb.dap/ada-arrays/pck.adb
@@ -0,0 +1,21 @@
+--  Copyright 2023 Free Software Foundation, Inc.
+--
+--  This program is free software; you can redistribute it and/or modify
+--  it under the terms of the GNU General Public License as published by
+--  the Free Software Foundation; either version 3 of the License, or
+--  (at your option) any later version.
+--
+--  This program is distributed in the hope that it will be useful,
+--  but WITHOUT ANY WARRANTY; without even the implied warranty of
+--  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+--  GNU General Public License for more details.
+--
+--  You should have received a copy of the GNU General Public License
+--  along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+package body Pck is
+   procedure Do_Nothing (The_Buffer : in out Buffer; The_AR : in out AR; Hello: in out String) is
+   begin
+      C_Procedure (23);
+   end Do_Nothing;
+end Pck;
diff --git a/gdb/testsuite/gdb.dap/ada-arrays/pck.ads b/gdb/testsuite/gdb.dap/ada-arrays/pck.ads
new file mode 100644
index 00000000000..475bb7bf1e9
--- /dev/null
+++ b/gdb/testsuite/gdb.dap/ada-arrays/pck.ads
@@ -0,0 +1,51 @@
+--  Copyright 2023 Free Software Foundation, Inc.
+--
+--  This program is free software; you can redistribute it and/or modify
+--  it under the terms of the GNU General Public License as published by
+--  the Free Software Foundation; either version 3 of the License, or
+--  (at your option) any later version.
+--
+--  This program is distributed in the hope that it will be useful,
+--  but WITHOUT ANY WARRANTY; without even the implied warranty of
+--  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+--  GNU General Public License for more details.
+--
+--  You should have received a copy of the GNU General Public License
+--  along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+package Pck is
+   pragma Linker_Options ("cstuff.o");
+
+   procedure C_Procedure (Value : Integer);
+   pragma Import(C, C_Procedure, "c_procedure");
+
+   type Small is new Integer range 0 .. 2 ** 6 - 1;
+
+   type Buffer is array (Integer range <>) of Small;
+   pragma Pack (Buffer);
+
+   type Enum_With_Gaps is
+     (
+      LIT0,
+      LIT1,
+      LIT2,
+      LIT3,
+      LIT4
+     );
+
+   for Enum_With_Gaps use
+     (
+      LIT0 => 3,
+      LIT1 => 5,
+      LIT2 => 8,
+      LIT3 => 13,
+      LIT4 => 21
+     );
+   for Enum_With_Gaps'size use 16;
+
+   type Enum_Subrange is new Enum_With_Gaps range Lit1 .. Lit3;
+
+   type AR is array (Enum_With_Gaps range <>) of Integer;
+
+   procedure Do_Nothing (The_Buffer : in out Buffer; The_AR : in out AR; Hello: in out String);
+end Pck;
diff --git a/gdb/testsuite/gdb.dap/rust-slices.exp b/gdb/testsuite/gdb.dap/rust-slices.exp
new file mode 100644
index 00000000000..96ed5dac8d3
--- /dev/null
+++ b/gdb/testsuite/gdb.dap/rust-slices.exp
@@ -0,0 +1,119 @@
+# Copyright 2023 Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+# Test "scopes" and "variables".
+
+load_lib rust-support.exp
+load_lib dap-support.exp
+
+require allow_dap_tests
+require allow_rust_tests
+require {can_compile rust}
+
+standard_testfile .rs
+
+if {[build_executable ${testfile}.exp $testfile $srcfile {debug rust}] == -1} {
+    return
+}
+
+if {[dap_launch $testfile] == ""} {
+    return
+}
+
+set line [gdb_get_line_number "STOP"]
+set obj [dap_check_request_and_response "set breakpoint by line number" \
+	     setBreakpoints \
+	     [format {o source [o path [%s]] breakpoints [a [o line [i %d]]]} \
+		  [list s $srcfile] $line]]
+set line_bpno [dap_get_breakpoint_number $obj]
+
+dap_check_request_and_response "start inferior" configurationDone
+dap_wait_for_event_and_check "inferior started" thread "body reason" started
+
+dap_wait_for_event_and_check "stopped at line breakpoint" stopped \
+    "body reason" breakpoint \
+    "body hitBreakpointIds" $line_bpno
+
+set bt [lindex [dap_check_request_and_response "backtrace" stackTrace \
+		    {o threadId [i 1]}] \
+	    0]
+set frame_id [dict get [lindex [dict get $bt body stackFrames] 0] id]
+
+set scopes [dap_check_request_and_response "get scopes" scopes \
+		[format {o frameId [i %d]} $frame_id]]
+set scopes [dict get [lindex $scopes 0] body scopes]
+
+gdb_assert {[llength $scopes] == 2} "two scopes"
+
+lassign $scopes scope ignore
+gdb_assert {[dict get $scope name] == "Locals"} "scope is locals"
+gdb_assert {[dict get $scope presentationHint] == "locals"} \
+    "locals presentation hint"
+gdb_assert {[dict get $scope namedVariables] == 3} "three vars in scope"
+
+set num [dict get $scope variablesReference]
+set refs [lindex [dap_check_request_and_response "fetch variables" \
+		      "variables" \
+		      [format {o variablesReference [i %d]} $num]] \
+	      0]
+
+# Helper to check the contents of a single array-like object.  VAR is
+# the variable entry.  NAME is the name of the variable, pulled out
+# for convenience.  ARGS are the expected child values.
+proc check_array_contents {var name args} {
+    set len [llength $args]
+    gdb_assert {[dict get $var indexedVariables] == $len} \
+	"check length of $name variable"
+
+    set num [dict get $var variablesReference]
+    set refs [lindex [dap_check_request_and_response \
+			  "fetch contents of $name" \
+			  "variables" \
+			  [format {o variablesReference [i %d]} $num]] \
+		  0]
+
+    foreach subvar [dict get $refs body variables] subvalue $args {
+	set subname [dict get $subvar name]
+	gdb_assert {[dict get $subvar value] == $subvalue} \
+	    "check value of $name entry $subname"
+    }
+}
+
+foreach var [dict get $refs body variables] {
+    set name [dict get $var name]
+    switch $name {
+	"array" {
+	    check_array_contents $var $name 1 2 3 4
+	}
+
+	"slice" {
+	    check_array_contents $var $name 2
+	}
+
+	"hello" {
+	    # Note that the expected value looks strange here -- there
+	    # are too many backslashes.  This is a TON issue, as the
+	    # JSON looks ok: "value": "\"hello\"".
+	    gdb_assert {[dict get $var value] == "\\\"hello\\\""} \
+		"value of hello variable"
+	}
+
+	default {
+	    fail "unknown variable $name"
+	}
+    }
+}
+
+dap_shutdown
diff --git a/gdb/testsuite/gdb.dap/rust-slices.rs b/gdb/testsuite/gdb.dap/rust-slices.rs
new file mode 100644
index 00000000000..0f06a75cfa7
--- /dev/null
+++ b/gdb/testsuite/gdb.dap/rust-slices.rs
@@ -0,0 +1,29 @@
+// Copyright (C) 2023 Free Software Foundation, Inc.
+
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License as published by
+// the Free Software Foundation; either version 3 of the License, or
+// (at your option) any later version.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+#![allow(dead_code)]
+#![allow(unused_variables)]
+#![allow(unused_assignments)]
+
+fn empty () {
+}
+
+fn main () {
+    let array = [1,2,3,4];
+    let slice = &array[1..2];
+    let hello = "hello";
+
+    empty();			// STOP
+}

-- 
2.40.1


^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [PATCH 7/8] Add new Python APIs to support DAP value display
  2023-08-22 15:25 ` [PATCH 7/8] Add new Python APIs to support DAP value display Tom Tromey
@ 2023-08-22 15:46   ` Eli Zaretskii
  0 siblings, 0 replies; 11+ messages in thread
From: Eli Zaretskii @ 2023-08-22 15:46 UTC (permalink / raw)
  To: Tom Tromey; +Cc: gdb-patches

> Date: Tue, 22 Aug 2023 09:25:13 -0600
> From: Tom Tromey via Gdb-patches <gdb-patches@sourceware.org>
> 
> gdb's language code may know how to display values specially.  For
> example, the Rust code understands that &str is a string-like type, or
> Ada knows how to handle unconstrained arrays.  This knowledge is
> exposed via val-print, and via varobj -- but currently not via DAP.
> 
> This patch adds some support code to let DAP also handle these cases,
> though in a somewhat more generic way.
> 
> Type.is_array_like and Value.to_array are added to make Python aware
> of the cases where gdb knows that a structure type is really
> "array-like".
> 
> Type.is_string_like is added to make Python aware of cases where gdb's
> language code knows that a type is string-like.
> 
> Unlike Value.string, these cases are handled by the type's language,
> rather than the current language.
> ---
>  gdb/NEWS              |  8 ++++++++
>  gdb/doc/python.texi   | 24 ++++++++++++++++++++++
>  gdb/python/py-type.c  | 57 +++++++++++++++++++++++++++++++++++++++++++++++++++
>  gdb/python/py-value.c | 37 +++++++++++++++++++++++++++++++++
>  4 files changed, 126 insertions(+)

Thanks, the documentation parts are okay.

Reviewed-By: Eli Zaretskii <eliz@gnu.org>

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [PATCH 0/8] Handle array- and string-like types in DAP
  2023-08-22 15:25 [PATCH 0/8] Handle array- and string-like types in DAP Tom Tromey
                   ` (7 preceding siblings ...)
  2023-08-22 15:25 ` [PATCH 8/8] Handle array- and string-like values in no-op pretty printers Tom Tromey
@ 2023-09-05 17:22 ` Tom Tromey
  8 siblings, 0 replies; 11+ messages in thread
From: Tom Tromey @ 2023-09-05 17:22 UTC (permalink / raw)
  To: Tom Tromey via Gdb-patches; +Cc: Tom Tromey

>>>>> "Tom" == Tom Tromey via Gdb-patches <gdb-patches@sourceware.org> writes:

Tom> A co-worker noticed that some Ada array types did not display properly
Tom> via DAP.  Looking into this, I found a couple related problems.

Tom> In Ada, some arrays are represented as structures.  The Ada code in
Tom> gdb (ada-valprint.c and ada-varobj.c) know how to display these as
Tom> arrays, instead.

Tom> Also, in Ada, a String is just an array of characters, and again the
Tom> Ada code in gdb understands this and displays them more naturally.

Tom> Similar cases occur in Rust.

Tom> After thinking about this for a while, I decided to try to take a
Tom> relatively generic approach to fixing this.  This series adds some
Tom> Python API so that Python code can know if a type is "array-like" or
Tom> "string-like", and then changes the no-op value-printers to use this
Tom> information.

Tom> All the tests are deferred until the end of the series.

I'm checking these in now.

Tom

^ permalink raw reply	[flat|nested] 11+ messages in thread

end of thread, other threads:[~2023-09-05 17:22 UTC | newest]

Thread overview: 11+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2023-08-22 15:25 [PATCH 0/8] Handle array- and string-like types in DAP Tom Tromey
2023-08-22 15:25 ` [PATCH 1/8] Move rust_language::lookup_symbol_nonlocal Tom Tromey
2023-08-22 15:25 ` [PATCH 2/8] Refactor Rust code for slice-to-array operation Tom Tromey
2023-08-22 15:25 ` [PATCH 3/8] Introduce TYPE_SPECIFIC_RUST_STUFF Tom Tromey
2023-08-22 15:25 ` [PATCH 4/8] Use ada_value_subscript in valpy_getitem Tom Tromey
2023-08-22 15:25 ` [PATCH 5/8] Introduce type::is_array_like and value_to_array Tom Tromey
2023-08-22 15:25 ` [PATCH 6/8] Select frame when fetching a frame variable in DAP Tom Tromey
2023-08-22 15:25 ` [PATCH 7/8] Add new Python APIs to support DAP value display Tom Tromey
2023-08-22 15:46   ` Eli Zaretskii
2023-08-22 15:25 ` [PATCH 8/8] Handle array- and string-like values in no-op pretty printers Tom Tromey
2023-09-05 17:22 ` [PATCH 0/8] Handle array- and string-like types in DAP Tom Tromey

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).