2011-08-24 12:07:28 +00:00
|
|
|
/* Linux-specific PROCFS manipulation routines.
|
2015-01-01 09:32:14 +00:00
|
|
|
Copyright (C) 2009-2015 Free Software Foundation, Inc.
|
2011-08-24 12:07:28 +00:00
|
|
|
|
|
|
|
This file is part of GDB.
|
|
|
|
|
|
|
|
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/>. */
|
|
|
|
|
2014-09-12 09:11:42 +00:00
|
|
|
#include "common-defs.h"
|
2011-08-24 12:07:28 +00:00
|
|
|
#include "linux-procfs.h"
|
PR gdb/7912:
* Makefile.in (SFILES): Add filestuff.c
(COMMON_OBS): Add filestuff.o.
(filestuff.o): New target.
* auto-load.c (auto_load_objfile_script_1): Use
gdb_fopen_cloexec.
* auxv.c (procfs_xfer_auxv): Use gdb_open_cloexec.
* cli/cli-cmds.c (shell_escape): Call close_most_fds.
* cli/cli-dump.c (fopen_with_cleanup): Use gdb_fopen_cloexec.
* common/agent.c (gdb_connect_sync_socket): Use
gdb_socket_cloexec.
* common/filestuff.c: New file.
* common/filestuff.h: New file.
* common/linux-osdata.c (linux_common_core_of_thread)
(command_from_pid, commandline_from_pid, print_source_lines)
(linux_xfer_osdata_shm, linux_xfer_osdata_sem)
(linux_xfer_osdata_msg, linux_xfer_osdata_modules): Use
gdb_fopen_cloexec.
* common/linux-procfs.c (linux_proc_get_int)
(linux_proc_pid_has_state): Use gdb_fopen_cloexec.
* config.in, configure: Rebuild.
* configure.ac: Don't check for sys/socket.h. Check for
fdwalk, pipe2.
* corelow.c (core_open): Use gdb_open_cloexec.
* dwarf2read.c (write_psymtabs_to_index): Use gdb_fopen_cloexec.
* fork-child.c (fork_inferior): Call close_most_fds.
* gdb_bfd.c (gdb_bfd_open): Use gdb_open_cloexec.
* inf-child.c (inf_child_fileio_readlink): Use gdb_open_cloexec.
* linux-nat.c (linux_nat_thread_name, linux_proc_pending_signals):
Use gdb_fopen_cloexec.
(linux_proc_xfer_partial, linux_proc_xfer_spu): Use
gdb_open_cloexec.
(linux_async_pipe): Use gdb_pipe_cloexec.
* remote-fileio.c (remote_fileio_func_open): Use
gdb_open_cloexec.
* remote.c (remote_file_put, remote_file_get): Use
gdb_fopen_cloexec.
* ser-pipe.c (pipe_open): Use gdb_socketpair_cloexec,
close_most_fds.
* ser-tcp.c (net_open): Use gdb_socket_cloexec.
* ser-unix.c (hardwire_open): Use gdb_open_cloexec.
* solib.c (solib_find): Use gdb_open_cloexec.
* source.c (openp, find_and_open_source): Use gdb_open_cloexec.
* tracepoint.c (tfile_start): Use gdb_fopen_cloexec.
(tfile_open): Use gdb_open_cloexec.
* tui/tui-io.c (tui_initialize_io): Use gdb_pipe_cloexec.
* ui-file.c (gdb_fopen): Use gdb_fopen_cloexec.
* xml-support.c (xml_fetch_content_from_file): Use
gdb_fopen_cloexec.
* main.c (captured_main): Call notice_open_fds.
gdbserver
* Makefile.in (SFILES): Add filestuff.c.
(OBS): Add filestuff.o.
(filestuff.o): New target.
* config.in, configure: Rebuild.
* configure.ac: Check for fdwalk, pipe2.
2013-04-22 16:46:15 +00:00
|
|
|
#include "filestuff.h"
|
Linux: on attach, attach to lwps listed under /proc/$pid/task/
... instead of relying on libthread_db.
I wrote a test that attaches to a program that constantly spawns
short-lived threads, which exposed several issues. This is one of
them.
On Linux, we need to attach to all threads of a process (thread group)
individually. We currently rely on libthread_db to list the threads,
but that is problematic, because libthread_db relies on reading data
structures out of the inferior (which may well be corrupted). If
threads are being created or exiting just while we try to attach, we
may trip on inconsistencies in the inferior's thread list. To work
around that, when we see a seemingly corrupt list, we currently retry
a few times:
static void
thread_db_find_new_threads_2 (ptid_t ptid, int until_no_new)
{
...
if (until_no_new)
{
/* Require 4 successive iterations which do not find any new threads.
The 4 is a heuristic: there is an inherent race here, and I have
seen that 2 iterations in a row are not always sufficient to
"capture" all threads. */
...
That heuristic may well fail, and when it does, we end up with threads
in the program that aren't under GDB's control. That's obviously bad
and results in quite mistifying failures, like e.g., the process dying
for seeminly no reason when a thread that wasn't attached trips on a
breakpoint.
There's really no reason to rely on libthread_db for this nowadays
when we have /proc mounted. In that case, which is the usual case, we
can list the LWPs from /proc/PID/task/. In fact, GDBserver is already
doing this. The patch factors out that code that knows to walk the
task/ directory out of GDBserver, and makes GDB use it too.
Like GDBserver, the patch makes GDB attach to LWPs and _not_ wait for
them to stop immediately. Instead, we just tag the LWP as having an
expected stop. Because we can only set the ptrace options when the
thread stops, we need a new flag in the lwp structure to keep track of
whether we've already set the ptrace options, just like in GDBserver.
Note that nothing issues any ptrace command to the threads between the
PTRACE_ATTACH and the stop, so this is safe (unlike one scenario
described in gdbserver's linux-low.c).
When we attach to a program that has threads exiting while we attach,
it's easy to race with a thread just exiting as we try to attach to
it, like:
#1 - get current list of threads
#2 - attach to each listed thread
#3 - ooops, attach failed, thread is already gone
As this is pretty normal, we shouldn't be issuing a scary warning in
step #3.
When #3 happens, PTRACE_ATTACH usually fails with ESRCH, but sometimes
we'll see EPERM as well. That happens when the kernel still has the
thread in its task list, but the thread is marked as dead.
Unfortunately, EPERM is ambiguous and we'll get it also on other
scenarios where the thread isn't dead, and in those cases, it's useful
to get a warning. To distiguish the cases, when we get an EPERM
failure, we open /proc/PID/status, and check the thread's state -- if
the /proc file no longer exists, or the state is "Z (Zombie)" or "X
(Dead)", we ignore the EPERM error silently; otherwise, we'll warn.
Unfortunately, there seems to be a kernel race here. Sometimes I get
EPERM, and then the /proc state still indicates "R (Running)"... If
we wait a bit and retry, we do end up seeing X or Z state, or get an
ESRCH. I thought of making GDB retry the attach a few times, but even
with a 500ms wait and 4 retries, I still see the warning sometimes. I
haven't been able to identify the kernel path that causes this yet,
but in any case, it looks like a kernel bug to me. As this just
results failure to suppress a warning that we've been printing since
about forever anyway, I'm just making the test cope with it, and issue
an XFAIL.
gdb/gdbserver/
2015-01-09 Pedro Alves <palves@redhat.com>
* linux-low.c (linux_attach_fail_reason_string): Move to
nat/linux-ptrace.c, and rename.
(linux_attach_lwp): Update comment.
(attach_proc_task_lwp_callback): New function.
(linux_attach): Adjust to rename and use
linux_proc_attach_tgid_threads.
(linux_attach_fail_reason_string): Delete declaration.
gdb/
2015-01-09 Pedro Alves <palves@redhat.com>
* linux-nat.c (attach_proc_task_lwp_callback): New function.
(linux_nat_attach): Use linux_proc_attach_tgid_threads.
(wait_lwp, linux_nat_filter_event): If not set yet, set the lwp's
ptrace option flags.
* linux-nat.h (struct lwp_info) <must_set_ptrace_flags>: New
field.
* nat/linux-procfs.c: Include <dirent.h>.
(linux_proc_get_int): New parameter "warn". Handle it.
(linux_proc_get_tgid): Adjust.
(linux_proc_get_tracerpid): Rename to ...
(linux_proc_get_tracerpid_nowarn): ... this.
(linux_proc_pid_get_state): New function, factored out from
(linux_proc_pid_has_state): ... this. Add new parameter "warn"
and handle it.
(linux_proc_pid_is_gone): New function.
(linux_proc_pid_is_stopped): Adjust.
(linux_proc_pid_is_zombie_maybe_warn)
(linux_proc_pid_is_zombie_nowarn): New functions.
(linux_proc_pid_is_zombie): Use
linux_proc_pid_is_zombie_maybe_warn.
(linux_proc_attach_tgid_threads): New function.
* nat/linux-procfs.h (linux_proc_get_tgid): Update comment.
(linux_proc_get_tracerpid): Rename to ...
(linux_proc_get_tracerpid_nowarn): ... this, and update comment.
(linux_proc_pid_is_gone): New declaration.
(linux_proc_pid_is_zombie): Update comment.
(linux_proc_pid_is_zombie_nowarn): New declaration.
(linux_proc_attach_lwp_func): New typedef.
(linux_proc_attach_tgid_threads): New declaration.
* nat/linux-ptrace.c (linux_ptrace_attach_fail_reason): Adjust to
use nowarn functions.
(linux_ptrace_attach_fail_reason_string): Move here from
gdbserver/linux-low.c and rename.
(ptrace_supports_feature): If the current ptrace options are not
known yet, check them now, instead of asserting.
* nat/linux-ptrace.h (linux_ptrace_attach_fail_reason_string):
Declare.
2014-12-16 16:12:24 +00:00
|
|
|
#include <dirent.h>
|
GNU/Linux: Stop using libthread_db/td_ta_thr_iter
TL;DR - GDB can hang if something refreshes the thread list out of the
target while the target is running. GDB hangs inside td_ta_thr_iter.
The fix is to not use that libthread_db function anymore.
Long version:
Running the testsuite against my all-stop-on-top-of-non-stop series is
still exposing latent non-stop bugs.
I was originally seeing this with the multi-create.exp test, back when
we were still using libthread_db thread event breakpoints. The
all-stop-on-top-of-non-stop series forces a thread list refresh each
time GDB needs to start stepping over a breakpoint (to pause all
threads). That test hits the thread event breakpoint often, resulting
in a bunch of step-over operations, thus a bunch of thread list
refreshes while some threads in the target are running.
The commit adds a real non-stop mode test that triggers the issue,
based on multi-create.exp, that does an explicit "info threads" when a
breakpoint is hit. IOW, it does the same things the as-ns series was
doing when testing multi-create.exp.
The bug is a race, so it unfortunately takes several runs for the test
to trigger it. In fact, even when setting the test running in a loop,
it sometimes takes several minutes for it to trigger for me.
The race is related to libthread_db's td_ta_thr_iter. This is
libthread_db's entry point for walking the thread list of the
inferior.
Sometimes, when GDB refreshes the thread list from the target,
libthread_db's td_ta_thr_iter can somehow see glibc's thread list as a
cycle, and get stuck in an infinite loop.
The issue is that when a thread exits, its thread control structure in
glibc is moved from a "used" list to a "cache" list. These lists are
simply circular linked lists where the "next/prev" pointers are
embedded in the thread control structure itself. The "next" pointer
of the last element of the list points back to the list's sentinel
"head". There's only one set of "next/prev" pointers for both lists;
thus a thread can only be in one of the lists at a time, not in both
simultaneously.
So when thread C exits, simplifying, the following happens. A-C are
threads. stack_used and stack_cache are the list's heads.
Before:
stack_used -> A -> B -> C -> (&stack_used)
stack_cache -> (&stack_cache)
After:
stack_used -> A -> B -> (&stack_used)
stack_cache -> C -> (&stack_cache)
td_ta_thr_iter starts by iterating at the list's head's next, and
iterates until it sees a thread whose next pointer points to the
list's head again. Thus in the before case above, C's next points to
stack_used, indicating end of list. In the same case, the stack_cache
list is empty.
For each thread being iterated, td_ta_thr_iter reads the whole thread
object out of the inferior. This includes the thread's "next"
pointer.
In the scenario above, it may happen that td_ta_thr_iter is iterating
thread B and has already read B's thread structure just before thread
C exits and its control structure moves to the cached list.
Now, recall that td_ta_thr_iter is running in the context of GDB, and
there's no locking between GDB and the inferior. From it's local copy
of B, td_ta_thr_iter believes that the next thread after B is thread
C, so it happilly continues iterating to C, a thread that has already
exited, and is now in the stack cache list.
After iterating C, td_ta_thr_iter finds the stack_cache head, which
because it is not stack_used, td_ta_thr_iter assumes it's just another
thread. After this, unless the reverse race triggers, GDB gets stuck
in td_ta_thr_iter forever walking the stack_cache list, as no thread
in thatlist has a next pointer that points back to stack_used (the
terminating condition).
Before fully understanding the issue, I tried adding cycle detection
to GDB's td_ta_thr_iter callback. However, td_ta_thr_iter skips
calling the callback in some cases, which means that it's possible
that the callback isn't called at all, making it impossible for GDB to
break the loop. I did manage to get GDB stuck in that state more than
once.
Fortunately, we can avoid the issue altogether. We don't really need
td_ta_thr_iter for live debugging nowadays, given PTRACE_EVENT_CLONE.
We already know how to map and lwp id to a thread id without iterating
(thread_from_lwp), so use that more.
gdb/ChangeLog:
2015-02-20 Pedro Alves <palves@redhat.com>
* linux-nat.c (linux_handle_extended_wait): Call
thread_db_notice_clone whenever a new clone LWP is detected.
(linux_stop_and_wait_all_lwps, linux_unstop_all_lwps): New
functions.
* linux-nat.h (thread_db_attach_lwp): Delete declaration.
(thread_db_notice_clone, linux_stop_and_wait_all_lwps)
(linux_unstop_all_lwps): Declare.
* linux-thread-db.c (struct thread_get_info_inout): Delete.
(thread_get_info_callback): Delete.
(thread_from_lwp): Use td_thr_get_info and record_thread.
(thread_db_attach_lwp): Delete.
(thread_db_notice_clone): New function.
(try_thread_db_load_1): If /proc is mounted and shows the
process'es task list, walk over all LWPs and call thread_from_lwp
instead of relying on td_ta_thr_iter.
(attach_thread): Don't call check_thread_signals here. Split the
tail part of the function (which adds the thread to the core GDB
thread list) to ...
(record_thread): ... this function. Call check_thread_signals
here.
(thread_db_wait): Don't call thread_db_find_new_threads_1. Always
call thread_from_lwp.
(thread_db_update_thread_list): Rename to ...
(thread_db_update_thread_list_org): ... this.
(thread_db_update_thread_list): New function.
(thread_db_find_thread_from_tid): Delete.
(thread_db_get_ada_task_ptid): Simplify.
* nat/linux-procfs.c: Include <sys/stat.h>.
(linux_proc_task_list_dir_exists): New function.
* nat/linux-procfs.h (linux_proc_task_list_dir_exists): Declare.
gdb/gdbserver/ChangeLog:
2015-02-20 Pedro Alves <palves@redhat.com>
* thread-db.c: Include "nat/linux-procfs.h".
(thread_db_init): Skip listing new threads if the kernel supports
PTRACE_EVENT_CLONE and /proc/PID/task/ is accessible.
gdb/testsuite/ChangeLog:
2015-02-20 Pedro Alves <palves@redhat.com>
* gdb.threads/multi-create-ns-info-thr.exp: New file.
2015-02-20 20:21:59 +00:00
|
|
|
#include <sys/stat.h>
|
2011-08-24 12:07:28 +00:00
|
|
|
|
|
|
|
/* Return the TGID of LWPID from /proc/pid/status. Returns -1 if not
|
|
|
|
found. */
|
|
|
|
|
2012-03-13 15:02:25 +00:00
|
|
|
static int
|
Linux: on attach, attach to lwps listed under /proc/$pid/task/
... instead of relying on libthread_db.
I wrote a test that attaches to a program that constantly spawns
short-lived threads, which exposed several issues. This is one of
them.
On Linux, we need to attach to all threads of a process (thread group)
individually. We currently rely on libthread_db to list the threads,
but that is problematic, because libthread_db relies on reading data
structures out of the inferior (which may well be corrupted). If
threads are being created or exiting just while we try to attach, we
may trip on inconsistencies in the inferior's thread list. To work
around that, when we see a seemingly corrupt list, we currently retry
a few times:
static void
thread_db_find_new_threads_2 (ptid_t ptid, int until_no_new)
{
...
if (until_no_new)
{
/* Require 4 successive iterations which do not find any new threads.
The 4 is a heuristic: there is an inherent race here, and I have
seen that 2 iterations in a row are not always sufficient to
"capture" all threads. */
...
That heuristic may well fail, and when it does, we end up with threads
in the program that aren't under GDB's control. That's obviously bad
and results in quite mistifying failures, like e.g., the process dying
for seeminly no reason when a thread that wasn't attached trips on a
breakpoint.
There's really no reason to rely on libthread_db for this nowadays
when we have /proc mounted. In that case, which is the usual case, we
can list the LWPs from /proc/PID/task/. In fact, GDBserver is already
doing this. The patch factors out that code that knows to walk the
task/ directory out of GDBserver, and makes GDB use it too.
Like GDBserver, the patch makes GDB attach to LWPs and _not_ wait for
them to stop immediately. Instead, we just tag the LWP as having an
expected stop. Because we can only set the ptrace options when the
thread stops, we need a new flag in the lwp structure to keep track of
whether we've already set the ptrace options, just like in GDBserver.
Note that nothing issues any ptrace command to the threads between the
PTRACE_ATTACH and the stop, so this is safe (unlike one scenario
described in gdbserver's linux-low.c).
When we attach to a program that has threads exiting while we attach,
it's easy to race with a thread just exiting as we try to attach to
it, like:
#1 - get current list of threads
#2 - attach to each listed thread
#3 - ooops, attach failed, thread is already gone
As this is pretty normal, we shouldn't be issuing a scary warning in
step #3.
When #3 happens, PTRACE_ATTACH usually fails with ESRCH, but sometimes
we'll see EPERM as well. That happens when the kernel still has the
thread in its task list, but the thread is marked as dead.
Unfortunately, EPERM is ambiguous and we'll get it also on other
scenarios where the thread isn't dead, and in those cases, it's useful
to get a warning. To distiguish the cases, when we get an EPERM
failure, we open /proc/PID/status, and check the thread's state -- if
the /proc file no longer exists, or the state is "Z (Zombie)" or "X
(Dead)", we ignore the EPERM error silently; otherwise, we'll warn.
Unfortunately, there seems to be a kernel race here. Sometimes I get
EPERM, and then the /proc state still indicates "R (Running)"... If
we wait a bit and retry, we do end up seeing X or Z state, or get an
ESRCH. I thought of making GDB retry the attach a few times, but even
with a 500ms wait and 4 retries, I still see the warning sometimes. I
haven't been able to identify the kernel path that causes this yet,
but in any case, it looks like a kernel bug to me. As this just
results failure to suppress a warning that we've been printing since
about forever anyway, I'm just making the test cope with it, and issue
an XFAIL.
gdb/gdbserver/
2015-01-09 Pedro Alves <palves@redhat.com>
* linux-low.c (linux_attach_fail_reason_string): Move to
nat/linux-ptrace.c, and rename.
(linux_attach_lwp): Update comment.
(attach_proc_task_lwp_callback): New function.
(linux_attach): Adjust to rename and use
linux_proc_attach_tgid_threads.
(linux_attach_fail_reason_string): Delete declaration.
gdb/
2015-01-09 Pedro Alves <palves@redhat.com>
* linux-nat.c (attach_proc_task_lwp_callback): New function.
(linux_nat_attach): Use linux_proc_attach_tgid_threads.
(wait_lwp, linux_nat_filter_event): If not set yet, set the lwp's
ptrace option flags.
* linux-nat.h (struct lwp_info) <must_set_ptrace_flags>: New
field.
* nat/linux-procfs.c: Include <dirent.h>.
(linux_proc_get_int): New parameter "warn". Handle it.
(linux_proc_get_tgid): Adjust.
(linux_proc_get_tracerpid): Rename to ...
(linux_proc_get_tracerpid_nowarn): ... this.
(linux_proc_pid_get_state): New function, factored out from
(linux_proc_pid_has_state): ... this. Add new parameter "warn"
and handle it.
(linux_proc_pid_is_gone): New function.
(linux_proc_pid_is_stopped): Adjust.
(linux_proc_pid_is_zombie_maybe_warn)
(linux_proc_pid_is_zombie_nowarn): New functions.
(linux_proc_pid_is_zombie): Use
linux_proc_pid_is_zombie_maybe_warn.
(linux_proc_attach_tgid_threads): New function.
* nat/linux-procfs.h (linux_proc_get_tgid): Update comment.
(linux_proc_get_tracerpid): Rename to ...
(linux_proc_get_tracerpid_nowarn): ... this, and update comment.
(linux_proc_pid_is_gone): New declaration.
(linux_proc_pid_is_zombie): Update comment.
(linux_proc_pid_is_zombie_nowarn): New declaration.
(linux_proc_attach_lwp_func): New typedef.
(linux_proc_attach_tgid_threads): New declaration.
* nat/linux-ptrace.c (linux_ptrace_attach_fail_reason): Adjust to
use nowarn functions.
(linux_ptrace_attach_fail_reason_string): Move here from
gdbserver/linux-low.c and rename.
(ptrace_supports_feature): If the current ptrace options are not
known yet, check them now, instead of asserting.
* nat/linux-ptrace.h (linux_ptrace_attach_fail_reason_string):
Declare.
2014-12-16 16:12:24 +00:00
|
|
|
linux_proc_get_int (pid_t lwpid, const char *field, int warn)
|
2011-08-24 12:07:28 +00:00
|
|
|
{
|
2012-03-13 15:02:25 +00:00
|
|
|
size_t field_len = strlen (field);
|
2011-08-24 12:07:28 +00:00
|
|
|
FILE *status_file;
|
|
|
|
char buf[100];
|
2012-03-13 15:02:25 +00:00
|
|
|
int retval = -1;
|
2011-08-24 12:07:28 +00:00
|
|
|
|
|
|
|
snprintf (buf, sizeof (buf), "/proc/%d/status", (int) lwpid);
|
PR gdb/7912:
* Makefile.in (SFILES): Add filestuff.c
(COMMON_OBS): Add filestuff.o.
(filestuff.o): New target.
* auto-load.c (auto_load_objfile_script_1): Use
gdb_fopen_cloexec.
* auxv.c (procfs_xfer_auxv): Use gdb_open_cloexec.
* cli/cli-cmds.c (shell_escape): Call close_most_fds.
* cli/cli-dump.c (fopen_with_cleanup): Use gdb_fopen_cloexec.
* common/agent.c (gdb_connect_sync_socket): Use
gdb_socket_cloexec.
* common/filestuff.c: New file.
* common/filestuff.h: New file.
* common/linux-osdata.c (linux_common_core_of_thread)
(command_from_pid, commandline_from_pid, print_source_lines)
(linux_xfer_osdata_shm, linux_xfer_osdata_sem)
(linux_xfer_osdata_msg, linux_xfer_osdata_modules): Use
gdb_fopen_cloexec.
* common/linux-procfs.c (linux_proc_get_int)
(linux_proc_pid_has_state): Use gdb_fopen_cloexec.
* config.in, configure: Rebuild.
* configure.ac: Don't check for sys/socket.h. Check for
fdwalk, pipe2.
* corelow.c (core_open): Use gdb_open_cloexec.
* dwarf2read.c (write_psymtabs_to_index): Use gdb_fopen_cloexec.
* fork-child.c (fork_inferior): Call close_most_fds.
* gdb_bfd.c (gdb_bfd_open): Use gdb_open_cloexec.
* inf-child.c (inf_child_fileio_readlink): Use gdb_open_cloexec.
* linux-nat.c (linux_nat_thread_name, linux_proc_pending_signals):
Use gdb_fopen_cloexec.
(linux_proc_xfer_partial, linux_proc_xfer_spu): Use
gdb_open_cloexec.
(linux_async_pipe): Use gdb_pipe_cloexec.
* remote-fileio.c (remote_fileio_func_open): Use
gdb_open_cloexec.
* remote.c (remote_file_put, remote_file_get): Use
gdb_fopen_cloexec.
* ser-pipe.c (pipe_open): Use gdb_socketpair_cloexec,
close_most_fds.
* ser-tcp.c (net_open): Use gdb_socket_cloexec.
* ser-unix.c (hardwire_open): Use gdb_open_cloexec.
* solib.c (solib_find): Use gdb_open_cloexec.
* source.c (openp, find_and_open_source): Use gdb_open_cloexec.
* tracepoint.c (tfile_start): Use gdb_fopen_cloexec.
(tfile_open): Use gdb_open_cloexec.
* tui/tui-io.c (tui_initialize_io): Use gdb_pipe_cloexec.
* ui-file.c (gdb_fopen): Use gdb_fopen_cloexec.
* xml-support.c (xml_fetch_content_from_file): Use
gdb_fopen_cloexec.
* main.c (captured_main): Call notice_open_fds.
gdbserver
* Makefile.in (SFILES): Add filestuff.c.
(OBS): Add filestuff.o.
(filestuff.o): New target.
* config.in, configure: Rebuild.
* configure.ac: Check for fdwalk, pipe2.
2013-04-22 16:46:15 +00:00
|
|
|
status_file = gdb_fopen_cloexec (buf, "r");
|
2012-03-13 15:02:25 +00:00
|
|
|
if (status_file == NULL)
|
2011-08-24 12:07:28 +00:00
|
|
|
{
|
Linux: on attach, attach to lwps listed under /proc/$pid/task/
... instead of relying on libthread_db.
I wrote a test that attaches to a program that constantly spawns
short-lived threads, which exposed several issues. This is one of
them.
On Linux, we need to attach to all threads of a process (thread group)
individually. We currently rely on libthread_db to list the threads,
but that is problematic, because libthread_db relies on reading data
structures out of the inferior (which may well be corrupted). If
threads are being created or exiting just while we try to attach, we
may trip on inconsistencies in the inferior's thread list. To work
around that, when we see a seemingly corrupt list, we currently retry
a few times:
static void
thread_db_find_new_threads_2 (ptid_t ptid, int until_no_new)
{
...
if (until_no_new)
{
/* Require 4 successive iterations which do not find any new threads.
The 4 is a heuristic: there is an inherent race here, and I have
seen that 2 iterations in a row are not always sufficient to
"capture" all threads. */
...
That heuristic may well fail, and when it does, we end up with threads
in the program that aren't under GDB's control. That's obviously bad
and results in quite mistifying failures, like e.g., the process dying
for seeminly no reason when a thread that wasn't attached trips on a
breakpoint.
There's really no reason to rely on libthread_db for this nowadays
when we have /proc mounted. In that case, which is the usual case, we
can list the LWPs from /proc/PID/task/. In fact, GDBserver is already
doing this. The patch factors out that code that knows to walk the
task/ directory out of GDBserver, and makes GDB use it too.
Like GDBserver, the patch makes GDB attach to LWPs and _not_ wait for
them to stop immediately. Instead, we just tag the LWP as having an
expected stop. Because we can only set the ptrace options when the
thread stops, we need a new flag in the lwp structure to keep track of
whether we've already set the ptrace options, just like in GDBserver.
Note that nothing issues any ptrace command to the threads between the
PTRACE_ATTACH and the stop, so this is safe (unlike one scenario
described in gdbserver's linux-low.c).
When we attach to a program that has threads exiting while we attach,
it's easy to race with a thread just exiting as we try to attach to
it, like:
#1 - get current list of threads
#2 - attach to each listed thread
#3 - ooops, attach failed, thread is already gone
As this is pretty normal, we shouldn't be issuing a scary warning in
step #3.
When #3 happens, PTRACE_ATTACH usually fails with ESRCH, but sometimes
we'll see EPERM as well. That happens when the kernel still has the
thread in its task list, but the thread is marked as dead.
Unfortunately, EPERM is ambiguous and we'll get it also on other
scenarios where the thread isn't dead, and in those cases, it's useful
to get a warning. To distiguish the cases, when we get an EPERM
failure, we open /proc/PID/status, and check the thread's state -- if
the /proc file no longer exists, or the state is "Z (Zombie)" or "X
(Dead)", we ignore the EPERM error silently; otherwise, we'll warn.
Unfortunately, there seems to be a kernel race here. Sometimes I get
EPERM, and then the /proc state still indicates "R (Running)"... If
we wait a bit and retry, we do end up seeing X or Z state, or get an
ESRCH. I thought of making GDB retry the attach a few times, but even
with a 500ms wait and 4 retries, I still see the warning sometimes. I
haven't been able to identify the kernel path that causes this yet,
but in any case, it looks like a kernel bug to me. As this just
results failure to suppress a warning that we've been printing since
about forever anyway, I'm just making the test cope with it, and issue
an XFAIL.
gdb/gdbserver/
2015-01-09 Pedro Alves <palves@redhat.com>
* linux-low.c (linux_attach_fail_reason_string): Move to
nat/linux-ptrace.c, and rename.
(linux_attach_lwp): Update comment.
(attach_proc_task_lwp_callback): New function.
(linux_attach): Adjust to rename and use
linux_proc_attach_tgid_threads.
(linux_attach_fail_reason_string): Delete declaration.
gdb/
2015-01-09 Pedro Alves <palves@redhat.com>
* linux-nat.c (attach_proc_task_lwp_callback): New function.
(linux_nat_attach): Use linux_proc_attach_tgid_threads.
(wait_lwp, linux_nat_filter_event): If not set yet, set the lwp's
ptrace option flags.
* linux-nat.h (struct lwp_info) <must_set_ptrace_flags>: New
field.
* nat/linux-procfs.c: Include <dirent.h>.
(linux_proc_get_int): New parameter "warn". Handle it.
(linux_proc_get_tgid): Adjust.
(linux_proc_get_tracerpid): Rename to ...
(linux_proc_get_tracerpid_nowarn): ... this.
(linux_proc_pid_get_state): New function, factored out from
(linux_proc_pid_has_state): ... this. Add new parameter "warn"
and handle it.
(linux_proc_pid_is_gone): New function.
(linux_proc_pid_is_stopped): Adjust.
(linux_proc_pid_is_zombie_maybe_warn)
(linux_proc_pid_is_zombie_nowarn): New functions.
(linux_proc_pid_is_zombie): Use
linux_proc_pid_is_zombie_maybe_warn.
(linux_proc_attach_tgid_threads): New function.
* nat/linux-procfs.h (linux_proc_get_tgid): Update comment.
(linux_proc_get_tracerpid): Rename to ...
(linux_proc_get_tracerpid_nowarn): ... this, and update comment.
(linux_proc_pid_is_gone): New declaration.
(linux_proc_pid_is_zombie): Update comment.
(linux_proc_pid_is_zombie_nowarn): New declaration.
(linux_proc_attach_lwp_func): New typedef.
(linux_proc_attach_tgid_threads): New declaration.
* nat/linux-ptrace.c (linux_ptrace_attach_fail_reason): Adjust to
use nowarn functions.
(linux_ptrace_attach_fail_reason_string): Move here from
gdbserver/linux-low.c and rename.
(ptrace_supports_feature): If the current ptrace options are not
known yet, check them now, instead of asserting.
* nat/linux-ptrace.h (linux_ptrace_attach_fail_reason_string):
Declare.
2014-12-16 16:12:24 +00:00
|
|
|
if (warn)
|
|
|
|
warning (_("unable to open /proc file '%s'"), buf);
|
2012-03-13 15:02:25 +00:00
|
|
|
return -1;
|
2011-08-24 12:07:28 +00:00
|
|
|
}
|
|
|
|
|
2012-03-13 15:02:25 +00:00
|
|
|
while (fgets (buf, sizeof (buf), status_file))
|
|
|
|
if (strncmp (buf, field, field_len) == 0 && buf[field_len] == ':')
|
|
|
|
{
|
|
|
|
retval = strtol (&buf[field_len + 1], NULL, 10);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
fclose (status_file);
|
|
|
|
return retval;
|
2011-08-24 12:07:28 +00:00
|
|
|
}
|
2012-02-27 16:22:16 +00:00
|
|
|
|
2012-03-13 15:02:25 +00:00
|
|
|
/* Return the TGID of LWPID from /proc/pid/status. Returns -1 if not
|
|
|
|
found. */
|
2012-02-27 16:22:16 +00:00
|
|
|
|
|
|
|
int
|
2012-03-13 15:02:25 +00:00
|
|
|
linux_proc_get_tgid (pid_t lwpid)
|
2012-02-27 16:22:16 +00:00
|
|
|
{
|
Linux: on attach, attach to lwps listed under /proc/$pid/task/
... instead of relying on libthread_db.
I wrote a test that attaches to a program that constantly spawns
short-lived threads, which exposed several issues. This is one of
them.
On Linux, we need to attach to all threads of a process (thread group)
individually. We currently rely on libthread_db to list the threads,
but that is problematic, because libthread_db relies on reading data
structures out of the inferior (which may well be corrupted). If
threads are being created or exiting just while we try to attach, we
may trip on inconsistencies in the inferior's thread list. To work
around that, when we see a seemingly corrupt list, we currently retry
a few times:
static void
thread_db_find_new_threads_2 (ptid_t ptid, int until_no_new)
{
...
if (until_no_new)
{
/* Require 4 successive iterations which do not find any new threads.
The 4 is a heuristic: there is an inherent race here, and I have
seen that 2 iterations in a row are not always sufficient to
"capture" all threads. */
...
That heuristic may well fail, and when it does, we end up with threads
in the program that aren't under GDB's control. That's obviously bad
and results in quite mistifying failures, like e.g., the process dying
for seeminly no reason when a thread that wasn't attached trips on a
breakpoint.
There's really no reason to rely on libthread_db for this nowadays
when we have /proc mounted. In that case, which is the usual case, we
can list the LWPs from /proc/PID/task/. In fact, GDBserver is already
doing this. The patch factors out that code that knows to walk the
task/ directory out of GDBserver, and makes GDB use it too.
Like GDBserver, the patch makes GDB attach to LWPs and _not_ wait for
them to stop immediately. Instead, we just tag the LWP as having an
expected stop. Because we can only set the ptrace options when the
thread stops, we need a new flag in the lwp structure to keep track of
whether we've already set the ptrace options, just like in GDBserver.
Note that nothing issues any ptrace command to the threads between the
PTRACE_ATTACH and the stop, so this is safe (unlike one scenario
described in gdbserver's linux-low.c).
When we attach to a program that has threads exiting while we attach,
it's easy to race with a thread just exiting as we try to attach to
it, like:
#1 - get current list of threads
#2 - attach to each listed thread
#3 - ooops, attach failed, thread is already gone
As this is pretty normal, we shouldn't be issuing a scary warning in
step #3.
When #3 happens, PTRACE_ATTACH usually fails with ESRCH, but sometimes
we'll see EPERM as well. That happens when the kernel still has the
thread in its task list, but the thread is marked as dead.
Unfortunately, EPERM is ambiguous and we'll get it also on other
scenarios where the thread isn't dead, and in those cases, it's useful
to get a warning. To distiguish the cases, when we get an EPERM
failure, we open /proc/PID/status, and check the thread's state -- if
the /proc file no longer exists, or the state is "Z (Zombie)" or "X
(Dead)", we ignore the EPERM error silently; otherwise, we'll warn.
Unfortunately, there seems to be a kernel race here. Sometimes I get
EPERM, and then the /proc state still indicates "R (Running)"... If
we wait a bit and retry, we do end up seeing X or Z state, or get an
ESRCH. I thought of making GDB retry the attach a few times, but even
with a 500ms wait and 4 retries, I still see the warning sometimes. I
haven't been able to identify the kernel path that causes this yet,
but in any case, it looks like a kernel bug to me. As this just
results failure to suppress a warning that we've been printing since
about forever anyway, I'm just making the test cope with it, and issue
an XFAIL.
gdb/gdbserver/
2015-01-09 Pedro Alves <palves@redhat.com>
* linux-low.c (linux_attach_fail_reason_string): Move to
nat/linux-ptrace.c, and rename.
(linux_attach_lwp): Update comment.
(attach_proc_task_lwp_callback): New function.
(linux_attach): Adjust to rename and use
linux_proc_attach_tgid_threads.
(linux_attach_fail_reason_string): Delete declaration.
gdb/
2015-01-09 Pedro Alves <palves@redhat.com>
* linux-nat.c (attach_proc_task_lwp_callback): New function.
(linux_nat_attach): Use linux_proc_attach_tgid_threads.
(wait_lwp, linux_nat_filter_event): If not set yet, set the lwp's
ptrace option flags.
* linux-nat.h (struct lwp_info) <must_set_ptrace_flags>: New
field.
* nat/linux-procfs.c: Include <dirent.h>.
(linux_proc_get_int): New parameter "warn". Handle it.
(linux_proc_get_tgid): Adjust.
(linux_proc_get_tracerpid): Rename to ...
(linux_proc_get_tracerpid_nowarn): ... this.
(linux_proc_pid_get_state): New function, factored out from
(linux_proc_pid_has_state): ... this. Add new parameter "warn"
and handle it.
(linux_proc_pid_is_gone): New function.
(linux_proc_pid_is_stopped): Adjust.
(linux_proc_pid_is_zombie_maybe_warn)
(linux_proc_pid_is_zombie_nowarn): New functions.
(linux_proc_pid_is_zombie): Use
linux_proc_pid_is_zombie_maybe_warn.
(linux_proc_attach_tgid_threads): New function.
* nat/linux-procfs.h (linux_proc_get_tgid): Update comment.
(linux_proc_get_tracerpid): Rename to ...
(linux_proc_get_tracerpid_nowarn): ... this, and update comment.
(linux_proc_pid_is_gone): New declaration.
(linux_proc_pid_is_zombie): Update comment.
(linux_proc_pid_is_zombie_nowarn): New declaration.
(linux_proc_attach_lwp_func): New typedef.
(linux_proc_attach_tgid_threads): New declaration.
* nat/linux-ptrace.c (linux_ptrace_attach_fail_reason): Adjust to
use nowarn functions.
(linux_ptrace_attach_fail_reason_string): Move here from
gdbserver/linux-low.c and rename.
(ptrace_supports_feature): If the current ptrace options are not
known yet, check them now, instead of asserting.
* nat/linux-ptrace.h (linux_ptrace_attach_fail_reason_string):
Declare.
2014-12-16 16:12:24 +00:00
|
|
|
return linux_proc_get_int (lwpid, "Tgid", 1);
|
2012-03-13 15:02:25 +00:00
|
|
|
}
|
2012-02-27 16:22:16 +00:00
|
|
|
|
2012-03-13 15:02:25 +00:00
|
|
|
/* See linux-procfs.h. */
|
|
|
|
|
|
|
|
pid_t
|
Linux: on attach, attach to lwps listed under /proc/$pid/task/
... instead of relying on libthread_db.
I wrote a test that attaches to a program that constantly spawns
short-lived threads, which exposed several issues. This is one of
them.
On Linux, we need to attach to all threads of a process (thread group)
individually. We currently rely on libthread_db to list the threads,
but that is problematic, because libthread_db relies on reading data
structures out of the inferior (which may well be corrupted). If
threads are being created or exiting just while we try to attach, we
may trip on inconsistencies in the inferior's thread list. To work
around that, when we see a seemingly corrupt list, we currently retry
a few times:
static void
thread_db_find_new_threads_2 (ptid_t ptid, int until_no_new)
{
...
if (until_no_new)
{
/* Require 4 successive iterations which do not find any new threads.
The 4 is a heuristic: there is an inherent race here, and I have
seen that 2 iterations in a row are not always sufficient to
"capture" all threads. */
...
That heuristic may well fail, and when it does, we end up with threads
in the program that aren't under GDB's control. That's obviously bad
and results in quite mistifying failures, like e.g., the process dying
for seeminly no reason when a thread that wasn't attached trips on a
breakpoint.
There's really no reason to rely on libthread_db for this nowadays
when we have /proc mounted. In that case, which is the usual case, we
can list the LWPs from /proc/PID/task/. In fact, GDBserver is already
doing this. The patch factors out that code that knows to walk the
task/ directory out of GDBserver, and makes GDB use it too.
Like GDBserver, the patch makes GDB attach to LWPs and _not_ wait for
them to stop immediately. Instead, we just tag the LWP as having an
expected stop. Because we can only set the ptrace options when the
thread stops, we need a new flag in the lwp structure to keep track of
whether we've already set the ptrace options, just like in GDBserver.
Note that nothing issues any ptrace command to the threads between the
PTRACE_ATTACH and the stop, so this is safe (unlike one scenario
described in gdbserver's linux-low.c).
When we attach to a program that has threads exiting while we attach,
it's easy to race with a thread just exiting as we try to attach to
it, like:
#1 - get current list of threads
#2 - attach to each listed thread
#3 - ooops, attach failed, thread is already gone
As this is pretty normal, we shouldn't be issuing a scary warning in
step #3.
When #3 happens, PTRACE_ATTACH usually fails with ESRCH, but sometimes
we'll see EPERM as well. That happens when the kernel still has the
thread in its task list, but the thread is marked as dead.
Unfortunately, EPERM is ambiguous and we'll get it also on other
scenarios where the thread isn't dead, and in those cases, it's useful
to get a warning. To distiguish the cases, when we get an EPERM
failure, we open /proc/PID/status, and check the thread's state -- if
the /proc file no longer exists, or the state is "Z (Zombie)" or "X
(Dead)", we ignore the EPERM error silently; otherwise, we'll warn.
Unfortunately, there seems to be a kernel race here. Sometimes I get
EPERM, and then the /proc state still indicates "R (Running)"... If
we wait a bit and retry, we do end up seeing X or Z state, or get an
ESRCH. I thought of making GDB retry the attach a few times, but even
with a 500ms wait and 4 retries, I still see the warning sometimes. I
haven't been able to identify the kernel path that causes this yet,
but in any case, it looks like a kernel bug to me. As this just
results failure to suppress a warning that we've been printing since
about forever anyway, I'm just making the test cope with it, and issue
an XFAIL.
gdb/gdbserver/
2015-01-09 Pedro Alves <palves@redhat.com>
* linux-low.c (linux_attach_fail_reason_string): Move to
nat/linux-ptrace.c, and rename.
(linux_attach_lwp): Update comment.
(attach_proc_task_lwp_callback): New function.
(linux_attach): Adjust to rename and use
linux_proc_attach_tgid_threads.
(linux_attach_fail_reason_string): Delete declaration.
gdb/
2015-01-09 Pedro Alves <palves@redhat.com>
* linux-nat.c (attach_proc_task_lwp_callback): New function.
(linux_nat_attach): Use linux_proc_attach_tgid_threads.
(wait_lwp, linux_nat_filter_event): If not set yet, set the lwp's
ptrace option flags.
* linux-nat.h (struct lwp_info) <must_set_ptrace_flags>: New
field.
* nat/linux-procfs.c: Include <dirent.h>.
(linux_proc_get_int): New parameter "warn". Handle it.
(linux_proc_get_tgid): Adjust.
(linux_proc_get_tracerpid): Rename to ...
(linux_proc_get_tracerpid_nowarn): ... this.
(linux_proc_pid_get_state): New function, factored out from
(linux_proc_pid_has_state): ... this. Add new parameter "warn"
and handle it.
(linux_proc_pid_is_gone): New function.
(linux_proc_pid_is_stopped): Adjust.
(linux_proc_pid_is_zombie_maybe_warn)
(linux_proc_pid_is_zombie_nowarn): New functions.
(linux_proc_pid_is_zombie): Use
linux_proc_pid_is_zombie_maybe_warn.
(linux_proc_attach_tgid_threads): New function.
* nat/linux-procfs.h (linux_proc_get_tgid): Update comment.
(linux_proc_get_tracerpid): Rename to ...
(linux_proc_get_tracerpid_nowarn): ... this, and update comment.
(linux_proc_pid_is_gone): New declaration.
(linux_proc_pid_is_zombie): Update comment.
(linux_proc_pid_is_zombie_nowarn): New declaration.
(linux_proc_attach_lwp_func): New typedef.
(linux_proc_attach_tgid_threads): New declaration.
* nat/linux-ptrace.c (linux_ptrace_attach_fail_reason): Adjust to
use nowarn functions.
(linux_ptrace_attach_fail_reason_string): Move here from
gdbserver/linux-low.c and rename.
(ptrace_supports_feature): If the current ptrace options are not
known yet, check them now, instead of asserting.
* nat/linux-ptrace.h (linux_ptrace_attach_fail_reason_string):
Declare.
2014-12-16 16:12:24 +00:00
|
|
|
linux_proc_get_tracerpid_nowarn (pid_t lwpid)
|
2012-03-13 15:02:25 +00:00
|
|
|
{
|
Linux: on attach, attach to lwps listed under /proc/$pid/task/
... instead of relying on libthread_db.
I wrote a test that attaches to a program that constantly spawns
short-lived threads, which exposed several issues. This is one of
them.
On Linux, we need to attach to all threads of a process (thread group)
individually. We currently rely on libthread_db to list the threads,
but that is problematic, because libthread_db relies on reading data
structures out of the inferior (which may well be corrupted). If
threads are being created or exiting just while we try to attach, we
may trip on inconsistencies in the inferior's thread list. To work
around that, when we see a seemingly corrupt list, we currently retry
a few times:
static void
thread_db_find_new_threads_2 (ptid_t ptid, int until_no_new)
{
...
if (until_no_new)
{
/* Require 4 successive iterations which do not find any new threads.
The 4 is a heuristic: there is an inherent race here, and I have
seen that 2 iterations in a row are not always sufficient to
"capture" all threads. */
...
That heuristic may well fail, and when it does, we end up with threads
in the program that aren't under GDB's control. That's obviously bad
and results in quite mistifying failures, like e.g., the process dying
for seeminly no reason when a thread that wasn't attached trips on a
breakpoint.
There's really no reason to rely on libthread_db for this nowadays
when we have /proc mounted. In that case, which is the usual case, we
can list the LWPs from /proc/PID/task/. In fact, GDBserver is already
doing this. The patch factors out that code that knows to walk the
task/ directory out of GDBserver, and makes GDB use it too.
Like GDBserver, the patch makes GDB attach to LWPs and _not_ wait for
them to stop immediately. Instead, we just tag the LWP as having an
expected stop. Because we can only set the ptrace options when the
thread stops, we need a new flag in the lwp structure to keep track of
whether we've already set the ptrace options, just like in GDBserver.
Note that nothing issues any ptrace command to the threads between the
PTRACE_ATTACH and the stop, so this is safe (unlike one scenario
described in gdbserver's linux-low.c).
When we attach to a program that has threads exiting while we attach,
it's easy to race with a thread just exiting as we try to attach to
it, like:
#1 - get current list of threads
#2 - attach to each listed thread
#3 - ooops, attach failed, thread is already gone
As this is pretty normal, we shouldn't be issuing a scary warning in
step #3.
When #3 happens, PTRACE_ATTACH usually fails with ESRCH, but sometimes
we'll see EPERM as well. That happens when the kernel still has the
thread in its task list, but the thread is marked as dead.
Unfortunately, EPERM is ambiguous and we'll get it also on other
scenarios where the thread isn't dead, and in those cases, it's useful
to get a warning. To distiguish the cases, when we get an EPERM
failure, we open /proc/PID/status, and check the thread's state -- if
the /proc file no longer exists, or the state is "Z (Zombie)" or "X
(Dead)", we ignore the EPERM error silently; otherwise, we'll warn.
Unfortunately, there seems to be a kernel race here. Sometimes I get
EPERM, and then the /proc state still indicates "R (Running)"... If
we wait a bit and retry, we do end up seeing X or Z state, or get an
ESRCH. I thought of making GDB retry the attach a few times, but even
with a 500ms wait and 4 retries, I still see the warning sometimes. I
haven't been able to identify the kernel path that causes this yet,
but in any case, it looks like a kernel bug to me. As this just
results failure to suppress a warning that we've been printing since
about forever anyway, I'm just making the test cope with it, and issue
an XFAIL.
gdb/gdbserver/
2015-01-09 Pedro Alves <palves@redhat.com>
* linux-low.c (linux_attach_fail_reason_string): Move to
nat/linux-ptrace.c, and rename.
(linux_attach_lwp): Update comment.
(attach_proc_task_lwp_callback): New function.
(linux_attach): Adjust to rename and use
linux_proc_attach_tgid_threads.
(linux_attach_fail_reason_string): Delete declaration.
gdb/
2015-01-09 Pedro Alves <palves@redhat.com>
* linux-nat.c (attach_proc_task_lwp_callback): New function.
(linux_nat_attach): Use linux_proc_attach_tgid_threads.
(wait_lwp, linux_nat_filter_event): If not set yet, set the lwp's
ptrace option flags.
* linux-nat.h (struct lwp_info) <must_set_ptrace_flags>: New
field.
* nat/linux-procfs.c: Include <dirent.h>.
(linux_proc_get_int): New parameter "warn". Handle it.
(linux_proc_get_tgid): Adjust.
(linux_proc_get_tracerpid): Rename to ...
(linux_proc_get_tracerpid_nowarn): ... this.
(linux_proc_pid_get_state): New function, factored out from
(linux_proc_pid_has_state): ... this. Add new parameter "warn"
and handle it.
(linux_proc_pid_is_gone): New function.
(linux_proc_pid_is_stopped): Adjust.
(linux_proc_pid_is_zombie_maybe_warn)
(linux_proc_pid_is_zombie_nowarn): New functions.
(linux_proc_pid_is_zombie): Use
linux_proc_pid_is_zombie_maybe_warn.
(linux_proc_attach_tgid_threads): New function.
* nat/linux-procfs.h (linux_proc_get_tgid): Update comment.
(linux_proc_get_tracerpid): Rename to ...
(linux_proc_get_tracerpid_nowarn): ... this, and update comment.
(linux_proc_pid_is_gone): New declaration.
(linux_proc_pid_is_zombie): Update comment.
(linux_proc_pid_is_zombie_nowarn): New declaration.
(linux_proc_attach_lwp_func): New typedef.
(linux_proc_attach_tgid_threads): New declaration.
* nat/linux-ptrace.c (linux_ptrace_attach_fail_reason): Adjust to
use nowarn functions.
(linux_ptrace_attach_fail_reason_string): Move here from
gdbserver/linux-low.c and rename.
(ptrace_supports_feature): If the current ptrace options are not
known yet, check them now, instead of asserting.
* nat/linux-ptrace.h (linux_ptrace_attach_fail_reason_string):
Declare.
2014-12-16 16:12:24 +00:00
|
|
|
return linux_proc_get_int (lwpid, "TracerPid", 0);
|
2012-02-27 16:22:16 +00:00
|
|
|
}
|
gdb/
* Makefile.in (linux-ptrace.o): New.
* common/linux-procfs.c (linux_proc_pid_is_zombie): New,
from linux-nat.c.
* common/linux-procfs.h (linux_proc_pid_is_zombie): New declaration.
* common/linux-ptrace.c: New file.
* config/alpha/alpha-linux.mh (NATDEPFILES): Add linux-ptrace.o.
* config/arm/linux.mh: Likewise.
* config/i386/linux.mh: Likewise.
* config/i386/linux64.mh: Likewise.
* config/ia64/linux.mh: Likewise.
* config/m32r/linux.mh: Likewise.
* config/m68k/linux.mh: Likewise.
* config/mips/linux.mh: Likewise.
* config/pa/linux.mh: Likewise.
* config/powerpc/linux.mh: Likewise.
* config/powerpc/ppc64-linux.mh: Likewise.
* config/powerpc/spu-linux.mh: Likewise.
* config/s390/s390.mh: Likewise.
* config/sparc/linux.mh: Likewise.
* config/sparc/linux64.mh: Likewise.
* config/xtensa/linux.mh: Likewise.
* linux-nat.c (linux_lwp_is_zombie): Remove, move it to
common/linux-procfs.c.
(wait_lwp): Rename linux_lwp_is_zombie to linux_proc_pid_is_zombie.
gdb/gdbserver/
* Makefile.in (linux-ptrace.o): New.
* configure.srv (arm*-*-linux*, bfin-*-*linux*, crisv32-*-linux*)
(cris-*-linux*, i[34567]86-*-linux*, ia64-*-linux*, m32r*-*-linux*)
(m68*-*-linux*, m68*-*-uclinux*, mips*-*-linux*, powerpc*-*-linux*)
(s390*-*-linux*, sh*-*-linux*, sparc*-*-linux*, tic6x-*-uclinux)
(x86_64-*-linux*, xtensa*-*-linux*): Add linux-ptrace.o to SRV_TGTOBJ
of these targets.
* linux-low.c (linux_attach_lwp_1): Remove redundent else clause.
2012-03-13 15:00:37 +00:00
|
|
|
|
Linux: on attach, attach to lwps listed under /proc/$pid/task/
... instead of relying on libthread_db.
I wrote a test that attaches to a program that constantly spawns
short-lived threads, which exposed several issues. This is one of
them.
On Linux, we need to attach to all threads of a process (thread group)
individually. We currently rely on libthread_db to list the threads,
but that is problematic, because libthread_db relies on reading data
structures out of the inferior (which may well be corrupted). If
threads are being created or exiting just while we try to attach, we
may trip on inconsistencies in the inferior's thread list. To work
around that, when we see a seemingly corrupt list, we currently retry
a few times:
static void
thread_db_find_new_threads_2 (ptid_t ptid, int until_no_new)
{
...
if (until_no_new)
{
/* Require 4 successive iterations which do not find any new threads.
The 4 is a heuristic: there is an inherent race here, and I have
seen that 2 iterations in a row are not always sufficient to
"capture" all threads. */
...
That heuristic may well fail, and when it does, we end up with threads
in the program that aren't under GDB's control. That's obviously bad
and results in quite mistifying failures, like e.g., the process dying
for seeminly no reason when a thread that wasn't attached trips on a
breakpoint.
There's really no reason to rely on libthread_db for this nowadays
when we have /proc mounted. In that case, which is the usual case, we
can list the LWPs from /proc/PID/task/. In fact, GDBserver is already
doing this. The patch factors out that code that knows to walk the
task/ directory out of GDBserver, and makes GDB use it too.
Like GDBserver, the patch makes GDB attach to LWPs and _not_ wait for
them to stop immediately. Instead, we just tag the LWP as having an
expected stop. Because we can only set the ptrace options when the
thread stops, we need a new flag in the lwp structure to keep track of
whether we've already set the ptrace options, just like in GDBserver.
Note that nothing issues any ptrace command to the threads between the
PTRACE_ATTACH and the stop, so this is safe (unlike one scenario
described in gdbserver's linux-low.c).
When we attach to a program that has threads exiting while we attach,
it's easy to race with a thread just exiting as we try to attach to
it, like:
#1 - get current list of threads
#2 - attach to each listed thread
#3 - ooops, attach failed, thread is already gone
As this is pretty normal, we shouldn't be issuing a scary warning in
step #3.
When #3 happens, PTRACE_ATTACH usually fails with ESRCH, but sometimes
we'll see EPERM as well. That happens when the kernel still has the
thread in its task list, but the thread is marked as dead.
Unfortunately, EPERM is ambiguous and we'll get it also on other
scenarios where the thread isn't dead, and in those cases, it's useful
to get a warning. To distiguish the cases, when we get an EPERM
failure, we open /proc/PID/status, and check the thread's state -- if
the /proc file no longer exists, or the state is "Z (Zombie)" or "X
(Dead)", we ignore the EPERM error silently; otherwise, we'll warn.
Unfortunately, there seems to be a kernel race here. Sometimes I get
EPERM, and then the /proc state still indicates "R (Running)"... If
we wait a bit and retry, we do end up seeing X or Z state, or get an
ESRCH. I thought of making GDB retry the attach a few times, but even
with a 500ms wait and 4 retries, I still see the warning sometimes. I
haven't been able to identify the kernel path that causes this yet,
but in any case, it looks like a kernel bug to me. As this just
results failure to suppress a warning that we've been printing since
about forever anyway, I'm just making the test cope with it, and issue
an XFAIL.
gdb/gdbserver/
2015-01-09 Pedro Alves <palves@redhat.com>
* linux-low.c (linux_attach_fail_reason_string): Move to
nat/linux-ptrace.c, and rename.
(linux_attach_lwp): Update comment.
(attach_proc_task_lwp_callback): New function.
(linux_attach): Adjust to rename and use
linux_proc_attach_tgid_threads.
(linux_attach_fail_reason_string): Delete declaration.
gdb/
2015-01-09 Pedro Alves <palves@redhat.com>
* linux-nat.c (attach_proc_task_lwp_callback): New function.
(linux_nat_attach): Use linux_proc_attach_tgid_threads.
(wait_lwp, linux_nat_filter_event): If not set yet, set the lwp's
ptrace option flags.
* linux-nat.h (struct lwp_info) <must_set_ptrace_flags>: New
field.
* nat/linux-procfs.c: Include <dirent.h>.
(linux_proc_get_int): New parameter "warn". Handle it.
(linux_proc_get_tgid): Adjust.
(linux_proc_get_tracerpid): Rename to ...
(linux_proc_get_tracerpid_nowarn): ... this.
(linux_proc_pid_get_state): New function, factored out from
(linux_proc_pid_has_state): ... this. Add new parameter "warn"
and handle it.
(linux_proc_pid_is_gone): New function.
(linux_proc_pid_is_stopped): Adjust.
(linux_proc_pid_is_zombie_maybe_warn)
(linux_proc_pid_is_zombie_nowarn): New functions.
(linux_proc_pid_is_zombie): Use
linux_proc_pid_is_zombie_maybe_warn.
(linux_proc_attach_tgid_threads): New function.
* nat/linux-procfs.h (linux_proc_get_tgid): Update comment.
(linux_proc_get_tracerpid): Rename to ...
(linux_proc_get_tracerpid_nowarn): ... this, and update comment.
(linux_proc_pid_is_gone): New declaration.
(linux_proc_pid_is_zombie): Update comment.
(linux_proc_pid_is_zombie_nowarn): New declaration.
(linux_proc_attach_lwp_func): New typedef.
(linux_proc_attach_tgid_threads): New declaration.
* nat/linux-ptrace.c (linux_ptrace_attach_fail_reason): Adjust to
use nowarn functions.
(linux_ptrace_attach_fail_reason_string): Move here from
gdbserver/linux-low.c and rename.
(ptrace_supports_feature): If the current ptrace options are not
known yet, check them now, instead of asserting.
* nat/linux-ptrace.h (linux_ptrace_attach_fail_reason_string):
Declare.
2014-12-16 16:12:24 +00:00
|
|
|
/* Fill in BUFFER, a buffer with BUFFER_SIZE bytes with the 'State'
|
|
|
|
line of /proc/PID/status. Returns -1 on failure to open the /proc
|
|
|
|
file, 1 if the line is found, and 0 if not found. If WARN, warn on
|
|
|
|
failure to open the /proc file. */
|
gdb/
* Makefile.in (linux-ptrace.o): New.
* common/linux-procfs.c (linux_proc_pid_is_zombie): New,
from linux-nat.c.
* common/linux-procfs.h (linux_proc_pid_is_zombie): New declaration.
* common/linux-ptrace.c: New file.
* config/alpha/alpha-linux.mh (NATDEPFILES): Add linux-ptrace.o.
* config/arm/linux.mh: Likewise.
* config/i386/linux.mh: Likewise.
* config/i386/linux64.mh: Likewise.
* config/ia64/linux.mh: Likewise.
* config/m32r/linux.mh: Likewise.
* config/m68k/linux.mh: Likewise.
* config/mips/linux.mh: Likewise.
* config/pa/linux.mh: Likewise.
* config/powerpc/linux.mh: Likewise.
* config/powerpc/ppc64-linux.mh: Likewise.
* config/powerpc/spu-linux.mh: Likewise.
* config/s390/s390.mh: Likewise.
* config/sparc/linux.mh: Likewise.
* config/sparc/linux64.mh: Likewise.
* config/xtensa/linux.mh: Likewise.
* linux-nat.c (linux_lwp_is_zombie): Remove, move it to
common/linux-procfs.c.
(wait_lwp): Rename linux_lwp_is_zombie to linux_proc_pid_is_zombie.
gdb/gdbserver/
* Makefile.in (linux-ptrace.o): New.
* configure.srv (arm*-*-linux*, bfin-*-*linux*, crisv32-*-linux*)
(cris-*-linux*, i[34567]86-*-linux*, ia64-*-linux*, m32r*-*-linux*)
(m68*-*-linux*, m68*-*-uclinux*, mips*-*-linux*, powerpc*-*-linux*)
(s390*-*-linux*, sh*-*-linux*, sparc*-*-linux*, tic6x-*-uclinux)
(x86_64-*-linux*, xtensa*-*-linux*): Add linux-ptrace.o to SRV_TGTOBJ
of these targets.
* linux-low.c (linux_attach_lwp_1): Remove redundent else clause.
2012-03-13 15:00:37 +00:00
|
|
|
|
2012-03-13 15:02:25 +00:00
|
|
|
static int
|
Linux: on attach, attach to lwps listed under /proc/$pid/task/
... instead of relying on libthread_db.
I wrote a test that attaches to a program that constantly spawns
short-lived threads, which exposed several issues. This is one of
them.
On Linux, we need to attach to all threads of a process (thread group)
individually. We currently rely on libthread_db to list the threads,
but that is problematic, because libthread_db relies on reading data
structures out of the inferior (which may well be corrupted). If
threads are being created or exiting just while we try to attach, we
may trip on inconsistencies in the inferior's thread list. To work
around that, when we see a seemingly corrupt list, we currently retry
a few times:
static void
thread_db_find_new_threads_2 (ptid_t ptid, int until_no_new)
{
...
if (until_no_new)
{
/* Require 4 successive iterations which do not find any new threads.
The 4 is a heuristic: there is an inherent race here, and I have
seen that 2 iterations in a row are not always sufficient to
"capture" all threads. */
...
That heuristic may well fail, and when it does, we end up with threads
in the program that aren't under GDB's control. That's obviously bad
and results in quite mistifying failures, like e.g., the process dying
for seeminly no reason when a thread that wasn't attached trips on a
breakpoint.
There's really no reason to rely on libthread_db for this nowadays
when we have /proc mounted. In that case, which is the usual case, we
can list the LWPs from /proc/PID/task/. In fact, GDBserver is already
doing this. The patch factors out that code that knows to walk the
task/ directory out of GDBserver, and makes GDB use it too.
Like GDBserver, the patch makes GDB attach to LWPs and _not_ wait for
them to stop immediately. Instead, we just tag the LWP as having an
expected stop. Because we can only set the ptrace options when the
thread stops, we need a new flag in the lwp structure to keep track of
whether we've already set the ptrace options, just like in GDBserver.
Note that nothing issues any ptrace command to the threads between the
PTRACE_ATTACH and the stop, so this is safe (unlike one scenario
described in gdbserver's linux-low.c).
When we attach to a program that has threads exiting while we attach,
it's easy to race with a thread just exiting as we try to attach to
it, like:
#1 - get current list of threads
#2 - attach to each listed thread
#3 - ooops, attach failed, thread is already gone
As this is pretty normal, we shouldn't be issuing a scary warning in
step #3.
When #3 happens, PTRACE_ATTACH usually fails with ESRCH, but sometimes
we'll see EPERM as well. That happens when the kernel still has the
thread in its task list, but the thread is marked as dead.
Unfortunately, EPERM is ambiguous and we'll get it also on other
scenarios where the thread isn't dead, and in those cases, it's useful
to get a warning. To distiguish the cases, when we get an EPERM
failure, we open /proc/PID/status, and check the thread's state -- if
the /proc file no longer exists, or the state is "Z (Zombie)" or "X
(Dead)", we ignore the EPERM error silently; otherwise, we'll warn.
Unfortunately, there seems to be a kernel race here. Sometimes I get
EPERM, and then the /proc state still indicates "R (Running)"... If
we wait a bit and retry, we do end up seeing X or Z state, or get an
ESRCH. I thought of making GDB retry the attach a few times, but even
with a 500ms wait and 4 retries, I still see the warning sometimes. I
haven't been able to identify the kernel path that causes this yet,
but in any case, it looks like a kernel bug to me. As this just
results failure to suppress a warning that we've been printing since
about forever anyway, I'm just making the test cope with it, and issue
an XFAIL.
gdb/gdbserver/
2015-01-09 Pedro Alves <palves@redhat.com>
* linux-low.c (linux_attach_fail_reason_string): Move to
nat/linux-ptrace.c, and rename.
(linux_attach_lwp): Update comment.
(attach_proc_task_lwp_callback): New function.
(linux_attach): Adjust to rename and use
linux_proc_attach_tgid_threads.
(linux_attach_fail_reason_string): Delete declaration.
gdb/
2015-01-09 Pedro Alves <palves@redhat.com>
* linux-nat.c (attach_proc_task_lwp_callback): New function.
(linux_nat_attach): Use linux_proc_attach_tgid_threads.
(wait_lwp, linux_nat_filter_event): If not set yet, set the lwp's
ptrace option flags.
* linux-nat.h (struct lwp_info) <must_set_ptrace_flags>: New
field.
* nat/linux-procfs.c: Include <dirent.h>.
(linux_proc_get_int): New parameter "warn". Handle it.
(linux_proc_get_tgid): Adjust.
(linux_proc_get_tracerpid): Rename to ...
(linux_proc_get_tracerpid_nowarn): ... this.
(linux_proc_pid_get_state): New function, factored out from
(linux_proc_pid_has_state): ... this. Add new parameter "warn"
and handle it.
(linux_proc_pid_is_gone): New function.
(linux_proc_pid_is_stopped): Adjust.
(linux_proc_pid_is_zombie_maybe_warn)
(linux_proc_pid_is_zombie_nowarn): New functions.
(linux_proc_pid_is_zombie): Use
linux_proc_pid_is_zombie_maybe_warn.
(linux_proc_attach_tgid_threads): New function.
* nat/linux-procfs.h (linux_proc_get_tgid): Update comment.
(linux_proc_get_tracerpid): Rename to ...
(linux_proc_get_tracerpid_nowarn): ... this, and update comment.
(linux_proc_pid_is_gone): New declaration.
(linux_proc_pid_is_zombie): Update comment.
(linux_proc_pid_is_zombie_nowarn): New declaration.
(linux_proc_attach_lwp_func): New typedef.
(linux_proc_attach_tgid_threads): New declaration.
* nat/linux-ptrace.c (linux_ptrace_attach_fail_reason): Adjust to
use nowarn functions.
(linux_ptrace_attach_fail_reason_string): Move here from
gdbserver/linux-low.c and rename.
(ptrace_supports_feature): If the current ptrace options are not
known yet, check them now, instead of asserting.
* nat/linux-ptrace.h (linux_ptrace_attach_fail_reason_string):
Declare.
2014-12-16 16:12:24 +00:00
|
|
|
linux_proc_pid_get_state (pid_t pid, char *buffer, size_t buffer_size,
|
|
|
|
int warn)
|
gdb/
* Makefile.in (linux-ptrace.o): New.
* common/linux-procfs.c (linux_proc_pid_is_zombie): New,
from linux-nat.c.
* common/linux-procfs.h (linux_proc_pid_is_zombie): New declaration.
* common/linux-ptrace.c: New file.
* config/alpha/alpha-linux.mh (NATDEPFILES): Add linux-ptrace.o.
* config/arm/linux.mh: Likewise.
* config/i386/linux.mh: Likewise.
* config/i386/linux64.mh: Likewise.
* config/ia64/linux.mh: Likewise.
* config/m32r/linux.mh: Likewise.
* config/m68k/linux.mh: Likewise.
* config/mips/linux.mh: Likewise.
* config/pa/linux.mh: Likewise.
* config/powerpc/linux.mh: Likewise.
* config/powerpc/ppc64-linux.mh: Likewise.
* config/powerpc/spu-linux.mh: Likewise.
* config/s390/s390.mh: Likewise.
* config/sparc/linux.mh: Likewise.
* config/sparc/linux64.mh: Likewise.
* config/xtensa/linux.mh: Likewise.
* linux-nat.c (linux_lwp_is_zombie): Remove, move it to
common/linux-procfs.c.
(wait_lwp): Rename linux_lwp_is_zombie to linux_proc_pid_is_zombie.
gdb/gdbserver/
* Makefile.in (linux-ptrace.o): New.
* configure.srv (arm*-*-linux*, bfin-*-*linux*, crisv32-*-linux*)
(cris-*-linux*, i[34567]86-*-linux*, ia64-*-linux*, m32r*-*-linux*)
(m68*-*-linux*, m68*-*-uclinux*, mips*-*-linux*, powerpc*-*-linux*)
(s390*-*-linux*, sh*-*-linux*, sparc*-*-linux*, tic6x-*-uclinux)
(x86_64-*-linux*, xtensa*-*-linux*): Add linux-ptrace.o to SRV_TGTOBJ
of these targets.
* linux-low.c (linux_attach_lwp_1): Remove redundent else clause.
2012-03-13 15:00:37 +00:00
|
|
|
{
|
|
|
|
FILE *procfile;
|
|
|
|
int have_state;
|
|
|
|
|
Linux: on attach, attach to lwps listed under /proc/$pid/task/
... instead of relying on libthread_db.
I wrote a test that attaches to a program that constantly spawns
short-lived threads, which exposed several issues. This is one of
them.
On Linux, we need to attach to all threads of a process (thread group)
individually. We currently rely on libthread_db to list the threads,
but that is problematic, because libthread_db relies on reading data
structures out of the inferior (which may well be corrupted). If
threads are being created or exiting just while we try to attach, we
may trip on inconsistencies in the inferior's thread list. To work
around that, when we see a seemingly corrupt list, we currently retry
a few times:
static void
thread_db_find_new_threads_2 (ptid_t ptid, int until_no_new)
{
...
if (until_no_new)
{
/* Require 4 successive iterations which do not find any new threads.
The 4 is a heuristic: there is an inherent race here, and I have
seen that 2 iterations in a row are not always sufficient to
"capture" all threads. */
...
That heuristic may well fail, and when it does, we end up with threads
in the program that aren't under GDB's control. That's obviously bad
and results in quite mistifying failures, like e.g., the process dying
for seeminly no reason when a thread that wasn't attached trips on a
breakpoint.
There's really no reason to rely on libthread_db for this nowadays
when we have /proc mounted. In that case, which is the usual case, we
can list the LWPs from /proc/PID/task/. In fact, GDBserver is already
doing this. The patch factors out that code that knows to walk the
task/ directory out of GDBserver, and makes GDB use it too.
Like GDBserver, the patch makes GDB attach to LWPs and _not_ wait for
them to stop immediately. Instead, we just tag the LWP as having an
expected stop. Because we can only set the ptrace options when the
thread stops, we need a new flag in the lwp structure to keep track of
whether we've already set the ptrace options, just like in GDBserver.
Note that nothing issues any ptrace command to the threads between the
PTRACE_ATTACH and the stop, so this is safe (unlike one scenario
described in gdbserver's linux-low.c).
When we attach to a program that has threads exiting while we attach,
it's easy to race with a thread just exiting as we try to attach to
it, like:
#1 - get current list of threads
#2 - attach to each listed thread
#3 - ooops, attach failed, thread is already gone
As this is pretty normal, we shouldn't be issuing a scary warning in
step #3.
When #3 happens, PTRACE_ATTACH usually fails with ESRCH, but sometimes
we'll see EPERM as well. That happens when the kernel still has the
thread in its task list, but the thread is marked as dead.
Unfortunately, EPERM is ambiguous and we'll get it also on other
scenarios where the thread isn't dead, and in those cases, it's useful
to get a warning. To distiguish the cases, when we get an EPERM
failure, we open /proc/PID/status, and check the thread's state -- if
the /proc file no longer exists, or the state is "Z (Zombie)" or "X
(Dead)", we ignore the EPERM error silently; otherwise, we'll warn.
Unfortunately, there seems to be a kernel race here. Sometimes I get
EPERM, and then the /proc state still indicates "R (Running)"... If
we wait a bit and retry, we do end up seeing X or Z state, or get an
ESRCH. I thought of making GDB retry the attach a few times, but even
with a 500ms wait and 4 retries, I still see the warning sometimes. I
haven't been able to identify the kernel path that causes this yet,
but in any case, it looks like a kernel bug to me. As this just
results failure to suppress a warning that we've been printing since
about forever anyway, I'm just making the test cope with it, and issue
an XFAIL.
gdb/gdbserver/
2015-01-09 Pedro Alves <palves@redhat.com>
* linux-low.c (linux_attach_fail_reason_string): Move to
nat/linux-ptrace.c, and rename.
(linux_attach_lwp): Update comment.
(attach_proc_task_lwp_callback): New function.
(linux_attach): Adjust to rename and use
linux_proc_attach_tgid_threads.
(linux_attach_fail_reason_string): Delete declaration.
gdb/
2015-01-09 Pedro Alves <palves@redhat.com>
* linux-nat.c (attach_proc_task_lwp_callback): New function.
(linux_nat_attach): Use linux_proc_attach_tgid_threads.
(wait_lwp, linux_nat_filter_event): If not set yet, set the lwp's
ptrace option flags.
* linux-nat.h (struct lwp_info) <must_set_ptrace_flags>: New
field.
* nat/linux-procfs.c: Include <dirent.h>.
(linux_proc_get_int): New parameter "warn". Handle it.
(linux_proc_get_tgid): Adjust.
(linux_proc_get_tracerpid): Rename to ...
(linux_proc_get_tracerpid_nowarn): ... this.
(linux_proc_pid_get_state): New function, factored out from
(linux_proc_pid_has_state): ... this. Add new parameter "warn"
and handle it.
(linux_proc_pid_is_gone): New function.
(linux_proc_pid_is_stopped): Adjust.
(linux_proc_pid_is_zombie_maybe_warn)
(linux_proc_pid_is_zombie_nowarn): New functions.
(linux_proc_pid_is_zombie): Use
linux_proc_pid_is_zombie_maybe_warn.
(linux_proc_attach_tgid_threads): New function.
* nat/linux-procfs.h (linux_proc_get_tgid): Update comment.
(linux_proc_get_tracerpid): Rename to ...
(linux_proc_get_tracerpid_nowarn): ... this, and update comment.
(linux_proc_pid_is_gone): New declaration.
(linux_proc_pid_is_zombie): Update comment.
(linux_proc_pid_is_zombie_nowarn): New declaration.
(linux_proc_attach_lwp_func): New typedef.
(linux_proc_attach_tgid_threads): New declaration.
* nat/linux-ptrace.c (linux_ptrace_attach_fail_reason): Adjust to
use nowarn functions.
(linux_ptrace_attach_fail_reason_string): Move here from
gdbserver/linux-low.c and rename.
(ptrace_supports_feature): If the current ptrace options are not
known yet, check them now, instead of asserting.
* nat/linux-ptrace.h (linux_ptrace_attach_fail_reason_string):
Declare.
2014-12-16 16:12:24 +00:00
|
|
|
xsnprintf (buffer, buffer_size, "/proc/%d/status", (int) pid);
|
PR gdb/7912:
* Makefile.in (SFILES): Add filestuff.c
(COMMON_OBS): Add filestuff.o.
(filestuff.o): New target.
* auto-load.c (auto_load_objfile_script_1): Use
gdb_fopen_cloexec.
* auxv.c (procfs_xfer_auxv): Use gdb_open_cloexec.
* cli/cli-cmds.c (shell_escape): Call close_most_fds.
* cli/cli-dump.c (fopen_with_cleanup): Use gdb_fopen_cloexec.
* common/agent.c (gdb_connect_sync_socket): Use
gdb_socket_cloexec.
* common/filestuff.c: New file.
* common/filestuff.h: New file.
* common/linux-osdata.c (linux_common_core_of_thread)
(command_from_pid, commandline_from_pid, print_source_lines)
(linux_xfer_osdata_shm, linux_xfer_osdata_sem)
(linux_xfer_osdata_msg, linux_xfer_osdata_modules): Use
gdb_fopen_cloexec.
* common/linux-procfs.c (linux_proc_get_int)
(linux_proc_pid_has_state): Use gdb_fopen_cloexec.
* config.in, configure: Rebuild.
* configure.ac: Don't check for sys/socket.h. Check for
fdwalk, pipe2.
* corelow.c (core_open): Use gdb_open_cloexec.
* dwarf2read.c (write_psymtabs_to_index): Use gdb_fopen_cloexec.
* fork-child.c (fork_inferior): Call close_most_fds.
* gdb_bfd.c (gdb_bfd_open): Use gdb_open_cloexec.
* inf-child.c (inf_child_fileio_readlink): Use gdb_open_cloexec.
* linux-nat.c (linux_nat_thread_name, linux_proc_pending_signals):
Use gdb_fopen_cloexec.
(linux_proc_xfer_partial, linux_proc_xfer_spu): Use
gdb_open_cloexec.
(linux_async_pipe): Use gdb_pipe_cloexec.
* remote-fileio.c (remote_fileio_func_open): Use
gdb_open_cloexec.
* remote.c (remote_file_put, remote_file_get): Use
gdb_fopen_cloexec.
* ser-pipe.c (pipe_open): Use gdb_socketpair_cloexec,
close_most_fds.
* ser-tcp.c (net_open): Use gdb_socket_cloexec.
* ser-unix.c (hardwire_open): Use gdb_open_cloexec.
* solib.c (solib_find): Use gdb_open_cloexec.
* source.c (openp, find_and_open_source): Use gdb_open_cloexec.
* tracepoint.c (tfile_start): Use gdb_fopen_cloexec.
(tfile_open): Use gdb_open_cloexec.
* tui/tui-io.c (tui_initialize_io): Use gdb_pipe_cloexec.
* ui-file.c (gdb_fopen): Use gdb_fopen_cloexec.
* xml-support.c (xml_fetch_content_from_file): Use
gdb_fopen_cloexec.
* main.c (captured_main): Call notice_open_fds.
gdbserver
* Makefile.in (SFILES): Add filestuff.c.
(OBS): Add filestuff.o.
(filestuff.o): New target.
* config.in, configure: Rebuild.
* configure.ac: Check for fdwalk, pipe2.
2013-04-22 16:46:15 +00:00
|
|
|
procfile = gdb_fopen_cloexec (buffer, "r");
|
gdb/
* Makefile.in (linux-ptrace.o): New.
* common/linux-procfs.c (linux_proc_pid_is_zombie): New,
from linux-nat.c.
* common/linux-procfs.h (linux_proc_pid_is_zombie): New declaration.
* common/linux-ptrace.c: New file.
* config/alpha/alpha-linux.mh (NATDEPFILES): Add linux-ptrace.o.
* config/arm/linux.mh: Likewise.
* config/i386/linux.mh: Likewise.
* config/i386/linux64.mh: Likewise.
* config/ia64/linux.mh: Likewise.
* config/m32r/linux.mh: Likewise.
* config/m68k/linux.mh: Likewise.
* config/mips/linux.mh: Likewise.
* config/pa/linux.mh: Likewise.
* config/powerpc/linux.mh: Likewise.
* config/powerpc/ppc64-linux.mh: Likewise.
* config/powerpc/spu-linux.mh: Likewise.
* config/s390/s390.mh: Likewise.
* config/sparc/linux.mh: Likewise.
* config/sparc/linux64.mh: Likewise.
* config/xtensa/linux.mh: Likewise.
* linux-nat.c (linux_lwp_is_zombie): Remove, move it to
common/linux-procfs.c.
(wait_lwp): Rename linux_lwp_is_zombie to linux_proc_pid_is_zombie.
gdb/gdbserver/
* Makefile.in (linux-ptrace.o): New.
* configure.srv (arm*-*-linux*, bfin-*-*linux*, crisv32-*-linux*)
(cris-*-linux*, i[34567]86-*-linux*, ia64-*-linux*, m32r*-*-linux*)
(m68*-*-linux*, m68*-*-uclinux*, mips*-*-linux*, powerpc*-*-linux*)
(s390*-*-linux*, sh*-*-linux*, sparc*-*-linux*, tic6x-*-uclinux)
(x86_64-*-linux*, xtensa*-*-linux*): Add linux-ptrace.o to SRV_TGTOBJ
of these targets.
* linux-low.c (linux_attach_lwp_1): Remove redundent else clause.
2012-03-13 15:00:37 +00:00
|
|
|
if (procfile == NULL)
|
|
|
|
{
|
Linux: on attach, attach to lwps listed under /proc/$pid/task/
... instead of relying on libthread_db.
I wrote a test that attaches to a program that constantly spawns
short-lived threads, which exposed several issues. This is one of
them.
On Linux, we need to attach to all threads of a process (thread group)
individually. We currently rely on libthread_db to list the threads,
but that is problematic, because libthread_db relies on reading data
structures out of the inferior (which may well be corrupted). If
threads are being created or exiting just while we try to attach, we
may trip on inconsistencies in the inferior's thread list. To work
around that, when we see a seemingly corrupt list, we currently retry
a few times:
static void
thread_db_find_new_threads_2 (ptid_t ptid, int until_no_new)
{
...
if (until_no_new)
{
/* Require 4 successive iterations which do not find any new threads.
The 4 is a heuristic: there is an inherent race here, and I have
seen that 2 iterations in a row are not always sufficient to
"capture" all threads. */
...
That heuristic may well fail, and when it does, we end up with threads
in the program that aren't under GDB's control. That's obviously bad
and results in quite mistifying failures, like e.g., the process dying
for seeminly no reason when a thread that wasn't attached trips on a
breakpoint.
There's really no reason to rely on libthread_db for this nowadays
when we have /proc mounted. In that case, which is the usual case, we
can list the LWPs from /proc/PID/task/. In fact, GDBserver is already
doing this. The patch factors out that code that knows to walk the
task/ directory out of GDBserver, and makes GDB use it too.
Like GDBserver, the patch makes GDB attach to LWPs and _not_ wait for
them to stop immediately. Instead, we just tag the LWP as having an
expected stop. Because we can only set the ptrace options when the
thread stops, we need a new flag in the lwp structure to keep track of
whether we've already set the ptrace options, just like in GDBserver.
Note that nothing issues any ptrace command to the threads between the
PTRACE_ATTACH and the stop, so this is safe (unlike one scenario
described in gdbserver's linux-low.c).
When we attach to a program that has threads exiting while we attach,
it's easy to race with a thread just exiting as we try to attach to
it, like:
#1 - get current list of threads
#2 - attach to each listed thread
#3 - ooops, attach failed, thread is already gone
As this is pretty normal, we shouldn't be issuing a scary warning in
step #3.
When #3 happens, PTRACE_ATTACH usually fails with ESRCH, but sometimes
we'll see EPERM as well. That happens when the kernel still has the
thread in its task list, but the thread is marked as dead.
Unfortunately, EPERM is ambiguous and we'll get it also on other
scenarios where the thread isn't dead, and in those cases, it's useful
to get a warning. To distiguish the cases, when we get an EPERM
failure, we open /proc/PID/status, and check the thread's state -- if
the /proc file no longer exists, or the state is "Z (Zombie)" or "X
(Dead)", we ignore the EPERM error silently; otherwise, we'll warn.
Unfortunately, there seems to be a kernel race here. Sometimes I get
EPERM, and then the /proc state still indicates "R (Running)"... If
we wait a bit and retry, we do end up seeing X or Z state, or get an
ESRCH. I thought of making GDB retry the attach a few times, but even
with a 500ms wait and 4 retries, I still see the warning sometimes. I
haven't been able to identify the kernel path that causes this yet,
but in any case, it looks like a kernel bug to me. As this just
results failure to suppress a warning that we've been printing since
about forever anyway, I'm just making the test cope with it, and issue
an XFAIL.
gdb/gdbserver/
2015-01-09 Pedro Alves <palves@redhat.com>
* linux-low.c (linux_attach_fail_reason_string): Move to
nat/linux-ptrace.c, and rename.
(linux_attach_lwp): Update comment.
(attach_proc_task_lwp_callback): New function.
(linux_attach): Adjust to rename and use
linux_proc_attach_tgid_threads.
(linux_attach_fail_reason_string): Delete declaration.
gdb/
2015-01-09 Pedro Alves <palves@redhat.com>
* linux-nat.c (attach_proc_task_lwp_callback): New function.
(linux_nat_attach): Use linux_proc_attach_tgid_threads.
(wait_lwp, linux_nat_filter_event): If not set yet, set the lwp's
ptrace option flags.
* linux-nat.h (struct lwp_info) <must_set_ptrace_flags>: New
field.
* nat/linux-procfs.c: Include <dirent.h>.
(linux_proc_get_int): New parameter "warn". Handle it.
(linux_proc_get_tgid): Adjust.
(linux_proc_get_tracerpid): Rename to ...
(linux_proc_get_tracerpid_nowarn): ... this.
(linux_proc_pid_get_state): New function, factored out from
(linux_proc_pid_has_state): ... this. Add new parameter "warn"
and handle it.
(linux_proc_pid_is_gone): New function.
(linux_proc_pid_is_stopped): Adjust.
(linux_proc_pid_is_zombie_maybe_warn)
(linux_proc_pid_is_zombie_nowarn): New functions.
(linux_proc_pid_is_zombie): Use
linux_proc_pid_is_zombie_maybe_warn.
(linux_proc_attach_tgid_threads): New function.
* nat/linux-procfs.h (linux_proc_get_tgid): Update comment.
(linux_proc_get_tracerpid): Rename to ...
(linux_proc_get_tracerpid_nowarn): ... this, and update comment.
(linux_proc_pid_is_gone): New declaration.
(linux_proc_pid_is_zombie): Update comment.
(linux_proc_pid_is_zombie_nowarn): New declaration.
(linux_proc_attach_lwp_func): New typedef.
(linux_proc_attach_tgid_threads): New declaration.
* nat/linux-ptrace.c (linux_ptrace_attach_fail_reason): Adjust to
use nowarn functions.
(linux_ptrace_attach_fail_reason_string): Move here from
gdbserver/linux-low.c and rename.
(ptrace_supports_feature): If the current ptrace options are not
known yet, check them now, instead of asserting.
* nat/linux-ptrace.h (linux_ptrace_attach_fail_reason_string):
Declare.
2014-12-16 16:12:24 +00:00
|
|
|
if (warn)
|
|
|
|
warning (_("unable to open /proc file '%s'"), buffer);
|
|
|
|
return -1;
|
gdb/
* Makefile.in (linux-ptrace.o): New.
* common/linux-procfs.c (linux_proc_pid_is_zombie): New,
from linux-nat.c.
* common/linux-procfs.h (linux_proc_pid_is_zombie): New declaration.
* common/linux-ptrace.c: New file.
* config/alpha/alpha-linux.mh (NATDEPFILES): Add linux-ptrace.o.
* config/arm/linux.mh: Likewise.
* config/i386/linux.mh: Likewise.
* config/i386/linux64.mh: Likewise.
* config/ia64/linux.mh: Likewise.
* config/m32r/linux.mh: Likewise.
* config/m68k/linux.mh: Likewise.
* config/mips/linux.mh: Likewise.
* config/pa/linux.mh: Likewise.
* config/powerpc/linux.mh: Likewise.
* config/powerpc/ppc64-linux.mh: Likewise.
* config/powerpc/spu-linux.mh: Likewise.
* config/s390/s390.mh: Likewise.
* config/sparc/linux.mh: Likewise.
* config/sparc/linux64.mh: Likewise.
* config/xtensa/linux.mh: Likewise.
* linux-nat.c (linux_lwp_is_zombie): Remove, move it to
common/linux-procfs.c.
(wait_lwp): Rename linux_lwp_is_zombie to linux_proc_pid_is_zombie.
gdb/gdbserver/
* Makefile.in (linux-ptrace.o): New.
* configure.srv (arm*-*-linux*, bfin-*-*linux*, crisv32-*-linux*)
(cris-*-linux*, i[34567]86-*-linux*, ia64-*-linux*, m32r*-*-linux*)
(m68*-*-linux*, m68*-*-uclinux*, mips*-*-linux*, powerpc*-*-linux*)
(s390*-*-linux*, sh*-*-linux*, sparc*-*-linux*, tic6x-*-uclinux)
(x86_64-*-linux*, xtensa*-*-linux*): Add linux-ptrace.o to SRV_TGTOBJ
of these targets.
* linux-low.c (linux_attach_lwp_1): Remove redundent else clause.
2012-03-13 15:00:37 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
have_state = 0;
|
Linux: on attach, attach to lwps listed under /proc/$pid/task/
... instead of relying on libthread_db.
I wrote a test that attaches to a program that constantly spawns
short-lived threads, which exposed several issues. This is one of
them.
On Linux, we need to attach to all threads of a process (thread group)
individually. We currently rely on libthread_db to list the threads,
but that is problematic, because libthread_db relies on reading data
structures out of the inferior (which may well be corrupted). If
threads are being created or exiting just while we try to attach, we
may trip on inconsistencies in the inferior's thread list. To work
around that, when we see a seemingly corrupt list, we currently retry
a few times:
static void
thread_db_find_new_threads_2 (ptid_t ptid, int until_no_new)
{
...
if (until_no_new)
{
/* Require 4 successive iterations which do not find any new threads.
The 4 is a heuristic: there is an inherent race here, and I have
seen that 2 iterations in a row are not always sufficient to
"capture" all threads. */
...
That heuristic may well fail, and when it does, we end up with threads
in the program that aren't under GDB's control. That's obviously bad
and results in quite mistifying failures, like e.g., the process dying
for seeminly no reason when a thread that wasn't attached trips on a
breakpoint.
There's really no reason to rely on libthread_db for this nowadays
when we have /proc mounted. In that case, which is the usual case, we
can list the LWPs from /proc/PID/task/. In fact, GDBserver is already
doing this. The patch factors out that code that knows to walk the
task/ directory out of GDBserver, and makes GDB use it too.
Like GDBserver, the patch makes GDB attach to LWPs and _not_ wait for
them to stop immediately. Instead, we just tag the LWP as having an
expected stop. Because we can only set the ptrace options when the
thread stops, we need a new flag in the lwp structure to keep track of
whether we've already set the ptrace options, just like in GDBserver.
Note that nothing issues any ptrace command to the threads between the
PTRACE_ATTACH and the stop, so this is safe (unlike one scenario
described in gdbserver's linux-low.c).
When we attach to a program that has threads exiting while we attach,
it's easy to race with a thread just exiting as we try to attach to
it, like:
#1 - get current list of threads
#2 - attach to each listed thread
#3 - ooops, attach failed, thread is already gone
As this is pretty normal, we shouldn't be issuing a scary warning in
step #3.
When #3 happens, PTRACE_ATTACH usually fails with ESRCH, but sometimes
we'll see EPERM as well. That happens when the kernel still has the
thread in its task list, but the thread is marked as dead.
Unfortunately, EPERM is ambiguous and we'll get it also on other
scenarios where the thread isn't dead, and in those cases, it's useful
to get a warning. To distiguish the cases, when we get an EPERM
failure, we open /proc/PID/status, and check the thread's state -- if
the /proc file no longer exists, or the state is "Z (Zombie)" or "X
(Dead)", we ignore the EPERM error silently; otherwise, we'll warn.
Unfortunately, there seems to be a kernel race here. Sometimes I get
EPERM, and then the /proc state still indicates "R (Running)"... If
we wait a bit and retry, we do end up seeing X or Z state, or get an
ESRCH. I thought of making GDB retry the attach a few times, but even
with a 500ms wait and 4 retries, I still see the warning sometimes. I
haven't been able to identify the kernel path that causes this yet,
but in any case, it looks like a kernel bug to me. As this just
results failure to suppress a warning that we've been printing since
about forever anyway, I'm just making the test cope with it, and issue
an XFAIL.
gdb/gdbserver/
2015-01-09 Pedro Alves <palves@redhat.com>
* linux-low.c (linux_attach_fail_reason_string): Move to
nat/linux-ptrace.c, and rename.
(linux_attach_lwp): Update comment.
(attach_proc_task_lwp_callback): New function.
(linux_attach): Adjust to rename and use
linux_proc_attach_tgid_threads.
(linux_attach_fail_reason_string): Delete declaration.
gdb/
2015-01-09 Pedro Alves <palves@redhat.com>
* linux-nat.c (attach_proc_task_lwp_callback): New function.
(linux_nat_attach): Use linux_proc_attach_tgid_threads.
(wait_lwp, linux_nat_filter_event): If not set yet, set the lwp's
ptrace option flags.
* linux-nat.h (struct lwp_info) <must_set_ptrace_flags>: New
field.
* nat/linux-procfs.c: Include <dirent.h>.
(linux_proc_get_int): New parameter "warn". Handle it.
(linux_proc_get_tgid): Adjust.
(linux_proc_get_tracerpid): Rename to ...
(linux_proc_get_tracerpid_nowarn): ... this.
(linux_proc_pid_get_state): New function, factored out from
(linux_proc_pid_has_state): ... this. Add new parameter "warn"
and handle it.
(linux_proc_pid_is_gone): New function.
(linux_proc_pid_is_stopped): Adjust.
(linux_proc_pid_is_zombie_maybe_warn)
(linux_proc_pid_is_zombie_nowarn): New functions.
(linux_proc_pid_is_zombie): Use
linux_proc_pid_is_zombie_maybe_warn.
(linux_proc_attach_tgid_threads): New function.
* nat/linux-procfs.h (linux_proc_get_tgid): Update comment.
(linux_proc_get_tracerpid): Rename to ...
(linux_proc_get_tracerpid_nowarn): ... this, and update comment.
(linux_proc_pid_is_gone): New declaration.
(linux_proc_pid_is_zombie): Update comment.
(linux_proc_pid_is_zombie_nowarn): New declaration.
(linux_proc_attach_lwp_func): New typedef.
(linux_proc_attach_tgid_threads): New declaration.
* nat/linux-ptrace.c (linux_ptrace_attach_fail_reason): Adjust to
use nowarn functions.
(linux_ptrace_attach_fail_reason_string): Move here from
gdbserver/linux-low.c and rename.
(ptrace_supports_feature): If the current ptrace options are not
known yet, check them now, instead of asserting.
* nat/linux-ptrace.h (linux_ptrace_attach_fail_reason_string):
Declare.
2014-12-16 16:12:24 +00:00
|
|
|
while (fgets (buffer, buffer_size, procfile) != NULL)
|
2015-03-06 09:42:06 +00:00
|
|
|
if (startswith (buffer, "State:"))
|
gdb/
* Makefile.in (linux-ptrace.o): New.
* common/linux-procfs.c (linux_proc_pid_is_zombie): New,
from linux-nat.c.
* common/linux-procfs.h (linux_proc_pid_is_zombie): New declaration.
* common/linux-ptrace.c: New file.
* config/alpha/alpha-linux.mh (NATDEPFILES): Add linux-ptrace.o.
* config/arm/linux.mh: Likewise.
* config/i386/linux.mh: Likewise.
* config/i386/linux64.mh: Likewise.
* config/ia64/linux.mh: Likewise.
* config/m32r/linux.mh: Likewise.
* config/m68k/linux.mh: Likewise.
* config/mips/linux.mh: Likewise.
* config/pa/linux.mh: Likewise.
* config/powerpc/linux.mh: Likewise.
* config/powerpc/ppc64-linux.mh: Likewise.
* config/powerpc/spu-linux.mh: Likewise.
* config/s390/s390.mh: Likewise.
* config/sparc/linux.mh: Likewise.
* config/sparc/linux64.mh: Likewise.
* config/xtensa/linux.mh: Likewise.
* linux-nat.c (linux_lwp_is_zombie): Remove, move it to
common/linux-procfs.c.
(wait_lwp): Rename linux_lwp_is_zombie to linux_proc_pid_is_zombie.
gdb/gdbserver/
* Makefile.in (linux-ptrace.o): New.
* configure.srv (arm*-*-linux*, bfin-*-*linux*, crisv32-*-linux*)
(cris-*-linux*, i[34567]86-*-linux*, ia64-*-linux*, m32r*-*-linux*)
(m68*-*-linux*, m68*-*-uclinux*, mips*-*-linux*, powerpc*-*-linux*)
(s390*-*-linux*, sh*-*-linux*, sparc*-*-linux*, tic6x-*-uclinux)
(x86_64-*-linux*, xtensa*-*-linux*): Add linux-ptrace.o to SRV_TGTOBJ
of these targets.
* linux-low.c (linux_attach_lwp_1): Remove redundent else clause.
2012-03-13 15:00:37 +00:00
|
|
|
{
|
|
|
|
have_state = 1;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
fclose (procfile);
|
Linux: on attach, attach to lwps listed under /proc/$pid/task/
... instead of relying on libthread_db.
I wrote a test that attaches to a program that constantly spawns
short-lived threads, which exposed several issues. This is one of
them.
On Linux, we need to attach to all threads of a process (thread group)
individually. We currently rely on libthread_db to list the threads,
but that is problematic, because libthread_db relies on reading data
structures out of the inferior (which may well be corrupted). If
threads are being created or exiting just while we try to attach, we
may trip on inconsistencies in the inferior's thread list. To work
around that, when we see a seemingly corrupt list, we currently retry
a few times:
static void
thread_db_find_new_threads_2 (ptid_t ptid, int until_no_new)
{
...
if (until_no_new)
{
/* Require 4 successive iterations which do not find any new threads.
The 4 is a heuristic: there is an inherent race here, and I have
seen that 2 iterations in a row are not always sufficient to
"capture" all threads. */
...
That heuristic may well fail, and when it does, we end up with threads
in the program that aren't under GDB's control. That's obviously bad
and results in quite mistifying failures, like e.g., the process dying
for seeminly no reason when a thread that wasn't attached trips on a
breakpoint.
There's really no reason to rely on libthread_db for this nowadays
when we have /proc mounted. In that case, which is the usual case, we
can list the LWPs from /proc/PID/task/. In fact, GDBserver is already
doing this. The patch factors out that code that knows to walk the
task/ directory out of GDBserver, and makes GDB use it too.
Like GDBserver, the patch makes GDB attach to LWPs and _not_ wait for
them to stop immediately. Instead, we just tag the LWP as having an
expected stop. Because we can only set the ptrace options when the
thread stops, we need a new flag in the lwp structure to keep track of
whether we've already set the ptrace options, just like in GDBserver.
Note that nothing issues any ptrace command to the threads between the
PTRACE_ATTACH and the stop, so this is safe (unlike one scenario
described in gdbserver's linux-low.c).
When we attach to a program that has threads exiting while we attach,
it's easy to race with a thread just exiting as we try to attach to
it, like:
#1 - get current list of threads
#2 - attach to each listed thread
#3 - ooops, attach failed, thread is already gone
As this is pretty normal, we shouldn't be issuing a scary warning in
step #3.
When #3 happens, PTRACE_ATTACH usually fails with ESRCH, but sometimes
we'll see EPERM as well. That happens when the kernel still has the
thread in its task list, but the thread is marked as dead.
Unfortunately, EPERM is ambiguous and we'll get it also on other
scenarios where the thread isn't dead, and in those cases, it's useful
to get a warning. To distiguish the cases, when we get an EPERM
failure, we open /proc/PID/status, and check the thread's state -- if
the /proc file no longer exists, or the state is "Z (Zombie)" or "X
(Dead)", we ignore the EPERM error silently; otherwise, we'll warn.
Unfortunately, there seems to be a kernel race here. Sometimes I get
EPERM, and then the /proc state still indicates "R (Running)"... If
we wait a bit and retry, we do end up seeing X or Z state, or get an
ESRCH. I thought of making GDB retry the attach a few times, but even
with a 500ms wait and 4 retries, I still see the warning sometimes. I
haven't been able to identify the kernel path that causes this yet,
but in any case, it looks like a kernel bug to me. As this just
results failure to suppress a warning that we've been printing since
about forever anyway, I'm just making the test cope with it, and issue
an XFAIL.
gdb/gdbserver/
2015-01-09 Pedro Alves <palves@redhat.com>
* linux-low.c (linux_attach_fail_reason_string): Move to
nat/linux-ptrace.c, and rename.
(linux_attach_lwp): Update comment.
(attach_proc_task_lwp_callback): New function.
(linux_attach): Adjust to rename and use
linux_proc_attach_tgid_threads.
(linux_attach_fail_reason_string): Delete declaration.
gdb/
2015-01-09 Pedro Alves <palves@redhat.com>
* linux-nat.c (attach_proc_task_lwp_callback): New function.
(linux_nat_attach): Use linux_proc_attach_tgid_threads.
(wait_lwp, linux_nat_filter_event): If not set yet, set the lwp's
ptrace option flags.
* linux-nat.h (struct lwp_info) <must_set_ptrace_flags>: New
field.
* nat/linux-procfs.c: Include <dirent.h>.
(linux_proc_get_int): New parameter "warn". Handle it.
(linux_proc_get_tgid): Adjust.
(linux_proc_get_tracerpid): Rename to ...
(linux_proc_get_tracerpid_nowarn): ... this.
(linux_proc_pid_get_state): New function, factored out from
(linux_proc_pid_has_state): ... this. Add new parameter "warn"
and handle it.
(linux_proc_pid_is_gone): New function.
(linux_proc_pid_is_stopped): Adjust.
(linux_proc_pid_is_zombie_maybe_warn)
(linux_proc_pid_is_zombie_nowarn): New functions.
(linux_proc_pid_is_zombie): Use
linux_proc_pid_is_zombie_maybe_warn.
(linux_proc_attach_tgid_threads): New function.
* nat/linux-procfs.h (linux_proc_get_tgid): Update comment.
(linux_proc_get_tracerpid): Rename to ...
(linux_proc_get_tracerpid_nowarn): ... this, and update comment.
(linux_proc_pid_is_gone): New declaration.
(linux_proc_pid_is_zombie): Update comment.
(linux_proc_pid_is_zombie_nowarn): New declaration.
(linux_proc_attach_lwp_func): New typedef.
(linux_proc_attach_tgid_threads): New declaration.
* nat/linux-ptrace.c (linux_ptrace_attach_fail_reason): Adjust to
use nowarn functions.
(linux_ptrace_attach_fail_reason_string): Move here from
gdbserver/linux-low.c and rename.
(ptrace_supports_feature): If the current ptrace options are not
known yet, check them now, instead of asserting.
* nat/linux-ptrace.h (linux_ptrace_attach_fail_reason_string):
Declare.
2014-12-16 16:12:24 +00:00
|
|
|
return have_state;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* See linux-procfs.h declaration. */
|
|
|
|
|
|
|
|
int
|
|
|
|
linux_proc_pid_is_gone (pid_t pid)
|
|
|
|
{
|
|
|
|
char buffer[100];
|
|
|
|
int have_state;
|
|
|
|
|
|
|
|
have_state = linux_proc_pid_get_state (pid, buffer, sizeof buffer, 0);
|
|
|
|
if (have_state < 0)
|
|
|
|
{
|
|
|
|
/* If we can't open the status file, assume the thread has
|
|
|
|
disappeared. */
|
|
|
|
return 1;
|
|
|
|
}
|
|
|
|
else if (have_state == 0)
|
|
|
|
{
|
|
|
|
/* No "State:" line, assume thread is alive. */
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
return (strstr (buffer, "Z (") != NULL
|
|
|
|
|| strstr (buffer, "X (") != NULL);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Return non-zero if 'State' of /proc/PID/status contains STATE. If
|
|
|
|
WARN, warn on failure to open the /proc file. */
|
|
|
|
|
|
|
|
static int
|
|
|
|
linux_proc_pid_has_state (pid_t pid, const char *state, int warn)
|
|
|
|
{
|
|
|
|
char buffer[100];
|
|
|
|
int have_state;
|
|
|
|
|
|
|
|
have_state = linux_proc_pid_get_state (pid, buffer, sizeof buffer, warn);
|
|
|
|
return (have_state > 0 && strstr (buffer, state) != NULL);
|
gdb/
* Makefile.in (linux-ptrace.o): New.
* common/linux-procfs.c (linux_proc_pid_is_zombie): New,
from linux-nat.c.
* common/linux-procfs.h (linux_proc_pid_is_zombie): New declaration.
* common/linux-ptrace.c: New file.
* config/alpha/alpha-linux.mh (NATDEPFILES): Add linux-ptrace.o.
* config/arm/linux.mh: Likewise.
* config/i386/linux.mh: Likewise.
* config/i386/linux64.mh: Likewise.
* config/ia64/linux.mh: Likewise.
* config/m32r/linux.mh: Likewise.
* config/m68k/linux.mh: Likewise.
* config/mips/linux.mh: Likewise.
* config/pa/linux.mh: Likewise.
* config/powerpc/linux.mh: Likewise.
* config/powerpc/ppc64-linux.mh: Likewise.
* config/powerpc/spu-linux.mh: Likewise.
* config/s390/s390.mh: Likewise.
* config/sparc/linux.mh: Likewise.
* config/sparc/linux64.mh: Likewise.
* config/xtensa/linux.mh: Likewise.
* linux-nat.c (linux_lwp_is_zombie): Remove, move it to
common/linux-procfs.c.
(wait_lwp): Rename linux_lwp_is_zombie to linux_proc_pid_is_zombie.
gdb/gdbserver/
* Makefile.in (linux-ptrace.o): New.
* configure.srv (arm*-*-linux*, bfin-*-*linux*, crisv32-*-linux*)
(cris-*-linux*, i[34567]86-*-linux*, ia64-*-linux*, m32r*-*-linux*)
(m68*-*-linux*, m68*-*-uclinux*, mips*-*-linux*, powerpc*-*-linux*)
(s390*-*-linux*, sh*-*-linux*, sparc*-*-linux*, tic6x-*-uclinux)
(x86_64-*-linux*, xtensa*-*-linux*): Add linux-ptrace.o to SRV_TGTOBJ
of these targets.
* linux-low.c (linux_attach_lwp_1): Remove redundent else clause.
2012-03-13 15:00:37 +00:00
|
|
|
}
|
2012-03-13 15:02:25 +00:00
|
|
|
|
|
|
|
/* Detect `T (stopped)' in `/proc/PID/status'.
|
|
|
|
Other states including `T (tracing stop)' are reported as false. */
|
|
|
|
|
|
|
|
int
|
|
|
|
linux_proc_pid_is_stopped (pid_t pid)
|
|
|
|
{
|
Linux: on attach, attach to lwps listed under /proc/$pid/task/
... instead of relying on libthread_db.
I wrote a test that attaches to a program that constantly spawns
short-lived threads, which exposed several issues. This is one of
them.
On Linux, we need to attach to all threads of a process (thread group)
individually. We currently rely on libthread_db to list the threads,
but that is problematic, because libthread_db relies on reading data
structures out of the inferior (which may well be corrupted). If
threads are being created or exiting just while we try to attach, we
may trip on inconsistencies in the inferior's thread list. To work
around that, when we see a seemingly corrupt list, we currently retry
a few times:
static void
thread_db_find_new_threads_2 (ptid_t ptid, int until_no_new)
{
...
if (until_no_new)
{
/* Require 4 successive iterations which do not find any new threads.
The 4 is a heuristic: there is an inherent race here, and I have
seen that 2 iterations in a row are not always sufficient to
"capture" all threads. */
...
That heuristic may well fail, and when it does, we end up with threads
in the program that aren't under GDB's control. That's obviously bad
and results in quite mistifying failures, like e.g., the process dying
for seeminly no reason when a thread that wasn't attached trips on a
breakpoint.
There's really no reason to rely on libthread_db for this nowadays
when we have /proc mounted. In that case, which is the usual case, we
can list the LWPs from /proc/PID/task/. In fact, GDBserver is already
doing this. The patch factors out that code that knows to walk the
task/ directory out of GDBserver, and makes GDB use it too.
Like GDBserver, the patch makes GDB attach to LWPs and _not_ wait for
them to stop immediately. Instead, we just tag the LWP as having an
expected stop. Because we can only set the ptrace options when the
thread stops, we need a new flag in the lwp structure to keep track of
whether we've already set the ptrace options, just like in GDBserver.
Note that nothing issues any ptrace command to the threads between the
PTRACE_ATTACH and the stop, so this is safe (unlike one scenario
described in gdbserver's linux-low.c).
When we attach to a program that has threads exiting while we attach,
it's easy to race with a thread just exiting as we try to attach to
it, like:
#1 - get current list of threads
#2 - attach to each listed thread
#3 - ooops, attach failed, thread is already gone
As this is pretty normal, we shouldn't be issuing a scary warning in
step #3.
When #3 happens, PTRACE_ATTACH usually fails with ESRCH, but sometimes
we'll see EPERM as well. That happens when the kernel still has the
thread in its task list, but the thread is marked as dead.
Unfortunately, EPERM is ambiguous and we'll get it also on other
scenarios where the thread isn't dead, and in those cases, it's useful
to get a warning. To distiguish the cases, when we get an EPERM
failure, we open /proc/PID/status, and check the thread's state -- if
the /proc file no longer exists, or the state is "Z (Zombie)" or "X
(Dead)", we ignore the EPERM error silently; otherwise, we'll warn.
Unfortunately, there seems to be a kernel race here. Sometimes I get
EPERM, and then the /proc state still indicates "R (Running)"... If
we wait a bit and retry, we do end up seeing X or Z state, or get an
ESRCH. I thought of making GDB retry the attach a few times, but even
with a 500ms wait and 4 retries, I still see the warning sometimes. I
haven't been able to identify the kernel path that causes this yet,
but in any case, it looks like a kernel bug to me. As this just
results failure to suppress a warning that we've been printing since
about forever anyway, I'm just making the test cope with it, and issue
an XFAIL.
gdb/gdbserver/
2015-01-09 Pedro Alves <palves@redhat.com>
* linux-low.c (linux_attach_fail_reason_string): Move to
nat/linux-ptrace.c, and rename.
(linux_attach_lwp): Update comment.
(attach_proc_task_lwp_callback): New function.
(linux_attach): Adjust to rename and use
linux_proc_attach_tgid_threads.
(linux_attach_fail_reason_string): Delete declaration.
gdb/
2015-01-09 Pedro Alves <palves@redhat.com>
* linux-nat.c (attach_proc_task_lwp_callback): New function.
(linux_nat_attach): Use linux_proc_attach_tgid_threads.
(wait_lwp, linux_nat_filter_event): If not set yet, set the lwp's
ptrace option flags.
* linux-nat.h (struct lwp_info) <must_set_ptrace_flags>: New
field.
* nat/linux-procfs.c: Include <dirent.h>.
(linux_proc_get_int): New parameter "warn". Handle it.
(linux_proc_get_tgid): Adjust.
(linux_proc_get_tracerpid): Rename to ...
(linux_proc_get_tracerpid_nowarn): ... this.
(linux_proc_pid_get_state): New function, factored out from
(linux_proc_pid_has_state): ... this. Add new parameter "warn"
and handle it.
(linux_proc_pid_is_gone): New function.
(linux_proc_pid_is_stopped): Adjust.
(linux_proc_pid_is_zombie_maybe_warn)
(linux_proc_pid_is_zombie_nowarn): New functions.
(linux_proc_pid_is_zombie): Use
linux_proc_pid_is_zombie_maybe_warn.
(linux_proc_attach_tgid_threads): New function.
* nat/linux-procfs.h (linux_proc_get_tgid): Update comment.
(linux_proc_get_tracerpid): Rename to ...
(linux_proc_get_tracerpid_nowarn): ... this, and update comment.
(linux_proc_pid_is_gone): New declaration.
(linux_proc_pid_is_zombie): Update comment.
(linux_proc_pid_is_zombie_nowarn): New declaration.
(linux_proc_attach_lwp_func): New typedef.
(linux_proc_attach_tgid_threads): New declaration.
* nat/linux-ptrace.c (linux_ptrace_attach_fail_reason): Adjust to
use nowarn functions.
(linux_ptrace_attach_fail_reason_string): Move here from
gdbserver/linux-low.c and rename.
(ptrace_supports_feature): If the current ptrace options are not
known yet, check them now, instead of asserting.
* nat/linux-ptrace.h (linux_ptrace_attach_fail_reason_string):
Declare.
2014-12-16 16:12:24 +00:00
|
|
|
return linux_proc_pid_has_state (pid, "T (stopped)", 1);
|
|
|
|
}
|
|
|
|
|
Fix race exposed by gdb.threads/killed.exp
On GNU/Linux, this test sometimes FAILs like this:
(gdb) run
Starting program: /home/pedro/gdb/mygit/build/gdb/testsuite/gdb.threads/killed
[Thread debugging using libthread_db enabled]
Using host libthread_db library "/lib64/libthread_db.so.1".
ptrace: No such process.
(gdb)
Program terminated with signal SIGKILL, Killed.
The program no longer exists.
FAIL: gdb.threads/killed.exp: run program to completion (timeout)
Note the suspicious "No such process" line (that's errno==ESRCH).
Adding debug output we see:
linux_nat_wait: [process -1], [TARGET_WNOHANG]
LLW: enter
LNW: waitpid(-1, ...) returned 18465, ERRNO-OK
LLW: waitpid 18465 received Stopped (signal) (stopped)
LNW: waitpid(-1, ...) returned 18461, ERRNO-OK
LLW: waitpid 18461 received Trace/breakpoint trap (stopped)
LLW: Handling extended status 0x03057f
LHEW: Got clone event from LWP 18461, new child is LWP 18465
LNW: waitpid(-1, ...) returned 0, ERRNO-OK
RSRL: resuming stopped-resumed LWP LWP 18465 at 0x3b36af4b51: step=0
RSRL: resuming stopped-resumed LWP LWP 18461 at 0x3b36af4b51: step=0
sigchld
ptrace: No such process.
(gdb) linux_nat_wait: [process -1], [TARGET_WNOHANG]
LLW: enter
LNW: waitpid(-1, ...) returned 18465, ERRNO-OK
LLW: waitpid 18465 received Killed (terminated)
LLW: LWP 18465 exited.
LNW: waitpid(-1, ...) returned 18461, No child processes
LLW: waitpid 18461 received Killed (terminated)
Process 18461 exited
LNW: waitpid(-1, ...) returned -1, No child processes
LLW: exit
sigchld
infrun: target_wait (-1, status) =
infrun: 18461 [process 18461],
infrun: status->kind = signalled, signal = GDB_SIGNAL_KILL
infrun: TARGET_WAITKIND_SIGNALLED
Program terminated with signal SIGKILL, Killed.
The program no longer exists.
infrun: stop_waiting
FAIL: gdb.threads/killed.exp: run program to completion (timeout)
The issue is that here:
RSRL: resuming stopped-resumed LWP LWP 18465 at 0x3b36af4b51: step=0
RSRL: resuming stopped-resumed LWP LWP 18461 at 0x3b36af4b51: step=0
The first line shows we had just resumed LWP 18465, which does:
void *
child_func (void *dummy)
{
kill (pid, SIGKILL);
exit (1);
}
So if the kernel manages to schedule that thread fast enough, the
process may be killed before GDB has a chance to resume LWP 18461.
GDBserver has code at the tail end of linux_resume_one_lwp to cope
with this:
~~~
ptrace (step ? PTRACE_SINGLESTEP : PTRACE_CONT, lwpid_of (thread),
(PTRACE_TYPE_ARG3) 0,
/* Coerce to a uintptr_t first to avoid potential gcc warning
of coercing an 8 byte integer to a 4 byte pointer. */
(PTRACE_TYPE_ARG4) (uintptr_t) signal);
current_thread = saved_thread;
if (errno)
{
/* ESRCH from ptrace either means that the thread was already
running (an error) or that it is gone (a race condition). If
it's gone, we will get a notification the next time we wait,
so we can ignore the error. We could differentiate these
two, but it's tricky without waiting; the thread still exists
as a zombie, so sending it signal 0 would succeed. So just
ignore ESRCH. */
if (errno == ESRCH)
return;
perror_with_name ("ptrace");
}
~~~
However, that's not a complete fix, because between starting to handle
the resume request and getting that PTRACE_CONTINUE, we run other
ptrace calls that can also fail with ESRCH, and that end up throwing
an error (with perror_with_name).
In the case above, I indeed sometimes see resume_stopped_resumed_lwps
fail in the registers read:
resume_stopped_resumed_lwps (struct lwp_info *lp, void *data)
{
...
CORE_ADDR pc = regcache_read_pc (regcache);
Or e.g., in 32-bit mode, i386_linux_resume has several calls that can
throw too.
Whether to ignore ptrace errors or not depends on context that is only
available somewhere up the call chain. So the fix is to let ptrace
errors throw as they do today, and wrap the resume request in a
TRY/CATCH that swallows it iff the lwp that we were trying to resume
is no longer ptrace-stopped.
gdb/gdbserver/ChangeLog:
2015-03-19 Pedro Alves <palves@redhat.com>
* linux-low.c (linux_resume_one_lwp): Rename to ...
(linux_resume_one_lwp_throw): ... this. Don't handle ESRCH here,
instead call perror_with_name.
(check_ptrace_stopped_lwp_gone): New function.
(linux_resume_one_lwp): Reimplement as wrapper around
linux_resume_one_lwp_throw that swallows errors if the LWP is
gone.
gdb/ChangeLog:
2015-03-19 Pedro Alves <palves@redhat.com>
* linux-nat.c (linux_resume_one_lwp): Rename to ...
(linux_resume_one_lwp_throw): ... this. Don't handle ESRCH here,
instead call perror_with_name.
(check_ptrace_stopped_lwp_gone): New function.
(linux_resume_one_lwp): Reimplement as wrapper around
linux_resume_one_lwp_throw that swallows errors if the LWP is
gone.
(resume_stopped_resumed_lwps): Try register reads in TRY/CATCH and
swallows errors if the LWP is gone. Use
linux_resume_one_lwp_throw instead of linux_resume_one_lwp.
2015-03-19 15:12:33 +00:00
|
|
|
/* Detect `T (tracing stop)' in `/proc/PID/status'.
|
|
|
|
Other states including `T (stopped)' are reported as false. */
|
|
|
|
|
|
|
|
int
|
|
|
|
linux_proc_pid_is_trace_stopped_nowarn (pid_t pid)
|
|
|
|
{
|
|
|
|
return linux_proc_pid_has_state (pid, "T (tracing stop)", 1);
|
|
|
|
}
|
|
|
|
|
Linux: on attach, attach to lwps listed under /proc/$pid/task/
... instead of relying on libthread_db.
I wrote a test that attaches to a program that constantly spawns
short-lived threads, which exposed several issues. This is one of
them.
On Linux, we need to attach to all threads of a process (thread group)
individually. We currently rely on libthread_db to list the threads,
but that is problematic, because libthread_db relies on reading data
structures out of the inferior (which may well be corrupted). If
threads are being created or exiting just while we try to attach, we
may trip on inconsistencies in the inferior's thread list. To work
around that, when we see a seemingly corrupt list, we currently retry
a few times:
static void
thread_db_find_new_threads_2 (ptid_t ptid, int until_no_new)
{
...
if (until_no_new)
{
/* Require 4 successive iterations which do not find any new threads.
The 4 is a heuristic: there is an inherent race here, and I have
seen that 2 iterations in a row are not always sufficient to
"capture" all threads. */
...
That heuristic may well fail, and when it does, we end up with threads
in the program that aren't under GDB's control. That's obviously bad
and results in quite mistifying failures, like e.g., the process dying
for seeminly no reason when a thread that wasn't attached trips on a
breakpoint.
There's really no reason to rely on libthread_db for this nowadays
when we have /proc mounted. In that case, which is the usual case, we
can list the LWPs from /proc/PID/task/. In fact, GDBserver is already
doing this. The patch factors out that code that knows to walk the
task/ directory out of GDBserver, and makes GDB use it too.
Like GDBserver, the patch makes GDB attach to LWPs and _not_ wait for
them to stop immediately. Instead, we just tag the LWP as having an
expected stop. Because we can only set the ptrace options when the
thread stops, we need a new flag in the lwp structure to keep track of
whether we've already set the ptrace options, just like in GDBserver.
Note that nothing issues any ptrace command to the threads between the
PTRACE_ATTACH and the stop, so this is safe (unlike one scenario
described in gdbserver's linux-low.c).
When we attach to a program that has threads exiting while we attach,
it's easy to race with a thread just exiting as we try to attach to
it, like:
#1 - get current list of threads
#2 - attach to each listed thread
#3 - ooops, attach failed, thread is already gone
As this is pretty normal, we shouldn't be issuing a scary warning in
step #3.
When #3 happens, PTRACE_ATTACH usually fails with ESRCH, but sometimes
we'll see EPERM as well. That happens when the kernel still has the
thread in its task list, but the thread is marked as dead.
Unfortunately, EPERM is ambiguous and we'll get it also on other
scenarios where the thread isn't dead, and in those cases, it's useful
to get a warning. To distiguish the cases, when we get an EPERM
failure, we open /proc/PID/status, and check the thread's state -- if
the /proc file no longer exists, or the state is "Z (Zombie)" or "X
(Dead)", we ignore the EPERM error silently; otherwise, we'll warn.
Unfortunately, there seems to be a kernel race here. Sometimes I get
EPERM, and then the /proc state still indicates "R (Running)"... If
we wait a bit and retry, we do end up seeing X or Z state, or get an
ESRCH. I thought of making GDB retry the attach a few times, but even
with a 500ms wait and 4 retries, I still see the warning sometimes. I
haven't been able to identify the kernel path that causes this yet,
but in any case, it looks like a kernel bug to me. As this just
results failure to suppress a warning that we've been printing since
about forever anyway, I'm just making the test cope with it, and issue
an XFAIL.
gdb/gdbserver/
2015-01-09 Pedro Alves <palves@redhat.com>
* linux-low.c (linux_attach_fail_reason_string): Move to
nat/linux-ptrace.c, and rename.
(linux_attach_lwp): Update comment.
(attach_proc_task_lwp_callback): New function.
(linux_attach): Adjust to rename and use
linux_proc_attach_tgid_threads.
(linux_attach_fail_reason_string): Delete declaration.
gdb/
2015-01-09 Pedro Alves <palves@redhat.com>
* linux-nat.c (attach_proc_task_lwp_callback): New function.
(linux_nat_attach): Use linux_proc_attach_tgid_threads.
(wait_lwp, linux_nat_filter_event): If not set yet, set the lwp's
ptrace option flags.
* linux-nat.h (struct lwp_info) <must_set_ptrace_flags>: New
field.
* nat/linux-procfs.c: Include <dirent.h>.
(linux_proc_get_int): New parameter "warn". Handle it.
(linux_proc_get_tgid): Adjust.
(linux_proc_get_tracerpid): Rename to ...
(linux_proc_get_tracerpid_nowarn): ... this.
(linux_proc_pid_get_state): New function, factored out from
(linux_proc_pid_has_state): ... this. Add new parameter "warn"
and handle it.
(linux_proc_pid_is_gone): New function.
(linux_proc_pid_is_stopped): Adjust.
(linux_proc_pid_is_zombie_maybe_warn)
(linux_proc_pid_is_zombie_nowarn): New functions.
(linux_proc_pid_is_zombie): Use
linux_proc_pid_is_zombie_maybe_warn.
(linux_proc_attach_tgid_threads): New function.
* nat/linux-procfs.h (linux_proc_get_tgid): Update comment.
(linux_proc_get_tracerpid): Rename to ...
(linux_proc_get_tracerpid_nowarn): ... this, and update comment.
(linux_proc_pid_is_gone): New declaration.
(linux_proc_pid_is_zombie): Update comment.
(linux_proc_pid_is_zombie_nowarn): New declaration.
(linux_proc_attach_lwp_func): New typedef.
(linux_proc_attach_tgid_threads): New declaration.
* nat/linux-ptrace.c (linux_ptrace_attach_fail_reason): Adjust to
use nowarn functions.
(linux_ptrace_attach_fail_reason_string): Move here from
gdbserver/linux-low.c and rename.
(ptrace_supports_feature): If the current ptrace options are not
known yet, check them now, instead of asserting.
* nat/linux-ptrace.h (linux_ptrace_attach_fail_reason_string):
Declare.
2014-12-16 16:12:24 +00:00
|
|
|
/* Return non-zero if PID is a zombie. If WARN, warn on failure to
|
|
|
|
open the /proc file. */
|
|
|
|
|
|
|
|
static int
|
|
|
|
linux_proc_pid_is_zombie_maybe_warn (pid_t pid, int warn)
|
|
|
|
{
|
|
|
|
return linux_proc_pid_has_state (pid, "Z (zombie)", warn);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* See linux-procfs.h declaration. */
|
|
|
|
|
|
|
|
int
|
|
|
|
linux_proc_pid_is_zombie_nowarn (pid_t pid)
|
|
|
|
{
|
|
|
|
return linux_proc_pid_is_zombie_maybe_warn (pid, 0);
|
2012-03-13 15:02:25 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* See linux-procfs.h declaration. */
|
|
|
|
|
|
|
|
int
|
|
|
|
linux_proc_pid_is_zombie (pid_t pid)
|
|
|
|
{
|
Linux: on attach, attach to lwps listed under /proc/$pid/task/
... instead of relying on libthread_db.
I wrote a test that attaches to a program that constantly spawns
short-lived threads, which exposed several issues. This is one of
them.
On Linux, we need to attach to all threads of a process (thread group)
individually. We currently rely on libthread_db to list the threads,
but that is problematic, because libthread_db relies on reading data
structures out of the inferior (which may well be corrupted). If
threads are being created or exiting just while we try to attach, we
may trip on inconsistencies in the inferior's thread list. To work
around that, when we see a seemingly corrupt list, we currently retry
a few times:
static void
thread_db_find_new_threads_2 (ptid_t ptid, int until_no_new)
{
...
if (until_no_new)
{
/* Require 4 successive iterations which do not find any new threads.
The 4 is a heuristic: there is an inherent race here, and I have
seen that 2 iterations in a row are not always sufficient to
"capture" all threads. */
...
That heuristic may well fail, and when it does, we end up with threads
in the program that aren't under GDB's control. That's obviously bad
and results in quite mistifying failures, like e.g., the process dying
for seeminly no reason when a thread that wasn't attached trips on a
breakpoint.
There's really no reason to rely on libthread_db for this nowadays
when we have /proc mounted. In that case, which is the usual case, we
can list the LWPs from /proc/PID/task/. In fact, GDBserver is already
doing this. The patch factors out that code that knows to walk the
task/ directory out of GDBserver, and makes GDB use it too.
Like GDBserver, the patch makes GDB attach to LWPs and _not_ wait for
them to stop immediately. Instead, we just tag the LWP as having an
expected stop. Because we can only set the ptrace options when the
thread stops, we need a new flag in the lwp structure to keep track of
whether we've already set the ptrace options, just like in GDBserver.
Note that nothing issues any ptrace command to the threads between the
PTRACE_ATTACH and the stop, so this is safe (unlike one scenario
described in gdbserver's linux-low.c).
When we attach to a program that has threads exiting while we attach,
it's easy to race with a thread just exiting as we try to attach to
it, like:
#1 - get current list of threads
#2 - attach to each listed thread
#3 - ooops, attach failed, thread is already gone
As this is pretty normal, we shouldn't be issuing a scary warning in
step #3.
When #3 happens, PTRACE_ATTACH usually fails with ESRCH, but sometimes
we'll see EPERM as well. That happens when the kernel still has the
thread in its task list, but the thread is marked as dead.
Unfortunately, EPERM is ambiguous and we'll get it also on other
scenarios where the thread isn't dead, and in those cases, it's useful
to get a warning. To distiguish the cases, when we get an EPERM
failure, we open /proc/PID/status, and check the thread's state -- if
the /proc file no longer exists, or the state is "Z (Zombie)" or "X
(Dead)", we ignore the EPERM error silently; otherwise, we'll warn.
Unfortunately, there seems to be a kernel race here. Sometimes I get
EPERM, and then the /proc state still indicates "R (Running)"... If
we wait a bit and retry, we do end up seeing X or Z state, or get an
ESRCH. I thought of making GDB retry the attach a few times, but even
with a 500ms wait and 4 retries, I still see the warning sometimes. I
haven't been able to identify the kernel path that causes this yet,
but in any case, it looks like a kernel bug to me. As this just
results failure to suppress a warning that we've been printing since
about forever anyway, I'm just making the test cope with it, and issue
an XFAIL.
gdb/gdbserver/
2015-01-09 Pedro Alves <palves@redhat.com>
* linux-low.c (linux_attach_fail_reason_string): Move to
nat/linux-ptrace.c, and rename.
(linux_attach_lwp): Update comment.
(attach_proc_task_lwp_callback): New function.
(linux_attach): Adjust to rename and use
linux_proc_attach_tgid_threads.
(linux_attach_fail_reason_string): Delete declaration.
gdb/
2015-01-09 Pedro Alves <palves@redhat.com>
* linux-nat.c (attach_proc_task_lwp_callback): New function.
(linux_nat_attach): Use linux_proc_attach_tgid_threads.
(wait_lwp, linux_nat_filter_event): If not set yet, set the lwp's
ptrace option flags.
* linux-nat.h (struct lwp_info) <must_set_ptrace_flags>: New
field.
* nat/linux-procfs.c: Include <dirent.h>.
(linux_proc_get_int): New parameter "warn". Handle it.
(linux_proc_get_tgid): Adjust.
(linux_proc_get_tracerpid): Rename to ...
(linux_proc_get_tracerpid_nowarn): ... this.
(linux_proc_pid_get_state): New function, factored out from
(linux_proc_pid_has_state): ... this. Add new parameter "warn"
and handle it.
(linux_proc_pid_is_gone): New function.
(linux_proc_pid_is_stopped): Adjust.
(linux_proc_pid_is_zombie_maybe_warn)
(linux_proc_pid_is_zombie_nowarn): New functions.
(linux_proc_pid_is_zombie): Use
linux_proc_pid_is_zombie_maybe_warn.
(linux_proc_attach_tgid_threads): New function.
* nat/linux-procfs.h (linux_proc_get_tgid): Update comment.
(linux_proc_get_tracerpid): Rename to ...
(linux_proc_get_tracerpid_nowarn): ... this, and update comment.
(linux_proc_pid_is_gone): New declaration.
(linux_proc_pid_is_zombie): Update comment.
(linux_proc_pid_is_zombie_nowarn): New declaration.
(linux_proc_attach_lwp_func): New typedef.
(linux_proc_attach_tgid_threads): New declaration.
* nat/linux-ptrace.c (linux_ptrace_attach_fail_reason): Adjust to
use nowarn functions.
(linux_ptrace_attach_fail_reason_string): Move here from
gdbserver/linux-low.c and rename.
(ptrace_supports_feature): If the current ptrace options are not
known yet, check them now, instead of asserting.
* nat/linux-ptrace.h (linux_ptrace_attach_fail_reason_string):
Declare.
2014-12-16 16:12:24 +00:00
|
|
|
return linux_proc_pid_is_zombie_maybe_warn (pid, 1);
|
2012-03-13 15:02:25 +00:00
|
|
|
}
|
2014-11-11 14:18:23 +00:00
|
|
|
|
|
|
|
/* See linux-procfs.h declaration. */
|
|
|
|
|
|
|
|
char *
|
|
|
|
linux_proc_pid_get_ns (pid_t pid, const char *ns)
|
|
|
|
{
|
|
|
|
char buf[100];
|
|
|
|
char nsval[64];
|
|
|
|
int ret;
|
|
|
|
xsnprintf (buf, sizeof (buf), "/proc/%d/ns/%s", (int) pid, ns);
|
|
|
|
ret = readlink (buf, nsval, sizeof (nsval));
|
|
|
|
if (0 < ret && ret < sizeof (nsval))
|
|
|
|
{
|
|
|
|
nsval[ret] = '\0';
|
|
|
|
return xstrdup (nsval);
|
|
|
|
}
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
Linux: on attach, attach to lwps listed under /proc/$pid/task/
... instead of relying on libthread_db.
I wrote a test that attaches to a program that constantly spawns
short-lived threads, which exposed several issues. This is one of
them.
On Linux, we need to attach to all threads of a process (thread group)
individually. We currently rely on libthread_db to list the threads,
but that is problematic, because libthread_db relies on reading data
structures out of the inferior (which may well be corrupted). If
threads are being created or exiting just while we try to attach, we
may trip on inconsistencies in the inferior's thread list. To work
around that, when we see a seemingly corrupt list, we currently retry
a few times:
static void
thread_db_find_new_threads_2 (ptid_t ptid, int until_no_new)
{
...
if (until_no_new)
{
/* Require 4 successive iterations which do not find any new threads.
The 4 is a heuristic: there is an inherent race here, and I have
seen that 2 iterations in a row are not always sufficient to
"capture" all threads. */
...
That heuristic may well fail, and when it does, we end up with threads
in the program that aren't under GDB's control. That's obviously bad
and results in quite mistifying failures, like e.g., the process dying
for seeminly no reason when a thread that wasn't attached trips on a
breakpoint.
There's really no reason to rely on libthread_db for this nowadays
when we have /proc mounted. In that case, which is the usual case, we
can list the LWPs from /proc/PID/task/. In fact, GDBserver is already
doing this. The patch factors out that code that knows to walk the
task/ directory out of GDBserver, and makes GDB use it too.
Like GDBserver, the patch makes GDB attach to LWPs and _not_ wait for
them to stop immediately. Instead, we just tag the LWP as having an
expected stop. Because we can only set the ptrace options when the
thread stops, we need a new flag in the lwp structure to keep track of
whether we've already set the ptrace options, just like in GDBserver.
Note that nothing issues any ptrace command to the threads between the
PTRACE_ATTACH and the stop, so this is safe (unlike one scenario
described in gdbserver's linux-low.c).
When we attach to a program that has threads exiting while we attach,
it's easy to race with a thread just exiting as we try to attach to
it, like:
#1 - get current list of threads
#2 - attach to each listed thread
#3 - ooops, attach failed, thread is already gone
As this is pretty normal, we shouldn't be issuing a scary warning in
step #3.
When #3 happens, PTRACE_ATTACH usually fails with ESRCH, but sometimes
we'll see EPERM as well. That happens when the kernel still has the
thread in its task list, but the thread is marked as dead.
Unfortunately, EPERM is ambiguous and we'll get it also on other
scenarios where the thread isn't dead, and in those cases, it's useful
to get a warning. To distiguish the cases, when we get an EPERM
failure, we open /proc/PID/status, and check the thread's state -- if
the /proc file no longer exists, or the state is "Z (Zombie)" or "X
(Dead)", we ignore the EPERM error silently; otherwise, we'll warn.
Unfortunately, there seems to be a kernel race here. Sometimes I get
EPERM, and then the /proc state still indicates "R (Running)"... If
we wait a bit and retry, we do end up seeing X or Z state, or get an
ESRCH. I thought of making GDB retry the attach a few times, but even
with a 500ms wait and 4 retries, I still see the warning sometimes. I
haven't been able to identify the kernel path that causes this yet,
but in any case, it looks like a kernel bug to me. As this just
results failure to suppress a warning that we've been printing since
about forever anyway, I'm just making the test cope with it, and issue
an XFAIL.
gdb/gdbserver/
2015-01-09 Pedro Alves <palves@redhat.com>
* linux-low.c (linux_attach_fail_reason_string): Move to
nat/linux-ptrace.c, and rename.
(linux_attach_lwp): Update comment.
(attach_proc_task_lwp_callback): New function.
(linux_attach): Adjust to rename and use
linux_proc_attach_tgid_threads.
(linux_attach_fail_reason_string): Delete declaration.
gdb/
2015-01-09 Pedro Alves <palves@redhat.com>
* linux-nat.c (attach_proc_task_lwp_callback): New function.
(linux_nat_attach): Use linux_proc_attach_tgid_threads.
(wait_lwp, linux_nat_filter_event): If not set yet, set the lwp's
ptrace option flags.
* linux-nat.h (struct lwp_info) <must_set_ptrace_flags>: New
field.
* nat/linux-procfs.c: Include <dirent.h>.
(linux_proc_get_int): New parameter "warn". Handle it.
(linux_proc_get_tgid): Adjust.
(linux_proc_get_tracerpid): Rename to ...
(linux_proc_get_tracerpid_nowarn): ... this.
(linux_proc_pid_get_state): New function, factored out from
(linux_proc_pid_has_state): ... this. Add new parameter "warn"
and handle it.
(linux_proc_pid_is_gone): New function.
(linux_proc_pid_is_stopped): Adjust.
(linux_proc_pid_is_zombie_maybe_warn)
(linux_proc_pid_is_zombie_nowarn): New functions.
(linux_proc_pid_is_zombie): Use
linux_proc_pid_is_zombie_maybe_warn.
(linux_proc_attach_tgid_threads): New function.
* nat/linux-procfs.h (linux_proc_get_tgid): Update comment.
(linux_proc_get_tracerpid): Rename to ...
(linux_proc_get_tracerpid_nowarn): ... this, and update comment.
(linux_proc_pid_is_gone): New declaration.
(linux_proc_pid_is_zombie): Update comment.
(linux_proc_pid_is_zombie_nowarn): New declaration.
(linux_proc_attach_lwp_func): New typedef.
(linux_proc_attach_tgid_threads): New declaration.
* nat/linux-ptrace.c (linux_ptrace_attach_fail_reason): Adjust to
use nowarn functions.
(linux_ptrace_attach_fail_reason_string): Move here from
gdbserver/linux-low.c and rename.
(ptrace_supports_feature): If the current ptrace options are not
known yet, check them now, instead of asserting.
* nat/linux-ptrace.h (linux_ptrace_attach_fail_reason_string):
Declare.
2014-12-16 16:12:24 +00:00
|
|
|
|
|
|
|
/* See linux-procfs.h. */
|
|
|
|
|
|
|
|
void
|
|
|
|
linux_proc_attach_tgid_threads (pid_t pid,
|
|
|
|
linux_proc_attach_lwp_func attach_lwp)
|
|
|
|
{
|
|
|
|
DIR *dir;
|
|
|
|
char pathname[128];
|
|
|
|
int new_threads_found;
|
|
|
|
int iterations;
|
|
|
|
|
|
|
|
if (linux_proc_get_tgid (pid) != pid)
|
|
|
|
return;
|
|
|
|
|
|
|
|
xsnprintf (pathname, sizeof (pathname), "/proc/%ld/task", (long) pid);
|
|
|
|
dir = opendir (pathname);
|
|
|
|
if (dir == NULL)
|
|
|
|
{
|
2015-01-13 10:36:34 +00:00
|
|
|
warning (_("Could not open /proc/%ld/task."), (long) pid);
|
Linux: on attach, attach to lwps listed under /proc/$pid/task/
... instead of relying on libthread_db.
I wrote a test that attaches to a program that constantly spawns
short-lived threads, which exposed several issues. This is one of
them.
On Linux, we need to attach to all threads of a process (thread group)
individually. We currently rely on libthread_db to list the threads,
but that is problematic, because libthread_db relies on reading data
structures out of the inferior (which may well be corrupted). If
threads are being created or exiting just while we try to attach, we
may trip on inconsistencies in the inferior's thread list. To work
around that, when we see a seemingly corrupt list, we currently retry
a few times:
static void
thread_db_find_new_threads_2 (ptid_t ptid, int until_no_new)
{
...
if (until_no_new)
{
/* Require 4 successive iterations which do not find any new threads.
The 4 is a heuristic: there is an inherent race here, and I have
seen that 2 iterations in a row are not always sufficient to
"capture" all threads. */
...
That heuristic may well fail, and when it does, we end up with threads
in the program that aren't under GDB's control. That's obviously bad
and results in quite mistifying failures, like e.g., the process dying
for seeminly no reason when a thread that wasn't attached trips on a
breakpoint.
There's really no reason to rely on libthread_db for this nowadays
when we have /proc mounted. In that case, which is the usual case, we
can list the LWPs from /proc/PID/task/. In fact, GDBserver is already
doing this. The patch factors out that code that knows to walk the
task/ directory out of GDBserver, and makes GDB use it too.
Like GDBserver, the patch makes GDB attach to LWPs and _not_ wait for
them to stop immediately. Instead, we just tag the LWP as having an
expected stop. Because we can only set the ptrace options when the
thread stops, we need a new flag in the lwp structure to keep track of
whether we've already set the ptrace options, just like in GDBserver.
Note that nothing issues any ptrace command to the threads between the
PTRACE_ATTACH and the stop, so this is safe (unlike one scenario
described in gdbserver's linux-low.c).
When we attach to a program that has threads exiting while we attach,
it's easy to race with a thread just exiting as we try to attach to
it, like:
#1 - get current list of threads
#2 - attach to each listed thread
#3 - ooops, attach failed, thread is already gone
As this is pretty normal, we shouldn't be issuing a scary warning in
step #3.
When #3 happens, PTRACE_ATTACH usually fails with ESRCH, but sometimes
we'll see EPERM as well. That happens when the kernel still has the
thread in its task list, but the thread is marked as dead.
Unfortunately, EPERM is ambiguous and we'll get it also on other
scenarios where the thread isn't dead, and in those cases, it's useful
to get a warning. To distiguish the cases, when we get an EPERM
failure, we open /proc/PID/status, and check the thread's state -- if
the /proc file no longer exists, or the state is "Z (Zombie)" or "X
(Dead)", we ignore the EPERM error silently; otherwise, we'll warn.
Unfortunately, there seems to be a kernel race here. Sometimes I get
EPERM, and then the /proc state still indicates "R (Running)"... If
we wait a bit and retry, we do end up seeing X or Z state, or get an
ESRCH. I thought of making GDB retry the attach a few times, but even
with a 500ms wait and 4 retries, I still see the warning sometimes. I
haven't been able to identify the kernel path that causes this yet,
but in any case, it looks like a kernel bug to me. As this just
results failure to suppress a warning that we've been printing since
about forever anyway, I'm just making the test cope with it, and issue
an XFAIL.
gdb/gdbserver/
2015-01-09 Pedro Alves <palves@redhat.com>
* linux-low.c (linux_attach_fail_reason_string): Move to
nat/linux-ptrace.c, and rename.
(linux_attach_lwp): Update comment.
(attach_proc_task_lwp_callback): New function.
(linux_attach): Adjust to rename and use
linux_proc_attach_tgid_threads.
(linux_attach_fail_reason_string): Delete declaration.
gdb/
2015-01-09 Pedro Alves <palves@redhat.com>
* linux-nat.c (attach_proc_task_lwp_callback): New function.
(linux_nat_attach): Use linux_proc_attach_tgid_threads.
(wait_lwp, linux_nat_filter_event): If not set yet, set the lwp's
ptrace option flags.
* linux-nat.h (struct lwp_info) <must_set_ptrace_flags>: New
field.
* nat/linux-procfs.c: Include <dirent.h>.
(linux_proc_get_int): New parameter "warn". Handle it.
(linux_proc_get_tgid): Adjust.
(linux_proc_get_tracerpid): Rename to ...
(linux_proc_get_tracerpid_nowarn): ... this.
(linux_proc_pid_get_state): New function, factored out from
(linux_proc_pid_has_state): ... this. Add new parameter "warn"
and handle it.
(linux_proc_pid_is_gone): New function.
(linux_proc_pid_is_stopped): Adjust.
(linux_proc_pid_is_zombie_maybe_warn)
(linux_proc_pid_is_zombie_nowarn): New functions.
(linux_proc_pid_is_zombie): Use
linux_proc_pid_is_zombie_maybe_warn.
(linux_proc_attach_tgid_threads): New function.
* nat/linux-procfs.h (linux_proc_get_tgid): Update comment.
(linux_proc_get_tracerpid): Rename to ...
(linux_proc_get_tracerpid_nowarn): ... this, and update comment.
(linux_proc_pid_is_gone): New declaration.
(linux_proc_pid_is_zombie): Update comment.
(linux_proc_pid_is_zombie_nowarn): New declaration.
(linux_proc_attach_lwp_func): New typedef.
(linux_proc_attach_tgid_threads): New declaration.
* nat/linux-ptrace.c (linux_ptrace_attach_fail_reason): Adjust to
use nowarn functions.
(linux_ptrace_attach_fail_reason_string): Move here from
gdbserver/linux-low.c and rename.
(ptrace_supports_feature): If the current ptrace options are not
known yet, check them now, instead of asserting.
* nat/linux-ptrace.h (linux_ptrace_attach_fail_reason_string):
Declare.
2014-12-16 16:12:24 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Scan the task list for existing threads. While we go through the
|
|
|
|
threads, new threads may be spawned. Cycle through the list of
|
|
|
|
threads until we have done two iterations without finding new
|
|
|
|
threads. */
|
|
|
|
for (iterations = 0; iterations < 2; iterations++)
|
|
|
|
{
|
|
|
|
struct dirent *dp;
|
|
|
|
|
|
|
|
new_threads_found = 0;
|
|
|
|
while ((dp = readdir (dir)) != NULL)
|
|
|
|
{
|
|
|
|
unsigned long lwp;
|
|
|
|
|
|
|
|
/* Fetch one lwp. */
|
|
|
|
lwp = strtoul (dp->d_name, NULL, 10);
|
|
|
|
if (lwp != 0)
|
|
|
|
{
|
|
|
|
ptid_t ptid = ptid_build (pid, lwp, 0);
|
|
|
|
|
|
|
|
if (attach_lwp (ptid))
|
|
|
|
new_threads_found = 1;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (new_threads_found)
|
|
|
|
{
|
|
|
|
/* Start over. */
|
|
|
|
iterations = -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
rewinddir (dir);
|
|
|
|
}
|
|
|
|
|
|
|
|
closedir (dir);
|
|
|
|
}
|
GNU/Linux: Stop using libthread_db/td_ta_thr_iter
TL;DR - GDB can hang if something refreshes the thread list out of the
target while the target is running. GDB hangs inside td_ta_thr_iter.
The fix is to not use that libthread_db function anymore.
Long version:
Running the testsuite against my all-stop-on-top-of-non-stop series is
still exposing latent non-stop bugs.
I was originally seeing this with the multi-create.exp test, back when
we were still using libthread_db thread event breakpoints. The
all-stop-on-top-of-non-stop series forces a thread list refresh each
time GDB needs to start stepping over a breakpoint (to pause all
threads). That test hits the thread event breakpoint often, resulting
in a bunch of step-over operations, thus a bunch of thread list
refreshes while some threads in the target are running.
The commit adds a real non-stop mode test that triggers the issue,
based on multi-create.exp, that does an explicit "info threads" when a
breakpoint is hit. IOW, it does the same things the as-ns series was
doing when testing multi-create.exp.
The bug is a race, so it unfortunately takes several runs for the test
to trigger it. In fact, even when setting the test running in a loop,
it sometimes takes several minutes for it to trigger for me.
The race is related to libthread_db's td_ta_thr_iter. This is
libthread_db's entry point for walking the thread list of the
inferior.
Sometimes, when GDB refreshes the thread list from the target,
libthread_db's td_ta_thr_iter can somehow see glibc's thread list as a
cycle, and get stuck in an infinite loop.
The issue is that when a thread exits, its thread control structure in
glibc is moved from a "used" list to a "cache" list. These lists are
simply circular linked lists where the "next/prev" pointers are
embedded in the thread control structure itself. The "next" pointer
of the last element of the list points back to the list's sentinel
"head". There's only one set of "next/prev" pointers for both lists;
thus a thread can only be in one of the lists at a time, not in both
simultaneously.
So when thread C exits, simplifying, the following happens. A-C are
threads. stack_used and stack_cache are the list's heads.
Before:
stack_used -> A -> B -> C -> (&stack_used)
stack_cache -> (&stack_cache)
After:
stack_used -> A -> B -> (&stack_used)
stack_cache -> C -> (&stack_cache)
td_ta_thr_iter starts by iterating at the list's head's next, and
iterates until it sees a thread whose next pointer points to the
list's head again. Thus in the before case above, C's next points to
stack_used, indicating end of list. In the same case, the stack_cache
list is empty.
For each thread being iterated, td_ta_thr_iter reads the whole thread
object out of the inferior. This includes the thread's "next"
pointer.
In the scenario above, it may happen that td_ta_thr_iter is iterating
thread B and has already read B's thread structure just before thread
C exits and its control structure moves to the cached list.
Now, recall that td_ta_thr_iter is running in the context of GDB, and
there's no locking between GDB and the inferior. From it's local copy
of B, td_ta_thr_iter believes that the next thread after B is thread
C, so it happilly continues iterating to C, a thread that has already
exited, and is now in the stack cache list.
After iterating C, td_ta_thr_iter finds the stack_cache head, which
because it is not stack_used, td_ta_thr_iter assumes it's just another
thread. After this, unless the reverse race triggers, GDB gets stuck
in td_ta_thr_iter forever walking the stack_cache list, as no thread
in thatlist has a next pointer that points back to stack_used (the
terminating condition).
Before fully understanding the issue, I tried adding cycle detection
to GDB's td_ta_thr_iter callback. However, td_ta_thr_iter skips
calling the callback in some cases, which means that it's possible
that the callback isn't called at all, making it impossible for GDB to
break the loop. I did manage to get GDB stuck in that state more than
once.
Fortunately, we can avoid the issue altogether. We don't really need
td_ta_thr_iter for live debugging nowadays, given PTRACE_EVENT_CLONE.
We already know how to map and lwp id to a thread id without iterating
(thread_from_lwp), so use that more.
gdb/ChangeLog:
2015-02-20 Pedro Alves <palves@redhat.com>
* linux-nat.c (linux_handle_extended_wait): Call
thread_db_notice_clone whenever a new clone LWP is detected.
(linux_stop_and_wait_all_lwps, linux_unstop_all_lwps): New
functions.
* linux-nat.h (thread_db_attach_lwp): Delete declaration.
(thread_db_notice_clone, linux_stop_and_wait_all_lwps)
(linux_unstop_all_lwps): Declare.
* linux-thread-db.c (struct thread_get_info_inout): Delete.
(thread_get_info_callback): Delete.
(thread_from_lwp): Use td_thr_get_info and record_thread.
(thread_db_attach_lwp): Delete.
(thread_db_notice_clone): New function.
(try_thread_db_load_1): If /proc is mounted and shows the
process'es task list, walk over all LWPs and call thread_from_lwp
instead of relying on td_ta_thr_iter.
(attach_thread): Don't call check_thread_signals here. Split the
tail part of the function (which adds the thread to the core GDB
thread list) to ...
(record_thread): ... this function. Call check_thread_signals
here.
(thread_db_wait): Don't call thread_db_find_new_threads_1. Always
call thread_from_lwp.
(thread_db_update_thread_list): Rename to ...
(thread_db_update_thread_list_org): ... this.
(thread_db_update_thread_list): New function.
(thread_db_find_thread_from_tid): Delete.
(thread_db_get_ada_task_ptid): Simplify.
* nat/linux-procfs.c: Include <sys/stat.h>.
(linux_proc_task_list_dir_exists): New function.
* nat/linux-procfs.h (linux_proc_task_list_dir_exists): Declare.
gdb/gdbserver/ChangeLog:
2015-02-20 Pedro Alves <palves@redhat.com>
* thread-db.c: Include "nat/linux-procfs.h".
(thread_db_init): Skip listing new threads if the kernel supports
PTRACE_EVENT_CLONE and /proc/PID/task/ is accessible.
gdb/testsuite/ChangeLog:
2015-02-20 Pedro Alves <palves@redhat.com>
* gdb.threads/multi-create-ns-info-thr.exp: New file.
2015-02-20 20:21:59 +00:00
|
|
|
|
|
|
|
/* See linux-procfs.h. */
|
|
|
|
|
|
|
|
int
|
|
|
|
linux_proc_task_list_dir_exists (pid_t pid)
|
|
|
|
{
|
|
|
|
char pathname[128];
|
|
|
|
struct stat buf;
|
|
|
|
|
|
|
|
xsnprintf (pathname, sizeof (pathname), "/proc/%ld/task", (long) pid);
|
|
|
|
return (stat (pathname, &buf) == 0);
|
|
|
|
}
|