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
|
|
|
|
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:23 +00:00
|
|
|
|
2015-01-09 Pedro Alves <palves@redhat.com>
|
|
|
|
|
|
|
|
|
|
* linux-thread-db.c (thread_db_find_new_threads_silently)
|
|
|
|
|
(try_thread_db_load_1, try_thread_db_load, thread_db_load_search)
|
|
|
|
|
(find_new_threads_once): Print debug output on gdb_stdlog.
|
|
|
|
|
|
2015-01-09 10:09:03 +00:00
|
|
|
|
2015-01-09 Chen Gang <gang.chen.5i5j@gmail.com>
|
|
|
|
|
Pedro Alves <palves@redhat.com>
|
|
|
|
|
|
|
|
|
|
* compile/compile.c: Include "gdb_wait.h".
|
|
|
|
|
(do_rmdir): Check return value, and free 'zap'.
|
|
|
|
|
|
2014-12-28 08:12:53 +00:00
|
|
|
|
2015-01-08 Pedro Alves <palves@redhat.com>
|
|
|
|
|
Yao Qi <yao@codesourcery.com>
|
|
|
|
|
|
|
|
|
|
* dwarf2loc.c (indirect_pieced_value): Don't call
|
|
|
|
|
gdb_sign_extend. Call extract_signed_integer instead.
|
|
|
|
|
* utils.c (gdb_sign_extend): Remove.
|
|
|
|
|
* utils.h (gdb_sign_extend): Remove declaration.
|
|
|
|
|
|
2015-01-08 07:53:26 +00:00
|
|
|
|
2015-01-07 Pierre Muller <muller@sourceware.org>
|
|
|
|
|
|
|
|
|
|
PR symtab/17811
|
|
|
|
|
* stabsread.c (define_symbol): Set language for C++ special symbols.
|
|
|
|
|
|
2015-01-07 21:23:39 +00:00
|
|
|
|
2015-01-07 Patrick Palka <patrick@parcs.ath.cx>
|
|
|
|
|
|
|
|
|
|
* inflow.c (initial_gdb_ttystate): Tweak comment.
|
|
|
|
|
|
2015-01-07 14:49:49 +00:00
|
|
|
|
2015-01-07 Joel Brobecker <brobecker@adacore.com>
|
|
|
|
|
|
|
|
|
|
* inflow.c (set_initial_gdb_ttystate): Add empty line after
|
|
|
|
|
comment documenting function.
|
|
|
|
|
|
Don't propagate our current terminal state to the inferior
Currently when we start an inferior we have the inferior inherit our
terminal state. Under TUI, our terminal is highly modified by ncurses
and readline. So when starting an inferior under TUI, the inferior will
have a highly modified terminal state which will interfere with standard
I/O. For example,
$ gdb gdb
(gdb) break main
(gdb) run
(gdb) print puts ("a\nb")
a
b
$1 = 4
(gdb) [enter TUI mode]
(gdb) run
(gdb) [exit TUI mode]
(gdb) print puts ("a\nb")
a
b
$2 = 4
(gdb) print puts ("a\r\nb\r")
a
b
$3 = 6
As you can see, when we start the inferior under the regular interface,
puts() prints the text properly. But when we start the inferior under
TUI, puts() does not print the text properly. This is because when we
start the inferior under TUI it inherits our current terminal state
which has been modified by ncurses to, among other things, require an
explicit \r\n to print a new line. As a result the inferior performs
standard I/O in an unexpected way.
Because of this discrepancy, it doesn't seem like a good idea to have
the inferior inherit our _current_ terminal state for it may have been
modified by readline and/or ncurses. Instead, we should have the
inferior inherit a pristine snapshot of our terminal state taken before
readline or ncurses have had a chance to alter it. This enables the
inferior to run in a more accurate way, more closely mimicking the
program's behavior had it run standalone. And it fixes the above
mentioned issue.
Tested on x86_64-unknown-linux-gnu.
gdb/ChangeLog:
* terminal.h (set_initial_gdb_ttystate): Declare.
* inflow.c (initial_gdb_ttystate): New static variable.
(set_initial_gdb_ttystate): New setter.
(child_terminal_init_with_pgrp): Copy initial_gdb_ttystate
instead of our current terminal state.
* top.c (gdb_init): Call set_initial_gdb_ttystate.
2014-11-22 19:12:49 +00:00
|
|
|
|
2015-01-07 Patrick Palka <patrick@parcs.ath.cx>
|
|
|
|
|
|
|
|
|
|
* terminal.h (set_initial_gdb_ttystate): Declare.
|
|
|
|
|
* inflow.c (initial_gdb_ttystate): New static variable.
|
|
|
|
|
(set_initial_gdb_ttystate): New setter.
|
|
|
|
|
(child_terminal_init_with_pgrp): Copy initial_gdb_ttystate
|
|
|
|
|
instead of our current terminal state.
|
|
|
|
|
* top.c (gdb_init): Call set_initial_gdb_ttystate.
|
|
|
|
|
|
2015-01-07 03:34:29 +00:00
|
|
|
|
2015-01-07 Joel Brobecker <brobecker@adacore.com>
|
|
|
|
|
|
|
|
|
|
* guile/scm-type.c (tyscm_array_1): Add comment.
|
|
|
|
|
* python/py-type.c (typy_array_1): Add comment.
|
|
|
|
|
|
2015-01-06 14:37:53 +00:00
|
|
|
|
2015-01-06 Joel Brobecker <brobecker@adacore.com>
|
|
|
|
|
|
|
|
|
|
* guile/scm-type.c (tyscm_array_1): Do not raise out-of-range
|
|
|
|
|
error if N2 is equal to N1 - 1.
|
|
|
|
|
|
2015-01-06 14:30:53 +00:00
|
|
|
|
2015-01-06 Joel Brobecker <brobecker@adacore.com>
|
|
|
|
|
|
|
|
|
|
* python/py-type.c (typy_array_1): Do not raise negative-length
|
|
|
|
|
exception if N2 is equal to N1 - 1.
|
|
|
|
|
|
2015-01-03 20:01:29 +00:00
|
|
|
|
2015-01-03 Doug Evans <xdje42@gmail.com>
|
|
|
|
|
|
|
|
|
|
* c-exp.y: Whitespace cleanup.
|
|
|
|
|
(classify_inner_name): Remove extra ;.
|
|
|
|
|
|
2015-01-02 23:36:05 +00:00
|
|
|
|
2015-01-02 Maciej W. Rozycki <macro@codesourcery.com>
|
|
|
|
|
|
|
|
|
|
* mips-tdep.c (mips32_scan_prologue): Keep the extracted stack
|
|
|
|
|
offset signed.
|
|
|
|
|
|
2015-01-02 19:49:14 +00:00
|
|
|
|
2015-01-02 Doug Evans <dje@google.com>
|
|
|
|
|
|
|
|
|
|
* dwarf2read.c (setup_type_unit_groups): Remove outdated comment.
|
|
|
|
|
|
2015-01-02 19:02:31 +00:00
|
|
|
|
2015-01-02 Doug Evans <dje@google.com>
|
|
|
|
|
|
|
|
|
|
* symtab.h (struct symbol): Fix typo in comment.
|
|
|
|
|
|
2015-01-01 09:32:14 +00:00
|
|
|
|
2015-01-01 Joel Brobecker <brobecker@adacore.com>
|
|
|
|
|
|
|
|
|
|
Update year range in copyright notice of all files.
|
|
|
|
|
|
2015-01-01 09:24:41 +00:00
|
|
|
|
2015-01-01 Joel Brobecker <brobecker@adacore.com>
|
|
|
|
|
|
|
|
|
|
* top.c (print_gdb_version): Update copyright year to 2015.
|
|
|
|
|
|
2015-01-01 09:21:14 +00:00
|
|
|
|
2015-01-01 Joel Brobecker <brobecker@adacore.com>
|
2014-12-30 07:36:53 +00:00
|
|
|
|
|
2015-01-01 09:21:14 +00:00
|
|
|
|
* config/djgpp/fnchange.lst: Add entry for gdb/ChangeLog-2014.
|
2014-12-30 07:36:53 +00:00
|
|
|
|
|
2015-01-01 09:21:14 +00:00
|
|
|
|
For older changes see ChangeLog-2014.
|
1999-04-16 01:35:26 +00:00
|
|
|
|
|
|
|
|
|
Local Variables:
|
|
|
|
|
mode: change-log
|
|
|
|
|
left-margin: 8
|
|
|
|
|
fill-column: 74
|
|
|
|
|
version-control: never
|
2007-08-09 22:44:38 +00:00
|
|
|
|
coding: utf-8
|
1999-04-16 01:35:26 +00:00
|
|
|
|
End:
|