diff options
-rw-r--r-- | gdb/ChangeLog | 8 | ||||
-rw-r--r-- | gdb/linux-nat.c | 35 | ||||
-rw-r--r-- | gdb/testsuite/ChangeLog | 20 | ||||
-rw-r--r-- | gdb/testsuite/gdb.base/catch-syscall.c | 10 | ||||
-rw-r--r-- | gdb/testsuite/gdb.base/catch-syscall.exp | 121 |
5 files changed, 171 insertions, 23 deletions
diff --git a/gdb/ChangeLog b/gdb/ChangeLog index 7e6440b6ae6..d922d5a8ecf 100644 --- a/gdb/ChangeLog +++ b/gdb/ChangeLog @@ -1,3 +1,11 @@ +2015-10-19 Josh Stone <jistone@redhat.com> + + * linux-nat.c (linux_handle_syscall_trap): Always update entry/ + return state, even when not actively catching syscalls at all. + (linux_handle_extended_wait): Mark syscall_state like an entry. + (wait_lwp): Set syscall_state ignored for other traps. + (linux_nat_filter_event): Likewise. + 2015-10-19 Luis Machado <lgustavo@codesourcery.com> * remote.c (remote_wait_as): Set rs->waiting_for_stop_reply to 0 diff --git a/gdb/linux-nat.c b/gdb/linux-nat.c index eb9f5bb91f6..841ec3949c3 100644 --- a/gdb/linux-nat.c +++ b/gdb/linux-nat.c @@ -1916,17 +1916,17 @@ linux_handle_syscall_trap (struct lwp_info *lp, int stopping) return 1; } + /* Always update the entry/return state, even if this particular + syscall isn't interesting to the core now. In async mode, + the user could install a new catchpoint for this syscall + between syscall enter/return, and we'll need to know to + report a syscall return if that happens. */ + lp->syscall_state = (lp->syscall_state == TARGET_WAITKIND_SYSCALL_ENTRY + ? TARGET_WAITKIND_SYSCALL_RETURN + : TARGET_WAITKIND_SYSCALL_ENTRY); + if (catch_syscall_enabled ()) { - /* Always update the entry/return state, even if this particular - syscall isn't interesting to the core now. In async mode, - the user could install a new catchpoint for this syscall - between syscall enter/return, and we'll need to know to - report a syscall return if that happens. */ - lp->syscall_state = (lp->syscall_state == TARGET_WAITKIND_SYSCALL_ENTRY - ? TARGET_WAITKIND_SYSCALL_RETURN - : TARGET_WAITKIND_SYSCALL_ENTRY); - if (catching_syscall_number (syscall_number)) { /* Alright, an event to report. */ @@ -2006,6 +2006,11 @@ linux_handle_extended_wait (struct lwp_info *lp, int status) struct target_waitstatus *ourstatus = &lp->waitstatus; int event = linux_ptrace_get_extended_event (status); + /* All extended events we currently use are mid-syscall. Only + PTRACE_EVENT_STOP is delivered more like a signal-stop, but + you have to be using PTRACE_SEIZE to get that. */ + lp->syscall_state = TARGET_WAITKIND_SYSCALL_ENTRY; + if (event == PTRACE_EVENT_FORK || event == PTRACE_EVENT_VFORK || event == PTRACE_EVENT_CLONE) { @@ -2324,6 +2329,12 @@ wait_lwp (struct lwp_info *lp) if (linux_handle_syscall_trap (lp, 1)) return wait_lwp (lp); } + else + { + /* Almost all other ptrace-stops are known to be outside of system + calls, with further exceptions in linux_handle_extended_wait. */ + lp->syscall_state = TARGET_WAITKIND_IGNORE; + } /* Handle GNU/Linux's extended waitstatus for trace events. */ if (WIFSTOPPED (status) && WSTOPSIG (status) == SIGTRAP @@ -3126,6 +3137,12 @@ linux_nat_filter_event (int lwpid, int status) if (linux_handle_syscall_trap (lp, 0)) return NULL; } + else + { + /* Almost all other ptrace-stops are known to be outside of system + calls, with further exceptions in linux_handle_extended_wait. */ + lp->syscall_state = TARGET_WAITKIND_IGNORE; + } /* Handle GNU/Linux's extended waitstatus for trace events. */ if (WIFSTOPPED (status) && WSTOPSIG (status) == SIGTRAP diff --git a/gdb/testsuite/ChangeLog b/gdb/testsuite/ChangeLog index bf3cac9af39..8a8f132c58f 100644 --- a/gdb/testsuite/ChangeLog +++ b/gdb/testsuite/ChangeLog @@ -1,3 +1,23 @@ +2015-10-19 Josh Stone <jistone@redhat.com> + + * gdb.base/catch-syscall.c: Include <sched.h>. + (unknown_syscall): New variable. + (main): Trigger a vfork and an unknown syscall. + * gdb.base/catch-syscall.exp (vfork_syscalls): New variable. + (unknown_syscall_number): Likewise. + (check_call_to_syscall): Accept an optional syscall pattern. + (check_return_from_syscall): Likewise. + (check_continue): Likewise. + (test_catch_syscall_without_args): Check for vfork and ENOSYS. + (test_catch_syscall_skipping_return): New test toggling off 'catch + syscall' to step over the syscall return, then toggling back on. + (test_catch_syscall_mid_vfork): New test turning on 'catch syscall' + during a PTRACE_EVENT_VFORK stop, in the middle of a vfork syscall. + (do_syscall_tests): Call test_catch_syscall_without_args and + test_catch_syscall_mid_vfork. + (test_catch_syscall_without_args_noxml): Check for vfork and ENOSYS. + (fill_all_syscalls_numbers): Initialize unknown_syscall_number. + 2015-10-19 Andrew Stubbs <ams@codesourcery.com> * gdb.cp/inherit.exp (print g_vB, print g_vC, print g_vD, diff --git a/gdb/testsuite/gdb.base/catch-syscall.c b/gdb/testsuite/gdb.base/catch-syscall.c index 4d0131c0d73..e65d4a4906c 100644 --- a/gdb/testsuite/gdb.base/catch-syscall.c +++ b/gdb/testsuite/gdb.base/catch-syscall.c @@ -11,6 +11,7 @@ #include <sys/syscall.h> #include <fcntl.h> #include <sys/stat.h> +#include <sched.h> /* These are the syscalls numbers used by the test. */ @@ -27,6 +28,7 @@ int pipe_syscall = SYS_pipe; int pipe2_syscall = SYS_pipe2; #endif int write_syscall = SYS_write; +int unknown_syscall = 123456789; int exit_group_syscall = SYS_exit_group; int @@ -47,6 +49,14 @@ main (void) write (fd[1], buf1, sizeof (buf1)); read (fd[0], buf2, sizeof (buf2)); + /* Test vfork-event interactions. Child exits immediately. + (Plain fork won't work on no-mmu kernel configurations.) */ + if (vfork () == 0) + _exit (0); + + /* Trigger an intentional ENOSYS. */ + syscall (unknown_syscall); + /* The last syscall. Do not change this. */ _exit (0); } diff --git a/gdb/testsuite/gdb.base/catch-syscall.exp b/gdb/testsuite/gdb.base/catch-syscall.exp index 499da322267..c1cfe23cddd 100644 --- a/gdb/testsuite/gdb.base/catch-syscall.exp +++ b/gdb/testsuite/gdb.base/catch-syscall.exp @@ -51,6 +51,10 @@ set all_syscalls_numbers { } set last_syscall "exit_group" set last_syscall_number { } +set vfork_syscalls "(vfork|clone2?)" + +set unknown_syscall_number { } + # Internal procedure used to check if, after issuing a 'catch syscall' # command (without arguments), the 'info breakpoints' command displays # that '"any syscall"' is to be caught. @@ -85,34 +89,45 @@ proc check_info_bp_many_syscalls { syscalls } { gdb_test "info breakpoints" ".*catchpoint.*keep y.*syscalls (.)?${filter_str}(.)?.*" $thistest } -# This procedure checks if there was a call to a syscall. -proc check_call_to_syscall { syscall } { +# This procedure checks if there was a call to a syscall. The optional +# pattern can match syscalls that vary in implementation, like vfork. +proc check_call_to_syscall { syscall { pattern "" } } { global decimal + if { $pattern eq "" } { + set pattern "${syscall}" + } + set thistest "program has called $syscall" - gdb_test "continue" "Catchpoint $decimal \\(call to syscall .?${syscall}.?\\).*" $thistest + gdb_test "continue" "Catchpoint $decimal \\(call to syscall .?${pattern}.?\\).*" $thistest } -# This procedure checks if the syscall returned. -proc check_return_from_syscall { syscall } { +# This procedure checks if the syscall returned. The optional pattern +# can match syscalls that vary in implementation, like vfork. +proc check_return_from_syscall { syscall { pattern "" } } { global decimal + if { $pattern eq "" } { + set pattern "${syscall}" + } + set thistest "syscall $syscall has returned" - gdb_test "continue" "Catchpoint $decimal \\(returned from syscall ${syscall}\\).*" $thistest + gdb_test "continue" "Catchpoint $decimal \\(returned from syscall ${pattern}\\).*" $thistest } # Internal procedure that performs two 'continue' commands and checks if -# a syscall call AND return occur. -proc check_continue { syscall } { +# a syscall call AND return occur. The optional pattern can match +# syscalls that vary in implementation, like vfork. +proc check_continue { syscall { pattern "" } } { # Testing if the 'continue' stops at the # specified syscall_name. If it does, then it should # first print that the infeior has called the syscall, # and after print that the syscall has returned. # Testing if the inferior has called the syscall. - check_call_to_syscall $syscall + check_call_to_syscall $syscall $pattern # And now, that the syscall has returned. - check_return_from_syscall $syscall + check_return_from_syscall $syscall $pattern } # Inserts a syscall catchpoint with an argument. @@ -154,7 +169,7 @@ proc check_for_program_end {} { } proc test_catch_syscall_without_args {} { - global all_syscalls last_syscall decimal + global all_syscalls last_syscall vfork_syscalls unknown_syscall_number decimal with_test_prefix "without arguments" { # Trying to set the syscall. @@ -167,6 +182,12 @@ proc test_catch_syscall_without_args {} { check_continue $name } + check_continue "vfork" $vfork_syscalls + + with_test_prefix "ENOSYS" { + check_continue $unknown_syscall_number + } + # At last but not least, we check if the inferior has called # the last (exit) syscall. check_call_to_syscall $last_syscall @@ -243,6 +264,64 @@ proc test_catch_syscall_restarting_inferior {} { } } +proc test_catch_syscall_skipping_return {} { + with_test_prefix "skipping return" { + with_test_prefix "entry" { + set syscall_name "write" + + insert_catch_syscall_with_arg $syscall_name + + # Let's first reach the entry of the syscall. + check_call_to_syscall $syscall_name + + # Now purposely skip the syscall return. + delete_breakpoints + gdb_test "stepi" ".*" "step over syscall return" + } + + # With a naive entry/return toggle, gdb will still think + # the target is due for a syscall return. + + with_test_prefix "entry/return" { + set syscall_name "read" + + insert_catch_syscall_with_arg $syscall_name + + # Check for entry first, then return. + check_continue $syscall_name + + # Can we finish? + check_for_program_end + } + } +} + +proc test_catch_syscall_mid_vfork {} { + global gdb_prompt decimal vfork_syscalls + + with_test_prefix "mid-vfork" { + # Verify that the system supports "catch vfork". + gdb_test "catch vfork" "Catchpoint $decimal \\(vfork\\)" "insert first vfork catchpoint" + gdb_test_multiple "continue" "continue to first vfork catchpoint" { + -re ".*Your system does not support this type\r\nof catchpoint.*$gdb_prompt $" { + unsupported "continue to first vfork catchpoint" + return + } + -re ".*Catchpoint $decimal \\(vforked process $decimal\\).*$gdb_prompt $" { + pass "continue to first vfork catchpoint" + } + } + + # Check that we now reach vfork return only. + # (The actual syscall used varies by architecture.) + gdb_test "catch syscall" "Catchpoint $decimal \\(any syscall\\)" + check_return_from_syscall "vfork" $vfork_syscalls + + # Can we finish? + check_for_program_end + } +} + proc test_catch_syscall_fail_nodatadir {} { with_test_prefix "fail no datadir" { # Sanitizing. @@ -302,10 +381,17 @@ proc do_syscall_tests {} { # This test should not trigger any catchpoints. if [runto_main] then { test_catch_syscall_with_wrong_args } - # Testing the 'catch' syscall command during a restart of + # Testing the 'catch syscall' command during a restart of # the inferior. if [runto_main] then { test_catch_syscall_restarting_inferior } + # Testing the 'catch syscall' command toggling off past a + # syscall return, then resuming entry/return as normal. + if [runto_main] then { test_catch_syscall_skipping_return } + + # Testing the 'catch syscall' command starting mid-vfork. + if [runto_main] then { test_catch_syscall_mid_vfork } + # Testing if the 'catch syscall' command works when switching to # different architectures on-the-fly (PR gdb/10737). if [runto_main] then { test_catch_syscall_multi_arch } @@ -315,7 +401,7 @@ proc test_catch_syscall_without_args_noxml {} { with_test_prefix "without args noxml" { # We will need the syscall names even not using it because we # need to know know many syscalls are in the example file. - global all_syscalls last_syscall_number all_syscalls_numbers + global decimal all_syscalls last_syscall_number unknown_syscall_number all_syscalls_numbers delete_breakpoints @@ -329,6 +415,12 @@ proc test_catch_syscall_without_args_noxml {} { } } + check_continue "vfork" $decimal + + with_test_prefix "ENOSYS" { + check_continue $unknown_syscall_number + } + # At last but not least, we check if the inferior has called # the last (exit) syscall. check_call_to_syscall $last_syscall_number @@ -466,13 +558,14 @@ proc do_syscall_tests_without_xml {} { # This procedure fills the vector "all_syscalls_numbers" with the proper # numbers for the used syscalls according to the architecture. proc fill_all_syscalls_numbers {} { - global all_syscalls_numbers last_syscall_number all_syscalls + global all_syscalls_numbers last_syscall_number unknown_syscall_number all_syscalls foreach syscall $all_syscalls { lappend all_syscalls_numbers [get_integer_valueof "${syscall}_syscall" -1] } set last_syscall_number [get_integer_valueof "exit_group_syscall" -1] + set unknown_syscall_number [get_integer_valueof "unknown_syscall" -1] } # Set up the vector all_syscalls. |