| # Copyright 2023-2025 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 DAP stack format options. |
| |
| require allow_dap_tests |
| |
| load_lib dap-support.exp |
| |
| standard_testfile |
| |
| if {[build_executable ${testfile}.exp $testfile] == -1} { |
| return |
| } |
| |
| set remote_python_file [gdb_remote_download host \ |
| ${srcdir}/${subdir}/${testfile}.py] |
| |
| save_vars GDBFLAGS { |
| append GDBFLAGS " -iex \"source $remote_python_file\"" |
| |
| if {[dap_initialize] == ""} { |
| return |
| } |
| } |
| |
| set launch_id [dap_launch $testfile] |
| |
| set line [gdb_get_line_number "BREAK"] |
| 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 "configurationDone" configurationDone |
| |
| dap_check_response "launch response" launch $launch_id |
| |
| dap_wait_for_event_and_check "stopped at line breakpoint" stopped \ |
| "body reason" breakpoint \ |
| "body hitBreakpointIds" $line_bpno |
| |
| |
| # Each request should return the same frame ID. Store it here, |
| # indexed by requested frame. |
| array set frame_id {} |
| |
| # Request a single frame of the stack trace and check it. NAME is the |
| # name of the test. FRAME is the number of the frame to request. |
| # FORMAT is contents of the StackFrameFormat object to use. It is in |
| # TON form. EXPECTED is the expected 'name' value of the resulting |
| # frame. If REGEXP is set, then EXPECTED is a regular expression; |
| # otherwise it is treated as the exact string result. |
| proc check_stack_frame {name frame format expected {regexp 0}} { |
| with_test_prefix $name { |
| set args [format {o startFrame [i %d] levels [i 1] threadId [i 1]} \ |
| $frame] |
| if {$format != ""} { |
| append args " format \[o $format\]" |
| } |
| |
| set bt [lindex [dap_check_request_and_response "backtrace" \ |
| stackTrace $args] \ |
| 0] |
| set frame_info [lindex [dict get $bt body stackFrames] 0] |
| |
| # Each request at this level should return the same frame ID. |
| set this_id [dict get $frame_info id] |
| global frame_id |
| if {[info exists frame_id($frame)]} { |
| gdb_assert {$frame_id($frame) == $this_id} "unchanging frame id" |
| } else { |
| set frame_id($frame) $this_id |
| } |
| |
| if {$regexp} { |
| gdb_assert {[regexp $expected [dict get $frame_info name]]} \ |
| "got expected name" |
| } else { |
| gdb_assert {[dict get $frame_info name] == $expected} \ |
| "got expected name" |
| } |
| } |
| } |
| |
| check_stack_frame empty 0 {} "function" |
| |
| check_stack_frame parameters 0 {parameters [l true] \ |
| parameterTypes [l true] \ |
| parameterNames [l true] \ |
| parameterValues [l true]} \ |
| {function([int] x = 64, [char] y = 65 'A')} |
| |
| # When 'parameters' is false, it disables the other parameter* |
| # options. This was clarified in |
| # https://github.com/microsoft/debug-adapter-protocol/issues/411 |
| check_stack_frame noparams 0 {parameters [l false] \ |
| parameterTypes [l true] \ |
| parameterNames [l true] \ |
| parameterValues [l true]} \ |
| "function" |
| |
| check_stack_frame line 0 {line [l true] module [l true]} \ |
| "function, line $line, module .*stack-format" \ |
| 1 |
| |
| check_stack_frame hex 0 \ |
| {parameters [l true] parameterValues [l true] hex [l true]} \ |
| "function(0x40, 0x41)" |
| |
| check_stack_frame elided-main 1 {} "main" |
| |
| # The next requests will ask for all frames, so the old frame 1 will |
| # be the new frame 4. Update the map to check this. |
| set frame_id(4) $frame_id(1) |
| unset frame_id(1) |
| |
| check_stack_frame no-elide 0 {includeAll [l true]} "function" |
| check_stack_frame z-frame-1 1 {includeAll [l true]} "z_1" |
| check_stack_frame z-frame-2 2 {includeAll [l true]} "z_2" |
| check_stack_frame z-frame-3 3 {includeAll [l true]} "z_3" |
| check_stack_frame main-include-all 4 {includeAll [l true]} "main" |
| |
| dap_shutdown |