From 147fe7f9fb9a89b217d11d73053f53e8edacf90f Mon Sep 17 00:00:00 2001 From: Tom de Vries Date: Mon, 6 May 2024 14:27:09 +0200 Subject: [gdb/testsuite] Handle ptrace operation not permitted in can_spawn_for_attach When running the testsuite on a system with kernel.yama.ptrace_scope set to 1, we run into attach failures. Fix this by recognizing "ptrace: Operation not permitted" in can_spawn_for_attach. Tested on aarch64-linux and x86_64-linux. Approved-By: Pedro Alves --- gdb/testsuite/gdb.base/break-interp.exp | 4 + gdb/testsuite/gdb.base/dprintf-detach.exp | 2 +- .../gdb.base/run-control-while-bg-execution.exp | 3 + gdb/testsuite/gdb.multi/attach-while-running.exp | 2 +- gdb/testsuite/gdb.threads/attach-into-signal.exp | 3 +- gdb/testsuite/gdb.threads/attach-slow-waitpid.exp | 3 +- gdb/testsuite/gdb.threads/attach-stopped.exp | 3 +- gdb/testsuite/gdb.threads/check-libthread-db.exp | 42 ++++---- gdb/testsuite/lib/gdb.exp | 112 ++++++++++++++++++--- 9 files changed, 135 insertions(+), 39 deletions(-) diff --git a/gdb/testsuite/gdb.base/break-interp.exp b/gdb/testsuite/gdb.base/break-interp.exp index addacde..d7f84db 100644 --- a/gdb/testsuite/gdb.base/break-interp.exp +++ b/gdb/testsuite/gdb.base/break-interp.exp @@ -318,6 +318,10 @@ proc test_attach_gdb {file pid displacement prefix} { } proc test_attach {file displacement {relink_args ""}} { + if { ![can_spawn_for_attach] } { + return + } + global board_info global exec diff --git a/gdb/testsuite/gdb.base/dprintf-detach.exp b/gdb/testsuite/gdb.base/dprintf-detach.exp index 550d319..b4184d6 100644 --- a/gdb/testsuite/gdb.base/dprintf-detach.exp +++ b/gdb/testsuite/gdb.base/dprintf-detach.exp @@ -21,7 +21,7 @@ load_lib gdbserver-support.exp # The test relies on "detach/attach". -require !use_gdb_stub +require can_spawn_for_attach standard_testfile set escapedbinfile [string_to_regexp ${binfile}] diff --git a/gdb/testsuite/gdb.base/run-control-while-bg-execution.exp b/gdb/testsuite/gdb.base/run-control-while-bg-execution.exp index f1cbd93..380047a 100644 --- a/gdb/testsuite/gdb.base/run-control-while-bg-execution.exp +++ b/gdb/testsuite/gdb.base/run-control-while-bg-execution.exp @@ -110,6 +110,9 @@ proc do_test { action1 action2 } { foreach_with_prefix action1 { kill detach add none } { foreach_with_prefix action2 { start run attach } { + if { $action2 == "attach" && ![can_spawn_for_attach] } { + continue + } do_test $action1 $action2 } } diff --git a/gdb/testsuite/gdb.multi/attach-while-running.exp b/gdb/testsuite/gdb.multi/attach-while-running.exp index eade8b4..ca4fa63 100644 --- a/gdb/testsuite/gdb.multi/attach-while-running.exp +++ b/gdb/testsuite/gdb.multi/attach-while-running.exp @@ -36,7 +36,7 @@ standard_testfile -require !use_gdb_stub +require can_spawn_for_attach if { [build_executable "failed to prepare" ${testfile} ${srcfile}] } { return diff --git a/gdb/testsuite/gdb.threads/attach-into-signal.exp b/gdb/testsuite/gdb.threads/attach-into-signal.exp index 87e3407..91da960 100644 --- a/gdb/testsuite/gdb.threads/attach-into-signal.exp +++ b/gdb/testsuite/gdb.threads/attach-into-signal.exp @@ -17,7 +17,8 @@ # This file was created by Jan Kratochvil . # This test only works on Linux -require !use_gdb_stub isnative +require can_spawn_for_attach +require isnative require {!is_remote host} require {istarget *-linux*} diff --git a/gdb/testsuite/gdb.threads/attach-slow-waitpid.exp b/gdb/testsuite/gdb.threads/attach-slow-waitpid.exp index dc3e62a..28d70da 100644 --- a/gdb/testsuite/gdb.threads/attach-slow-waitpid.exp +++ b/gdb/testsuite/gdb.threads/attach-slow-waitpid.exp @@ -37,7 +37,8 @@ # during the attach phase. # This test only works on Linux -require !use_gdb_stub isnative +require can_spawn_for_attach +require isnative require {!is_remote host} require {istarget *-linux*} diff --git a/gdb/testsuite/gdb.threads/attach-stopped.exp b/gdb/testsuite/gdb.threads/attach-stopped.exp index 78e194c..0421ffc 100644 --- a/gdb/testsuite/gdb.threads/attach-stopped.exp +++ b/gdb/testsuite/gdb.threads/attach-stopped.exp @@ -18,7 +18,8 @@ # This file was updated by Jan Kratochvil . # This test only works on Linux -require !use_gdb_stub isnative +require can_spawn_for_attach +require isnative require {!is_remote host} require {istarget *-linux*} diff --git a/gdb/testsuite/gdb.threads/check-libthread-db.exp b/gdb/testsuite/gdb.threads/check-libthread-db.exp index 5662eed..6976fe6 100644 --- a/gdb/testsuite/gdb.threads/check-libthread-db.exp +++ b/gdb/testsuite/gdb.threads/check-libthread-db.exp @@ -102,25 +102,27 @@ with_test_prefix "automated load-time check" { } # Automated load-time check with NPTL fully operational. - with_test_prefix "libpthread.so fully initialized" { - clean_restart ${binfile} - - gdb_test_no_output "maint set check-libthread-db 1" - gdb_test_no_output "set debug libthread-db 1" - - set test_spawn_id [spawn_wait_for_attach $binfile] - set testpid [spawn_id_get_pid $test_spawn_id] - - gdb_test_sequence "attach $testpid" \ - "check debug libthread-db output" { - "\[\r\n\]+Running libthread_db integrity checks:" - "\[\r\n\]+\[ \]+Got thread 0x\[1-9a-f\]\[0-9a-f\]+ => \[0-9\]+ => 0x\[1-9a-f\]\[0-9a-f\]+ ... OK" - "\[\r\n\]+\[ \]+Got thread 0x\[1-9a-f\]\[0-9a-f\]+ => \[0-9\]+ => 0x\[1-9a-f\]\[0-9a-f\]+ ... OK" - "\[\r\n\]+libthread_db integrity checks passed." - "\[\r\n\]+[Thread debugging using libthread_db enabled]" - } - - gdb_exit - kill_wait_spawned_process $test_spawn_id + if { [can_spawn_for_attach] } { + with_test_prefix "libpthread.so fully initialized" { + clean_restart ${binfile} + + gdb_test_no_output "maint set check-libthread-db 1" + gdb_test_no_output "set debug libthread-db 1" + + set test_spawn_id [spawn_wait_for_attach $binfile] + set testpid [spawn_id_get_pid $test_spawn_id] + + gdb_test_sequence "attach $testpid" \ + "check debug libthread-db output" { + "\[\r\n\]+Running libthread_db integrity checks:" + "\[\r\n\]+\[ \]+Got thread 0x\[1-9a-f\]\[0-9a-f\]+ => \[0-9\]+ => 0x\[1-9a-f\]\[0-9a-f\]+ ... OK" + "\[\r\n\]+\[ \]+Got thread 0x\[1-9a-f\]\[0-9a-f\]+ => \[0-9\]+ => 0x\[1-9a-f\]\[0-9a-f\]+ ... OK" + "\[\r\n\]+libthread_db integrity checks passed." + "\[\r\n\]+[Thread debugging using libthread_db enabled]" + } + + gdb_exit + kill_wait_spawned_process $test_spawn_id + } } } diff --git a/gdb/testsuite/lib/gdb.exp b/gdb/testsuite/lib/gdb.exp index 5fb81f6..0d78691 100644 --- a/gdb/testsuite/lib/gdb.exp +++ b/gdb/testsuite/lib/gdb.exp @@ -6153,8 +6153,54 @@ proc gdb_exit { } { catch default_gdb_exit } +# Helper function for can_spawn_for_attach. Try to spawn and attach, and +# return 0 only if we cannot attach because it's unsupported. + +gdb_caching_proc can_spawn_for_attach_1 {} { + # Assume yes. + set res 1 + + set me "can_spawn_for_attach" + set src { + #include + + int + main (void) + { + sleep (600); + return 0; + } + } + if {![gdb_simple_compile $me $src executable]} { + return $res + } + + set test_spawn_id [spawn_wait_for_attach_1 $obj] + remote_file build delete $obj + + gdb_start + + set test_pid [spawn_id_get_pid $test_spawn_id] + set attaching_re "Attaching to process $test_pid" + gdb_test_multiple "attach $test_pid" "can spawn for attach" { + -re -wrap "$attaching_re\r\n.*ptrace: Operation not permitted\\." { + # Not permitted. + set res 0 + } + -re -wrap "" { + # Don't know, keep assuming yes. + } + } + + gdb_exit + + kill_wait_spawned_process $test_spawn_id + + return $res +} + # Return true if we can spawn a program on the target and attach to -# it. +# it. Calls gdb_exit for the first call in a test-case. proc can_spawn_for_attach { } { # We use exp_pid to get the inferior's pid, assuming that gives @@ -6173,8 +6219,39 @@ proc can_spawn_for_attach { } { return 0 } - # Assume yes. - return 1 + # The normal sequence to use for a runtime test like + # can_spawn_for_attach_1 is: + # - gdb_exit (don't use a running gdb, we don't know what state it is in), + # - gdb_start (start a new gdb), and + # - gdb_exit (cleanup). + # + # By making can_spawn_for_attach_1 a gdb_caching_proc, we make it + # unpredictable which test-case will call it first, and consequently a + # test-case may pass in say a full test run, but fail when run + # individually, due to a can_spawn_for_attach call in a location where a + # gdb_exit (as can_spawn_for_attach_1 does) breaks things. + # To avoid this, we move the initial gdb_exit out of + # can_spawn_for_attach_1, guaranteeing that we end up in the same state + # regardless of whether can_spawn_for_attach_1 is called. However, that + # is only necessary for the first call in a test-case, so cache the result + # in a global (which should be reset after each test-case) to keep track + # of that. + # + # In summary, we distinguish between three cases: + # - first call in first test-case. Executes can_spawn_for_attach_1. + # Calls gdb_exit, gdb_start, gdb_exit. + # - first call in following test-cases. Uses cached result of + # can_spawn_for_attach_1. Calls gdb_exit. + # - rest. Use cached result in cache_can_spawn_for_attach_1. Calls no + # gdb_start or gdb_exit. + global cache_can_spawn_for_attach_1 + if { [info exists cache_can_spawn_for_attach_1] } { + return $cache_can_spawn_for_attach_1 + } + gdb_exit + + set cache_can_spawn_for_attach_1 [can_spawn_for_attach_1] + return $cache_can_spawn_for_attach_1 } # Centralize the failure checking of "attach" command. @@ -6287,20 +6364,12 @@ proc spawn_id_get_pid { spawn_id } { return $testpid } -# Start a set of programs running and then wait for a bit, to be sure -# that they can be attached to. Return a list of processes spawn IDs, -# one element for each process spawned. It's a test error to call -# this when [can_spawn_for_attach] is false. +# Helper function for spawn_wait_for_attach and can_spawn_for_attach_1. As +# spawn_wait_for_attach, but doesn't check for can_spawn_for_attach. -proc spawn_wait_for_attach { executable_list } { +proc spawn_wait_for_attach_1 { executable_list } { set spawn_id_list {} - if ![can_spawn_for_attach] { - # The caller should have checked can_spawn_for_attach itself - # before getting here. - error "can't spawn for attach with this target/board" - } - foreach {executable} $executable_list { # Note we use Expect's spawn, not Tcl's exec, because with # spawn we control when to wait for/reap the process. That @@ -6314,6 +6383,21 @@ proc spawn_wait_for_attach { executable_list } { return $spawn_id_list } +# Start a set of programs running and then wait for a bit, to be sure +# that they can be attached to. Return a list of processes spawn IDs, +# one element for each process spawned. It's a test error to call +# this when [can_spawn_for_attach] is false. + +proc spawn_wait_for_attach { executable_list } { + if ![can_spawn_for_attach] { + # The caller should have checked can_spawn_for_attach itself + # before getting here. + error "can't spawn for attach with this target/board" + } + + return [spawn_wait_for_attach_1 $executable_list] +} + # # gdb_load_cmd -- load a file into the debugger. # ARGS - additional args to load command. -- cgit v1.1