diff options
author | Yao Qi <yao.qi@linaro.org> | 2016-06-17 10:25:12 +0100 |
---|---|---|
committer | Yao Qi <yao.qi@linaro.org> | 2016-06-17 10:38:55 +0100 |
commit | f50bf8e5153e3cdddd1ad5d3f7d16f2b4e5adb3c (patch) | |
tree | ac0815d07b13c8d80b7ee797b0a7d32333743abe /gdb/testsuite | |
parent | 8376a3cbf73ca8b623db1daa8f9c49fb83ac54bd (diff) | |
download | gdb-f50bf8e5153e3cdddd1ad5d3f7d16f2b4e5adb3c.zip gdb-f50bf8e5153e3cdddd1ad5d3f7d16f2b4e5adb3c.tar.gz gdb-f50bf8e5153e3cdddd1ad5d3f7d16f2b4e5adb3c.tar.bz2 |
Step over exit with reinsert breakpoints
This patch fixes a GDBserver crash when one thread is stepping over
a syscall instruction which is exit. Step-over isn't finished due
to the exit, but GDBserver doesn't clean up the state of step-over,
so in the wait next time, GDBserver will wait on step_over_bkpt,
which is already exited, and GDBserver crashes because
'requested_child' is NULL. See gdbserver logs below,
Need step over [LWP 14858]? yes, found breakpoint at 0x2aaaaad91307^M
proceed_all_lwps: found thread 14858 needing a step-over^M
Starting step-over on LWP 14858. Stopping all threads^M
>>>> entering void stop_all_lwps(int, lwp_info*)
....
<<<< exiting void stop_all_lwps(int, lwp_info*)^M
Done stopping all threads for step-over.^M
pc is 0x2aaaaad91307^M
Writing 0f to 0x2aaaaad91307 in process 14858^M
Could not find fast tracepoint jump at 0x2aaaaad91307 in list (uninserting).^M
pending reinsert at 0x2aaaaad91307^M
step from pc 0x2aaaaad91307^M
Resuming lwp 14858 (step, signal 0, stop not expected)^M
# Start step-over for LWP 14858
>>>> entering ptid_t linux_wait_1(ptid_t, target_waitstatus*, int)
....
LLFE: 14858 exited.
...
<<<< exiting ptid_t linux_wait_1(ptid_t, target_waitstatus*, int)
# LWP 14858 exited
.....
>>>> entering ptid_t linux_wait_1(ptid_t, target_waitstatus*, int)^M
linux_wait_1: [<all threads>]^M
step_over_bkpt set [LWP 14858.14858], doing a blocking wait
# but step_over_bkpt is still LWP 14858, which is wrong
The fix is to finish step-over if it is ongoing, and unsuspend other
threads. Without the fix in linux-low.c, GDBserver will crash in
with running gdb.base/step-over-exit.exp.
gdb/gdbserver:
2016-06-17 Yao Qi <yao.qi@linaro.org>
* linux-low.c (unsuspend_all_lwps): Declare.
(linux_low_filter_event): If thread exited, call finish_step_over.
If step-over is finished, unsuspend other threads.
gdb/testsuite:
2016-06-17 Yao Qi <yao.qi@linaro.org>
* gdb.base/step-over-exit.c: New.
* gdb.base/step-over-exit.exp: New.
Diffstat (limited to 'gdb/testsuite')
-rw-r--r-- | gdb/testsuite/ChangeLog | 5 | ||||
-rw-r--r-- | gdb/testsuite/gdb.base/step-over-exit.c | 50 | ||||
-rw-r--r-- | gdb/testsuite/gdb.base/step-over-exit.exp | 127 |
3 files changed, 182 insertions, 0 deletions
diff --git a/gdb/testsuite/ChangeLog b/gdb/testsuite/ChangeLog index 3dad273..fbdcd2b 100644 --- a/gdb/testsuite/ChangeLog +++ b/gdb/testsuite/ChangeLog @@ -1,3 +1,8 @@ +2016-06-17 Yao Qi <yao.qi@linaro.org> + + * gdb.base/step-over-exit.c: New. + * gdb.base/step-over-exit.exp: New. + 2016-06-17 Yan-Ting Lin <currygt52@gmail.com> * gdb.base/float.exp: Add target check for nds32*-*-*. diff --git a/gdb/testsuite/gdb.base/step-over-exit.c b/gdb/testsuite/gdb.base/step-over-exit.c new file mode 100644 index 0000000..fd0de71 --- /dev/null +++ b/gdb/testsuite/gdb.base/step-over-exit.c @@ -0,0 +1,50 @@ +/* This testcase is part of GDB, the GNU debugger. + + Copyright 2016 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/>. */ + +#include <stdlib.h> +#include <unistd.h> +#include <string.h> + +static void +marker (void) +{} + +int +main (void) +{ + int pid; + + pid = fork (); + if (pid == 0) /* child */ + { + _exit (0); + } + else + { + } + + pid = fork (); + if (pid == 0) /* child */ + { + marker (); + _exit (0); + } + else + { + marker (); + } +} diff --git a/gdb/testsuite/gdb.base/step-over-exit.exp b/gdb/testsuite/gdb.base/step-over-exit.exp new file mode 100644 index 0000000..9f4c826 --- /dev/null +++ b/gdb/testsuite/gdb.base/step-over-exit.exp @@ -0,0 +1,127 @@ +# Copyright 2016 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/>. + +standard_testfile + +# Test a thread is doing step-over a syscall instruction which is exit, +# and GDBserver should cleanup its state of step-over properly. + +set syscall_insn "" + +# Define the syscall instruction for each target. + +if { [istarget "i\[34567\]86-*-linux*"] || [istarget "x86_64-*-linux*"] } { + set syscall_insn "\[ \t\](int|syscall|sysenter)\[ \t\]" +} elseif { [istarget "aarch64*-*-linux*"] || [istarget "arm*-*-linux*"] } { + set syscall_insn "\[ \t\](swi|svc)\[ \t\]" +} else { + unsupported "unknown syscall instruction" + return -1 +} + +if {[prepare_for_testing $testfile.exp $testfile $srcfile debug]} { + untested $testfile.exp + return -1 +} + +# Start with a fresh gdb. +clean_restart ${testfile} +if ![runto_main] { + fail "Can't run to main" + return -1 +} + +gdb_test "set follow-fork-mode child" +gdb_test "set detach-on-fork off" + +# Step 1, find the syscall instruction address. + +gdb_test "break _exit" "Breakpoint $decimal at .*" + +# Hit the breakpoint on _exit. The address of syscall insn is recorded. + +gdb_test "continue" \ + "Continuing\\..*Breakpoint $decimal.*_exit \\(.*\\).*" \ + "continue to exit" + +gdb_test "display/i \$pc" ".*" + +# Single step until we see a syscall insn or we reach the +# upper bound of loop iterations. +set msg "find syscall insn in exit" +set steps 0 +set max_steps 1000 +gdb_test_multiple "stepi" $msg { + -re ".*$syscall_insn.*$gdb_prompt $" { + pass $msg + } + -re "x/i .*=>.*\r\n$gdb_prompt $" { + incr steps + if {$steps == $max_steps} { + fail $msg + } else { + send_gdb "stepi\n" + exp_continue + } + } +} + +if {$steps == $max_steps} { + return +} + +# Remove the display +gdb_test_no_output "delete display 1" + +set syscall_insn_addr [get_hexadecimal_valueof "\$pc" "0"] + +gdb_test "continue" "exited normally.*" "continue to end, first time" +gdb_test "inferior 1" ".*Switching to inferior 1.*" \ + "switch back to inferior 1, first time" + +delete_breakpoints + +gdb_test "break marker" + +gdb_test "continue" "Continuing\\..*Breakpoint $decimal, .*" \ + "continue to marker, first time" + +# Step 2, create a breakpoint which evaluates false, and force it +# evaluated on the target side. + +set test "set breakpoint condition-evaluation target" +gdb_test_multiple $test $test { + -re "warning: Target does not support breakpoint condition evaluation.\r\nUsing host evaluation mode instead.\r\n$gdb_prompt $" { + # Target doesn't support breakpoint condition evaluation + # on its side, but it is no harm to run the test. + } + -re "^$test\r\n$gdb_prompt $" { + } +} + +gdb_test "break \*$syscall_insn_addr if main == 0" \ + "Breakpoint \[0-9\]* at .*" + +# Resume the child process, and the step-over is being done. + +gdb_test "continue" "exited normally.*" "continue to end, second time" +gdb_test "inferior 1" ".*Switching to inferior 1.*" \ + "switch back to inferior 1, second time" + +# Switch back to the parent process, continue to the marker to +# test GDBserver's state is still correct. + +gdb_test "continue" "Continuing\\..*Breakpoint $decimal, .*" \ + "continue to marker, second time" |