summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--gdb/ChangeLog8
-rw-r--r--gdb/linux-nat.c35
-rw-r--r--gdb/testsuite/ChangeLog20
-rw-r--r--gdb/testsuite/gdb.base/catch-syscall.c10
-rw-r--r--gdb/testsuite/gdb.base/catch-syscall.exp121
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.