forked from Imagelibrary/binutils-gdb
When GDB attaches to a process, it looks at the /proc/PID/task/ dir
for all clone threads of that process, and attaches to each of them.
Usually, if there is more than one clone thread, it means the program
is multi threaded and linked with pthreads. Thus when GDB soon after
attaching finds and loads a libthread_db matching the process, it'll
add a thread to the thread list for each of the initially found
lower-level LWPs.
If, however, GDB fails to find/load a matching libthread_db, nothing
is adding the LWPs to the thread list. And because of that, "detach"
hits an internal error:
(gdb) PASS: gdb.threads/clone-attach-detach.exp: fg attach 1: attach
info threads
Id Target Id Frame
* 1 LWP 6891 "clone-attach-de" 0x00007f87e5fd0790 in __nanosleep_nocancel () at ../sysdeps/unix/syscall-template.S:84
(gdb) FAIL: gdb.threads/clone-attach-detach.exp: fg attach 1: info threads shows two LWPs
detach
.../src/gdb/thread.c:1010: internal-error: is_executing: Assertion `tp' failed.
A problem internal to GDB has been detected,
further debugging may prove unreliable.
Quit this debugging session? (y or n)
FAIL: gdb.threads/clone-attach-detach.exp: fg attach 1: detach (GDB internal error)
From here:
...
#8 0x00000000007ba7cc in internal_error (file=0x98ea68 ".../src/gdb/thread.c", line=1010, fmt=0x98ea30 "%s: Assertion `%s' failed.")
at .../src/gdb/common/errors.c:55
#9 0x000000000064bb83 in is_executing (ptid=...) at .../src/gdb/thread.c:1010
#10 0x00000000004c23bb in get_pending_status (lp=0x12c5cc0, status=0x7fffffffdc0c) at .../src/gdb/linux-nat.c:1235
#11 0x00000000004c2738 in detach_callback (lp=0x12c5cc0, data=0x0) at .../src/gdb/linux-nat.c:1317
#12 0x00000000004c1a2a in iterate_over_lwps (filter=..., callback=0x4c2599 <detach_callback>, data=0x0) at .../src/gdb/linux-nat.c:899
#13 0x00000000004c295c in linux_nat_detach (ops=0xe7bd30, args=0x0, from_tty=1) at .../src/gdb/linux-nat.c:1358
#14 0x000000000068284d in delegate_detach (self=0xe7bd30, arg1=0x0, arg2=1) at .../src/gdb/target-delegates.c:34
#15 0x0000000000694141 in target_detach (args=0x0, from_tty=1) at .../src/gdb/target.c:2241
#16 0x0000000000630582 in detach_command (args=0x0, from_tty=1) at .../src/gdb/infcmd.c:2975
...
Tested on x86-64 Fedora 23. Also confirmed the test passes against
gdbserver with "maint set target-non-stop".
Unfortunately, making GDB add LWPs to the thread list sooner exposes
inefficiencies that in turn result in
gdb.threads/attach-many-short-lived-threads.exp timing out frequently.
Since that testcase is really a contrived use case designed to stress
some aspects of attach/detach and thread listing, not really
representative of real programs, this commit disables the test.
gdb/ChangeLog:
2016-05-25 Pedro Alves <palves@redhat.com>
PR gdb/19828
* linux-nat.c (attach_proc_task_lwp_callback): Mark the lwp
resumed, and add the thread to GDB's thread list.
testsuite/ChangeLog:
2016-05-25 Pedro Alves <palves@redhat.com>
PR gdb/19828
* gdb.threads/clone-attach-detach.c: New file.
* gdb.threads/clone-attach-detach.exp: New file.
* gdb.threads/attach-many-short-lived-threads.exp: Skip.
148 lines
4.6 KiB
Plaintext
148 lines
4.6 KiB
Plaintext
# Copyright 2008-2016 Free Software Foundation, Inc.
|
|
|
|
# This program is free software; you can redistribute it and/or modify
|
|
# it under the terms of the GNU General Public License as published by
|
|
# the Free Software Foundation; either version 3 of the License, or
|
|
# (at your option) any later version.
|
|
#
|
|
# This program is distributed in the hope that it will be useful,
|
|
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
# GNU General Public License for more details.
|
|
#
|
|
# You should have received a copy of the GNU General Public License
|
|
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
# Test attaching to a program that is constantly spawning short-lived
|
|
# threads. The stresses the edge cases of attaching to threads that
|
|
# have just been created or are in process of dying. In addition, the
|
|
# test attaches, debugs, detaches, reattaches in a loop a few times,
|
|
# to stress the behavior of the debug API around detach (some systems
|
|
# end up leaving stale state behind that confuse the following
|
|
# attach).
|
|
|
|
# Disabled in gdb 7.11.1 because the fix for PR gdb/19828 exposes
|
|
# latent inefficiencies that make this test often time out.
|
|
return
|
|
|
|
if {![can_spawn_for_attach]} {
|
|
return 0
|
|
}
|
|
|
|
standard_testfile
|
|
|
|
# The test proper. See description above.
|
|
|
|
proc test {} {
|
|
global binfile
|
|
global gdb_prompt
|
|
global decimal
|
|
|
|
clean_restart ${binfile}
|
|
|
|
set test_spawn_id [spawn_wait_for_attach $binfile]
|
|
set testpid [spawn_id_get_pid $test_spawn_id]
|
|
|
|
set attempts 10
|
|
for {set attempt 1} { $attempt <= $attempts } { incr attempt } {
|
|
with_test_prefix "iter $attempt" {
|
|
set attached 0
|
|
set eperm 0
|
|
set test "attach"
|
|
gdb_test_multiple "attach $testpid" $test {
|
|
-re "new threads in iteration" {
|
|
# Seen when "set debug libthread_db" is on.
|
|
exp_continue
|
|
}
|
|
-re "warning: Cannot attach to lwp $decimal: Operation not permitted" {
|
|
# On Linux, PTRACE_ATTACH sometimes fails with
|
|
# EPERM, even though /proc/PID/status indicates
|
|
# the thread is running.
|
|
set eperm 1
|
|
exp_continue
|
|
}
|
|
-re "debugger service failed.*$gdb_prompt $" {
|
|
fail $test
|
|
}
|
|
-re "$gdb_prompt $" {
|
|
if {$eperm} {
|
|
xfail "$test (EPERM)"
|
|
} else {
|
|
pass $test
|
|
}
|
|
}
|
|
-re "Attaching to program.*process $testpid.*$gdb_prompt $" {
|
|
pass $test
|
|
}
|
|
}
|
|
|
|
# Sleep a bit and try updating the thread list. We should
|
|
# know about all threads already at this point. If we see
|
|
# "New Thread" or similar being output, then "attach" is
|
|
# failing to actually attach to all threads in the process,
|
|
# which would be a bug.
|
|
sleep 1
|
|
|
|
set test "no new threads"
|
|
gdb_test_multiple "info threads" $test {
|
|
-re "New .*$gdb_prompt $" {
|
|
fail $test
|
|
}
|
|
-re "$gdb_prompt $" {
|
|
pass $test
|
|
}
|
|
}
|
|
|
|
# Force breakpoints always inserted, so that threads we might
|
|
# have failed to attach to hit them even when threads we do
|
|
# know about are stopped.
|
|
gdb_test_no_output "set breakpoint always-inserted on"
|
|
|
|
# Run to a breakpoint a few times. A few threads should spawn
|
|
# and die meanwhile. This checks that thread creation/death
|
|
# events carry on correctly after attaching. Also, be
|
|
# detaching from the program and reattaching, we check that
|
|
# the program doesn't die due to gdb leaving a pending
|
|
# breakpoint hit on a new thread unprocessed.
|
|
gdb_test "break break_fn" "Breakpoint.*" "break break_fn"
|
|
|
|
# Wait a bit, to give time for most threads to hit the
|
|
# breakpoint, including threads we might have failed to
|
|
# attach.
|
|
sleep 2
|
|
|
|
set bps 3
|
|
for {set bp 1} { $bp <= $bps } { incr bp } {
|
|
gdb_test "continue" "Breakpoint.*" "break at break_fn: $bp"
|
|
}
|
|
|
|
if {$attempt < $attempts} {
|
|
# Kick the time out timer for another round.
|
|
gdb_test "print again = 1" " = 1" "reset timer in the inferior"
|
|
# Show the time we had left in the logs, in case
|
|
# something goes wrong.
|
|
gdb_test "print seconds_left" " = .*"
|
|
|
|
gdb_test "detach" "Detaching from.*"
|
|
} else {
|
|
gdb_test "kill" "" "kill process" "Kill the program being debugged.*y or n. $" "y"
|
|
}
|
|
|
|
gdb_test_no_output "set breakpoint always-inserted off"
|
|
delete_breakpoints
|
|
}
|
|
}
|
|
kill_wait_spawned_process $test_spawn_id
|
|
}
|
|
|
|
# The test program exits after a while, in case GDB crashes. Make it
|
|
# wait at least as long as we may wait before declaring a time out
|
|
# failure.
|
|
set options { "additional_flags=-DTIMEOUT=$timeout" debug pthreads }
|
|
|
|
if {[prepare_for_testing "failed to prepare" $testfile $srcfile $options] == -1} {
|
|
return -1
|
|
}
|
|
|
|
test
|