| # Copyright (C) 2017-2021 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 quitting GDB with live inferiors. |
| # |
| # Exercises combinations of: |
| # |
| # - quitting with "quit" command, or with SIGTERM/SIGHUP signals. |
| # |
| # - quitting with live inferior selected, or file_stratum inferior |
| # selected. |
| # |
| # - quitting after "run", or after "attach". |
| # |
| # - quitting with local executable, or executable loaded from target |
| # directly (via default "target:/" sysroot), or with no executable |
| # loaded. |
| |
| # Note: sending an asynchronous SIGHUP with kill is not the exact same |
| # as closing GDB's input, and that resulting in SIGHUP. However, it's |
| # still a good approximation, and it has the advantage that because |
| # GDB still has a terminal, internal errors (if any) are visible in |
| # gdb.sum/gdb.log. |
| |
| standard_testfile |
| |
| if {[build_executable "failed to build" $testfile $srcfile debug]} { |
| return |
| } |
| |
| # Send signal SIG to GDB, and expect GDB to exit. |
| |
| proc test_quit_with_sig {sig} { |
| set gdb_pid [exp_pid -i [board_info host fileid]] |
| remote_exec host "kill -$sig ${gdb_pid}" |
| |
| set test "quit with SIG$sig" |
| # If GDB mishandles the signal and doesn't exit, this should FAIL |
| # with timeout. We don't expect a GDB prompt, so if we see one, |
| # we'll FAIL too (without having to wait for timeout). |
| gdb_test_multiple "" $test { |
| eof { |
| pass $test |
| } |
| } |
| } |
| |
| # Call the "quit" command with an inferior live. |
| # |
| # APPEAR_HOW specifies how the running inferior appears in GDB. Can |
| # be either: |
| # |
| # - "run" |
| # |
| # Appear via the "run" command. |
| # |
| # - "attach" |
| # |
| # Appear via the "attach" command. |
| # |
| # - "attach-nofile" |
| # |
| # Appear via the "attach" command, but with no program preloaded in |
| # GDB so that GDB reads the program directly from the target when |
| # remote debugging (i.e., from the target:/ sysroot). This makes |
| # sure that GDB doesn't misbehave if it decides to close the |
| # 'target:/.../program' exec_file after closing the remote |
| # connection. |
| # |
| # EXTRA_INFERIOR is a boolean that specifies whether we try to quit |
| # GDB with an extra executable-only (before "run") inferior selected |
| # or whether we try to quit GDB when the live inferior is selected, |
| # with no extra inferior. |
| # |
| # QUIT_HOW specifies how to tell GDB to quit. It can be either "quit" |
| # (for "quit" command), "sighup" or "sigterm" (for quitting with |
| # SIGHUP and SIGTERM signals, respectively). |
| |
| proc quit_with_live_inferior {appear_how extra_inferior quit_how} { |
| global srcfile testfile binfile |
| global gdb_spawn_id gdb_prompt |
| |
| set test_spawn_id "" |
| |
| if {$appear_how != "attach-nofile"} { |
| clean_restart $binfile |
| } else { |
| clean_restart |
| } |
| |
| if {$appear_how == "run"} { |
| if ![runto_main] then { |
| return |
| } |
| } elseif {$appear_how == "attach" || $appear_how == "attach-nofile"} { |
| set test_spawn_id [spawn_wait_for_attach $binfile] |
| set testpid [spawn_id_get_pid $test_spawn_id] |
| |
| if {[gdb_test "attach $testpid" \ |
| "Attaching to .*process $testpid.*Reading symbols from.*" \ |
| "attach"] != 0} { |
| kill_wait_spawned_process $test_spawn_id |
| return |
| } |
| } else { |
| error "unhandled '\$appear_how': $appear_how" |
| } |
| |
| if {$extra_inferior} { |
| gdb_test "add-inferior" "Added inferior 2 on connection .*" \ |
| "add empty inferior 2" |
| gdb_test "inferior 2" "Switching to inferior 2.*" \ |
| "switch to inferior 2" |
| } |
| |
| if {$quit_how == "quit"} { |
| # Make regexp that matches the "quit" command's output. |
| proc make_re {how} { |
| multi_line \ |
| "A debugging session is active.\[ \t\r\n\]*Inferior 1\[^\r\n\]* will be $how\." \ |
| "" \ |
| "Quit anyway\\? \\(y or n\\) $" |
| } |
| |
| if {$appear_how == "run"} { |
| set quit_anyway_re [make_re "killed"] |
| } else { |
| set quit_anyway_re [make_re "detached"] |
| } |
| |
| set test "quit with \"quit\"" |
| gdb_test_multiple "quit" $test { |
| -re $quit_anyway_re { |
| send_gdb "y\n" |
| gdb_test_multiple "" $test { |
| eof { |
| pass $test |
| } |
| } |
| } |
| } |
| } elseif {$quit_how == "sighup"} { |
| test_quit_with_sig HUP |
| } elseif {$quit_how == "sigterm"} { |
| test_quit_with_sig TERM |
| } else { |
| error "unhandled '\$quit_how': $quit_how" |
| } |
| |
| if {$test_spawn_id != ""} { |
| kill_wait_spawned_process $test_spawn_id |
| } |
| } |
| |
| foreach_with_prefix appear_how {"run" "attach" "attach-nofile"} { |
| if {$appear_how != "run" && ![can_spawn_for_attach]} { |
| continue |
| } |
| |
| foreach_with_prefix extra_inferior {0 1} { |
| foreach_with_prefix quit_how {"quit" "sigterm" "sighup"} { |
| quit_with_live_inferior $appear_how $extra_inferior $quit_how |
| } |
| } |
| } |