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. */
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)
{
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
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
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.
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.
}
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.
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
}
}
+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.
# 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 }
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
}
}
+ 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
# 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.