Skip to content

Commit

Permalink
Fix PR gdb/19828: gdb -p <process from a container>: internal error
Browse files Browse the repository at this point in the history
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:

  ...
  tromey#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
  tromey#9  0x000000000064bb83 in is_executing (ptid=...) at .../src/gdb/thread.c:1010
  tromey#10 0x00000000004c23bb in get_pending_status (lp=0x12c5cc0, status=0x7fffffffdc0c) at .../src/gdb/linux-nat.c:1235
  tromey#11 0x00000000004c2738 in detach_callback (lp=0x12c5cc0, data=0x0) at .../src/gdb/linux-nat.c:1317
  tromey#12 0x00000000004c1a2a in iterate_over_lwps (filter=..., callback=0x4c2599 <detach_callback>, data=0x0) at .../src/gdb/linux-nat.c:899
  tromey#13 0x00000000004c295c in linux_nat_detach (ops=0xe7bd30, args=0x0, from_tty=1) at .../src/gdb/linux-nat.c:1358
  tromey#14 0x000000000068284d in delegate_detach (self=0xe7bd30, arg1=0x0, arg2=1) at .../src/gdb/target-delegates.c:34
  tromey#15 0x0000000000694141 in target_detach (args=0x0, from_tty=1) at .../src/gdb/target.c:2241
  tromey#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".

gdb/ChangeLog:
2016-05-24  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-24  Pedro Alves  <palves@redhat.com>

	PR gdb/19828
	* gdb.threads/clone-attach-detach.c: New file.
	* gdb.threads/clone-attach-detach.exp: New file.
  • Loading branch information
palves committed May 24, 2016
1 parent 72b049d commit 026a917
Show file tree
Hide file tree
Showing 5 changed files with 186 additions and 0 deletions.
6 changes: 6 additions & 0 deletions gdb/ChangeLog
Original file line number Diff line number Diff line change
@@ -1,3 +1,9 @@
2016-05-24 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.

2016-05-24 Pedro Alves <palves@redhat.com>

PR gdb/19828
Expand Down
10 changes: 10 additions & 0 deletions gdb/linux-nat.c
Original file line number Diff line number Diff line change
Expand Up @@ -1172,6 +1172,16 @@ attach_proc_task_lwp_callback (ptid_t ptid)
/* We need to wait for a stop before being able to make the
next ptrace call on this LWP. */
lp->must_set_ptrace_flags = 1;

/* So that wait collects the SIGSTOP. */
lp->resumed = 1;

/* Also add the LWP to gdb's thread list, in case a
matching libthread_db is not found (or the process uses
raw clone). */
add_thread (lp->ptid);
set_running (lp->ptid, 1);
set_executing (lp->ptid, 1);
}

return 1;
Expand Down
6 changes: 6 additions & 0 deletions gdb/testsuite/ChangeLog
Original file line number Diff line number Diff line change
@@ -1,3 +1,9 @@
2016-05-24 Pedro Alves <palves@redhat.com>

PR gdb/19828
* gdb.threads/clone-attach-detach.c: New file.
* gdb.threads/clone-attach-detach.exp: New file.

2016-05-24 Francis Ricci <francisjricci@gmail.com> (tiny patch)

* gdb.base/annota-input-while-running.exp: Fix syntax error.
Expand Down
66 changes: 66 additions & 0 deletions gdb/testsuite/gdb.threads/clone-attach-detach.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
/* This testcase is part of GDB, the GNU debugger.
Copyright 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/>.
*/

#define _GNU_SOURCE
#include <sched.h>
#include <assert.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/wait.h>
#include <unistd.h>

#define STACK_SIZE 0x1000

int clone_pid;

static int
clone_fn (void *unused)
{
/* Wait for alarm. */
while (1)
sleep (1);
return 0;
}

int
main (int argc, char **argv)
{
unsigned char *stack;
int res;

alarm (300);

stack = malloc (STACK_SIZE);
assert (stack != NULL);

#define CLONE_FLAGS (CLONE_THREAD | CLONE_SIGHAND | CLONE_VM)

#ifdef __ia64__
clone_pid = __clone2 (clone_fn, stack, STACK_SIZE, CLONE_FLAGS, NULL);
#else
clone_pid = clone (clone_fn, stack + STACK_SIZE, CLONE_FLAGS, NULL);
#endif

assert (clone_pid > 0);

/* Wait for alarm. */
while (1)
sleep (1);

return 0;
}
98 changes: 98 additions & 0 deletions gdb/testsuite/gdb.threads/clone-attach-detach.exp
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
# This testcase is part of GDB, the GNU debugger.

# Copyright 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 attach / detach from a process that uses raw clone. We use raw
# clone as proxy for when libthread_db is not available.

# This only works on targets with the Linux kernel.
if ![istarget *-*-linux*] {
return
}

if {![can_spawn_for_attach]} {
return 0
}

standard_testfile

if [prepare_for_testing "failed to prepare" $testfile $srcfile {debug}] {
return -1
}

clean_restart ${binfile}

set test_spawn_id [spawn_wait_for_attach $binfile]
set testpid [spawn_id_get_pid $test_spawn_id]

# Native/gdbserver.
set thread_re "(LWP $decimal|Thread )"

# Try attach / detach a few times, in case GDB ends up with stale
# state after detaching.

set attempts 3
for {set attempt 1} {$attempt <= $attempts} {incr attempt} {