]> git.ipfire.org Git - thirdparty/binutils-gdb.git/commitdiff
[gdb/testsuite] Handle ptrace operation not permitted in can_spawn_for_attach
authorTom de Vries <tdevries@suse.de>
Mon, 6 May 2024 12:27:09 +0000 (14:27 +0200)
committerTom de Vries <tdevries@suse.de>
Mon, 6 May 2024 12:27:09 +0000 (14:27 +0200)
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 <pedro@palves.net>
gdb/testsuite/gdb.base/break-interp.exp
gdb/testsuite/gdb.base/dprintf-detach.exp
gdb/testsuite/gdb.base/run-control-while-bg-execution.exp
gdb/testsuite/gdb.multi/attach-while-running.exp
gdb/testsuite/gdb.threads/attach-into-signal.exp
gdb/testsuite/gdb.threads/attach-slow-waitpid.exp
gdb/testsuite/gdb.threads/attach-stopped.exp
gdb/testsuite/gdb.threads/check-libthread-db.exp
gdb/testsuite/lib/gdb.exp

index addacde552de7f7802b07833eb60332a9177619e..d7f84db4770e2769c5e33734fc4f689e12af5e39 100644 (file)
@@ -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
 
index 550d319a895dfb4590656c7522e371f8c9fbee40..b4184d698df2252d44d1dce60c98d0417b7bd244 100644 (file)
@@ -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}]
index f1cbd9351d30bd8a6843714711d039ba6fda32f3..380047ae854d6f88f7d09d6af0bb2b5012c58d21 100644 (file)
@@ -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
     }
 }
index eade8b42a18ee418e851db1aeb47a985e5b34fba..ca4fa635467874346f96224da676ab687fc7cb5b 100644 (file)
@@ -36,7 +36,7 @@
 
 standard_testfile
 
-require !use_gdb_stub
+require can_spawn_for_attach
 
 if { [build_executable "failed to prepare" ${testfile} ${srcfile}] } {
     return
index 87e3407054894e9172d357ba597706d298cd9dc5..91da960e09aa475ec982e8c91e67f3b512c100df 100644 (file)
@@ -17,7 +17,8 @@
 # This file was created by Jan Kratochvil <jan.kratochvil@redhat.com>.
 
 # 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*}
 
index dc3e62a7b7eefdcad406d46dc9b071f1e8e51933..28d70daad8c5d0142b5c0b24361e9db338eb2c81 100644 (file)
@@ -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*}
 
index 78e194c992f95b354b0567876bb4bd4323d106d2..0421ffc3794949fa1bf9ec0f873d64c4f260b59c 100644 (file)
@@ -18,7 +18,8 @@
 # This file was updated by Jan Kratochvil <jan.kratochvil@redhat.com>.
 
 # 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*}
 
index 5662eeda0770fc0c698d85c2bc3ffb6ee548c445..6976fe6f83bf2b23b1409d31ff5150b649ccb5c9 100644 (file)
@@ -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
+       }
     }
 }
index 5fb81f6e28d1a052cb98198db31d18dd6c724508..0d78691c381b14b36889e652ce32b77266d230a0 100644 (file)
@@ -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 <unistd.h>
+
+       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.