import gdb
import gdb.types
+import itertools
import re
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 ""
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)
--- /dev/null
+# 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
--- /dev/null
+/* 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 */
+}
--- /dev/null
+-- 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;
--- /dev/null
+-- 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;
--- /dev/null
+-- 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;
--- /dev/null
+# 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
--- /dev/null
+// 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
+}