From: Tom Tromey <tromey@adacore.com>
To: gdb-patches@sourceware.org
Subject: [PATCH 8/8] Handle array- and string-like values in no-op pretty printers
Date: Tue, 22 Aug 2023 09:25:14 -0600 [thread overview]
Message-ID: <20230822-array-and-string-like-v1-8-2dcea29b0567@adacore.com> (raw)
In-Reply-To: <20230822-array-and-string-like-v1-0-2dcea29b0567@adacore.com>
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
next prev parent reply other threads:[~2023-08-22 15:25 UTC|newest]
Thread overview: 11+ messages / expand[flat|nested] mbox.gz Atom feed top
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 ` Tom Tromey [this message]
2023-09-05 17:22 ` [PATCH 0/8] Handle array- and string-like types in DAP Tom Tromey
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20230822-array-and-string-like-v1-8-2dcea29b0567@adacore.com \
--to=tromey@adacore.com \
--cc=gdb-patches@sourceware.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
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).