aboutsummaryrefslogtreecommitdiff
path: root/gdb/common
diff options
context:
space:
mode:
authorPedro Alves <palves@redhat.com>2014-04-25 19:07:33 +0100
committerPedro Alves <palves@redhat.com>2014-04-25 19:07:33 +0100
commit7ae1a6a6ccda41aa8bbe9adb0f7fcde8bf8d5cb3 (patch)
treeac642730c7c29c0735909a95e60be6253fd24f49 /gdb/common
parent4082afcc3d1af9d8063d1c8e02deb34a8b97a489 (diff)
downloadfsf-binutils-gdb-7ae1a6a6ccda41aa8bbe9adb0f7fcde8bf8d5cb3.zip
fsf-binutils-gdb-7ae1a6a6ccda41aa8bbe9adb0f7fcde8bf8d5cb3.tar.gz
fsf-binutils-gdb-7ae1a6a6ccda41aa8bbe9adb0f7fcde8bf8d5cb3.tar.bz2
PR server/16255: gdbserver cannot attach to a second inferior that is multi-threaded.
On Linux, we need to explicitly ptrace attach to all lwps of a process. Because GDB might not be connected yet when an attach is requested, and thus it may not be possible to activate thread_db, as that requires access to symbols (IOW, gdbserver --attach), a while ago we make linux_attach loop over the lwps as listed by /proc/PID/task to find the lwps to attach to. linux_attach_lwp_1 has: ... if (initial) /* If lwp is the tgid, we handle adding existing threads later. Otherwise we just add lwp without bothering about any other threads. */ ptid = ptid_build (lwpid, lwpid, 0); else { /* Note that extracting the pid from the current inferior is safe, since we're always called in the context of the same process as this new thread. */ int pid = pid_of (current_inferior); ptid = ptid_build (pid, lwpid, 0); } That "safe" comment referred to linux_attach_lwp being called by thread-db.c. But this was clearly missed when a new call to linux_attach_lwp_1 was added to linux_attach. As a result, current_inferior will be set to some random process, and non-initial lwps of the second inferior get assigned the pid of the wrong inferior. E.g., in the case of attaching to two inferiors, for the second inferior (and so on), non-initial lwps of the second inferior get assigned the pid of the first inferior. This doesn't trigger on the first inferior, when current_inferior is NULL, add_thread switches the current inferior to the newly added thread. Rather than making linux_attach switch current_inferior temporarily (thus avoiding further reliance on global state), or making linux_attach_lwp_1 get the tgid from /proc, which add extra syscalls, and will be wrong in case of the user having originally attached directly to a non-tgid lwp, and then that lwp spawning new clones (the ptid.pid field of further new clones should be the same as the original lwp's pid, which is not the tgid), we note that callers of linux_attach_lwp/linux_attach_lwp_1 always have the right pid handy already, so they can pass it down along with the lwpid. The only other reason for the "initial" parameter is to error out instead of warn in case of attach failure, when we're first attaching to a process. There are only three callers of linux_attach_lwp/linux_attach_lwp_1, and each wants to print a different warn/error string, so we can just move the error/warn out of linux_attach_lwp_1 to the callers, thus getting rid of the "initial" parameter. There really nothing gdbserver-specific about attaching to two threaded processes, so this adds a new test under gdb.multi/. The test passes cleanly against the native GNU/Linux target, but fails/triggers the bug against GDBserver (before the patch), with the native-extended-remote board (as plain remote doesn't support multi-process). Tested on x86_64 Fedora 17, with the native-extended-gdbserver board. gdb/gdbserver/ 2014-04-25 Pedro Alves <palves@redhat.com> PR server/16255 * linux-low.c (linux_attach_fail_reason_string): New function. (linux_attach_lwp): Delete. (linux_attach_lwp_1): Rename to ... (linux_attach_lwp): ... this. Take a ptid instead of a pid as argument. Remove "initial" parameter. Return int instead of void. Don't error or warn here. (linux_attach): Adjust to call linux_attach_lwp. Call error on failure to attach to the tgid. Call warning when failing to attach to an lwp. * linux-low.h (linux_attach_lwp): Take a ptid instead of a pid as argument. Remove "initial" parameter. Return int instead of void. Don't error or warn here. (linux_attach_fail_reason_string): New declaration. * thread-db.c (attach_thread): Adjust to linux_attach_lwp's interface change. Use linux_attach_fail_reason_string. gdb/ 2014-04-25 Pedro Alves <palves@redhat.com> PR server/16255 * common/linux-ptrace.c (linux_ptrace_attach_warnings): Rename to ... (linux_ptrace_attach_fail_reason): ... this. Remove "warning: " and newline from built string. * common/linux-ptrace.h (linux_ptrace_attach_warnings): Rename to ... (linux_ptrace_attach_fail_reason): ... this. * linux-nat.c (linux_nat_attach): Adjust to use linux_ptrace_attach_fail_reason. gdb/testsuite/ 2014-04-25 Simon Marchi <simon.marchi@ericsson.com> Pedro Alves <palves@redhat.com> PR server/16255 * gdb.multi/multi-attach.c: New file. * gdb.multi/multi-attach.exp: New file.
Diffstat (limited to 'gdb/common')
-rw-r--r--gdb/common/linux-ptrace.c16
-rw-r--r--gdb/common/linux-ptrace.h2
2 files changed, 9 insertions, 9 deletions
diff --git a/gdb/common/linux-ptrace.c b/gdb/common/linux-ptrace.c
index 7c1b78a..efbd1ea 100644
--- a/gdb/common/linux-ptrace.c
+++ b/gdb/common/linux-ptrace.c
@@ -37,24 +37,24 @@
there are no supported features. */
static int current_ptrace_options = -1;
-/* Find all possible reasons we could fail to attach PID and append these
- newline terminated reason strings to initialized BUFFER. '\0' termination
- of BUFFER must be done by the caller. */
+/* Find all possible reasons we could fail to attach PID and append
+ these as strings to the already initialized BUFFER. '\0'
+ termination of BUFFER must be done by the caller. */
void
-linux_ptrace_attach_warnings (pid_t pid, struct buffer *buffer)
+linux_ptrace_attach_fail_reason (pid_t pid, struct buffer *buffer)
{
pid_t tracerpid;
tracerpid = linux_proc_get_tracerpid (pid);
if (tracerpid > 0)
- buffer_xml_printf (buffer, _("warning: process %d is already traced "
- "by process %d\n"),
+ buffer_xml_printf (buffer, _("process %d is already traced "
+ "by process %d"),
(int) pid, (int) tracerpid);
if (linux_proc_pid_is_zombie (pid))
- buffer_xml_printf (buffer, _("warning: process %d is a zombie "
- "- the process has already terminated\n"),
+ buffer_xml_printf (buffer, _("process %d is a zombie "
+ "- the process has already terminated"),
(int) pid);
}
diff --git a/gdb/common/linux-ptrace.h b/gdb/common/linux-ptrace.h
index 38bb9ea..881d9c9 100644
--- a/gdb/common/linux-ptrace.h
+++ b/gdb/common/linux-ptrace.h
@@ -83,7 +83,7 @@ struct buffer;
#define __WALL 0x40000000 /* Wait for any child. */
#endif
-extern void linux_ptrace_attach_warnings (pid_t pid, struct buffer *buffer);
+extern void linux_ptrace_attach_fail_reason (pid_t pid, struct buffer *buffer);
extern void linux_ptrace_init_warnings (void);
extern void linux_enable_event_reporting (pid_t pid);
extern int linux_supports_tracefork (void);