* Makefile.in (linux_nat_h): Update dependencies.
* configure.in: Check for <gnu/libc-version.h>. * configure: Regenerate. * config.in: Regenerate. * linux-nat.h: Include "target.h". Add waitstatus field to struct lwp_info. * lin-lwp.c (add_lwp): Initialize waitstatus.kind. (lin_lwp_attach_lwp): Don't attach to LWPs we have already attached to. (lin_lwp_handle_extended): New function. Handle clone events. (wait_lwp): Use lin_lwp_handle_extended. Update comment about thread exit events. (child_wait): Handle clone events. (lin_lwp_wait: Use lin_lwp_handle_extended and handle clone events. * linux-nat.c (linux_enable_event_reporting): Turn on PTRACE_O_TRACECLONE. (linux_handle_extended_wait): Handle clone events. * thread-db.c: Include <gnu/libc-version.h>. (struct private_thread_info): Add dying flag. (enable_thread_event_reporting): Enable TD_DEATH for glibc 2.2 and higher. (attach_thread): Update comments. Handle dying threads. (detach_thread): Set the dying flag. (check_event): Always call attach_thread.
This commit is contained in:
parent
8d5f9dcb37
commit
a2f23071c9
|
@ -1,3 +1,30 @@
|
||||||
|
2004-03-29 Daniel Jacobowitz <drow@mvista.com>
|
||||||
|
|
||||||
|
* Makefile.in (linux_nat_h): Update dependencies.
|
||||||
|
* configure.in: Check for <gnu/libc-version.h>.
|
||||||
|
* configure: Regenerate.
|
||||||
|
* config.in: Regenerate.
|
||||||
|
* linux-nat.h: Include "target.h". Add waitstatus field to
|
||||||
|
struct lwp_info.
|
||||||
|
* lin-lwp.c (add_lwp): Initialize waitstatus.kind.
|
||||||
|
(lin_lwp_attach_lwp): Don't attach to LWPs we have already attached
|
||||||
|
to.
|
||||||
|
(lin_lwp_handle_extended): New function. Handle clone events.
|
||||||
|
(wait_lwp): Use lin_lwp_handle_extended. Update comment about
|
||||||
|
thread exit events.
|
||||||
|
(child_wait): Handle clone events.
|
||||||
|
(lin_lwp_wait: Use lin_lwp_handle_extended and handle clone events.
|
||||||
|
* linux-nat.c (linux_enable_event_reporting): Turn on
|
||||||
|
PTRACE_O_TRACECLONE.
|
||||||
|
(linux_handle_extended_wait): Handle clone events.
|
||||||
|
* thread-db.c: Include <gnu/libc-version.h>.
|
||||||
|
(struct private_thread_info): Add dying flag.
|
||||||
|
(enable_thread_event_reporting): Enable TD_DEATH for glibc 2.2 and
|
||||||
|
higher.
|
||||||
|
(attach_thread): Update comments. Handle dying threads.
|
||||||
|
(detach_thread): Set the dying flag.
|
||||||
|
(check_event): Always call attach_thread.
|
||||||
|
|
||||||
2004-03-29 Daniel Jacobowitz <drow@mvista.com>
|
2004-03-29 Daniel Jacobowitz <drow@mvista.com>
|
||||||
|
|
||||||
* mips-tdep.c (mips_pdr_data): New.
|
* mips-tdep.c (mips_pdr_data): New.
|
||||||
|
|
|
@ -699,7 +699,7 @@ kod_h = kod.h
|
||||||
language_h = language.h
|
language_h = language.h
|
||||||
libunwind_frame_h = libunwind-frame.h $(libunwind_h)
|
libunwind_frame_h = libunwind-frame.h $(libunwind_h)
|
||||||
linespec_h = linespec.h
|
linespec_h = linespec.h
|
||||||
linux_nat_h = linux-nat.h
|
linux_nat_h = linux-nat.h $(target_h)
|
||||||
m2_lang_h = m2-lang.h
|
m2_lang_h = m2-lang.h
|
||||||
m68k_tdep_h = m68k-tdep.h
|
m68k_tdep_h = m68k-tdep.h
|
||||||
macroexp_h = macroexp.h
|
macroexp_h = macroexp.h
|
||||||
|
|
|
@ -266,6 +266,9 @@
|
||||||
/* Define if you have the <dirent.h> header file. */
|
/* Define if you have the <dirent.h> header file. */
|
||||||
#undef HAVE_DIRENT_H
|
#undef HAVE_DIRENT_H
|
||||||
|
|
||||||
|
/* Define if you have the <gnu/libc-version.h> header file. */
|
||||||
|
#undef HAVE_GNU_LIBC_VERSION_H
|
||||||
|
|
||||||
/* Define if you have the <libunwind-ia64.h> header file. */
|
/* Define if you have the <libunwind-ia64.h> header file. */
|
||||||
#undef HAVE_LIBUNWIND_IA64_H
|
#undef HAVE_LIBUNWIND_IA64_H
|
||||||
|
|
||||||
|
|
|
@ -4756,7 +4756,7 @@ else
|
||||||
fi
|
fi
|
||||||
done
|
done
|
||||||
|
|
||||||
for ac_hdr in proc_service.h thread_db.h
|
for ac_hdr in proc_service.h thread_db.h gnu/libc-version.h
|
||||||
do
|
do
|
||||||
ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'`
|
ac_safe=`echo "$ac_hdr" | sed 'y%./+-%__p_%'`
|
||||||
echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6
|
echo $ac_n "checking for $ac_hdr""... $ac_c" 1>&6
|
||||||
|
|
|
@ -342,7 +342,7 @@ AC_CHECK_HEADERS(link.h)
|
||||||
AC_CHECK_HEADERS(machine/reg.h)
|
AC_CHECK_HEADERS(machine/reg.h)
|
||||||
AC_CHECK_HEADERS(nlist.h)
|
AC_CHECK_HEADERS(nlist.h)
|
||||||
AC_CHECK_HEADERS(poll.h sys/poll.h)
|
AC_CHECK_HEADERS(poll.h sys/poll.h)
|
||||||
AC_CHECK_HEADERS(proc_service.h thread_db.h)
|
AC_CHECK_HEADERS(proc_service.h thread_db.h gnu/libc-version.h)
|
||||||
AC_CHECK_HEADERS(stddef.h)
|
AC_CHECK_HEADERS(stddef.h)
|
||||||
AC_CHECK_HEADERS(stdlib.h)
|
AC_CHECK_HEADERS(stdlib.h)
|
||||||
AC_CHECK_HEADERS(stdint.h)
|
AC_CHECK_HEADERS(stdint.h)
|
||||||
|
|
123
gdb/lin-lwp.c
123
gdb/lin-lwp.c
|
@ -1,5 +1,5 @@
|
||||||
/* Multi-threaded debugging support for GNU/Linux (LWP layer).
|
/* Multi-threaded debugging support for GNU/Linux (LWP layer).
|
||||||
Copyright 2000, 2001, 2002, 2003 Free Software Foundation, Inc.
|
Copyright 2000, 2001, 2002, 2003, 2004 Free Software Foundation, Inc.
|
||||||
|
|
||||||
This file is part of GDB.
|
This file is part of GDB.
|
||||||
|
|
||||||
|
@ -183,6 +183,8 @@ add_lwp (ptid_t ptid)
|
||||||
|
|
||||||
memset (lp, 0, sizeof (struct lwp_info));
|
memset (lp, 0, sizeof (struct lwp_info));
|
||||||
|
|
||||||
|
lp->waitstatus.kind = TARGET_WAITKIND_IGNORE;
|
||||||
|
|
||||||
lp->ptid = ptid;
|
lp->ptid = ptid;
|
||||||
|
|
||||||
lp->next = lwp_list;
|
lp->next = lwp_list;
|
||||||
|
@ -278,7 +280,7 @@ lin_lwp_open (char *args, int from_tty)
|
||||||
void
|
void
|
||||||
lin_lwp_attach_lwp (ptid_t ptid, int verbose)
|
lin_lwp_attach_lwp (ptid_t ptid, int verbose)
|
||||||
{
|
{
|
||||||
struct lwp_info *lp;
|
struct lwp_info *lp, *found_lp;
|
||||||
|
|
||||||
gdb_assert (is_lwp (ptid));
|
gdb_assert (is_lwp (ptid));
|
||||||
|
|
||||||
|
@ -293,13 +295,17 @@ lin_lwp_attach_lwp (ptid_t ptid, int verbose)
|
||||||
if (verbose)
|
if (verbose)
|
||||||
printf_filtered ("[New %s]\n", target_pid_to_str (ptid));
|
printf_filtered ("[New %s]\n", target_pid_to_str (ptid));
|
||||||
|
|
||||||
lp = find_lwp_pid (ptid);
|
found_lp = lp = find_lwp_pid (ptid);
|
||||||
if (lp == NULL)
|
if (lp == NULL)
|
||||||
lp = add_lwp (ptid);
|
lp = add_lwp (ptid);
|
||||||
|
|
||||||
/* We assume that we're already attached to any LWP that has an
|
/* We assume that we're already attached to any LWP that has an id
|
||||||
id equal to the overall process id. */
|
equal to the overall process id, and to any LWP that is already
|
||||||
if (GET_LWP (ptid) != GET_PID (ptid))
|
in our list of LWPs. If we're not seeing exit events from threads
|
||||||
|
and we've had PID wraparound since we last tried to stop all threads,
|
||||||
|
this assumption might be wrong; fortunately, this is very unlikely
|
||||||
|
to happen. */
|
||||||
|
if (GET_LWP (ptid) != GET_PID (ptid) && found_lp == NULL)
|
||||||
{
|
{
|
||||||
pid_t pid;
|
pid_t pid;
|
||||||
int status;
|
int status;
|
||||||
|
@ -590,6 +596,41 @@ kill_lwp (int lwpid, int signo)
|
||||||
return kill (lwpid, signo);
|
return kill (lwpid, signo);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Handle a GNU/Linux extended wait response. Most of the work we
|
||||||
|
just pass off to linux_handle_extended_wait, but if it reports a
|
||||||
|
clone event we need to add the new LWP to our list (and not report
|
||||||
|
the trap to higher layers). This function returns non-zero if
|
||||||
|
the event should be ignored and we should wait again. */
|
||||||
|
|
||||||
|
static int
|
||||||
|
lin_lwp_handle_extended (struct lwp_info *lp, int status)
|
||||||
|
{
|
||||||
|
linux_handle_extended_wait (GET_LWP (lp->ptid), status,
|
||||||
|
&lp->waitstatus);
|
||||||
|
|
||||||
|
/* TARGET_WAITKIND_SPURIOUS is used to indicate clone events. */
|
||||||
|
if (lp->waitstatus.kind == TARGET_WAITKIND_SPURIOUS)
|
||||||
|
{
|
||||||
|
struct lwp_info *new_lp;
|
||||||
|
new_lp = add_lwp (BUILD_LWP (lp->waitstatus.value.related_pid,
|
||||||
|
GET_PID (inferior_ptid)));
|
||||||
|
new_lp->cloned = 1;
|
||||||
|
new_lp->stopped = 1;
|
||||||
|
|
||||||
|
lp->waitstatus.kind = TARGET_WAITKIND_IGNORE;
|
||||||
|
|
||||||
|
if (debug_lin_lwp)
|
||||||
|
fprintf_unfiltered (gdb_stdlog,
|
||||||
|
"LLHE: Got clone event from LWP %ld, resuming\n",
|
||||||
|
GET_LWP (lp->ptid));
|
||||||
|
ptrace (PTRACE_CONT, GET_LWP (lp->ptid), 0, 0);
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
/* Wait for LP to stop. Returns the wait status, or 0 if the LWP has
|
/* Wait for LP to stop. Returns the wait status, or 0 if the LWP has
|
||||||
exited. */
|
exited. */
|
||||||
|
|
||||||
|
@ -609,9 +650,11 @@ wait_lwp (struct lwp_info *lp)
|
||||||
pid = waitpid (GET_LWP (lp->ptid), &status, __WCLONE);
|
pid = waitpid (GET_LWP (lp->ptid), &status, __WCLONE);
|
||||||
if (pid == -1 && errno == ECHILD)
|
if (pid == -1 && errno == ECHILD)
|
||||||
{
|
{
|
||||||
/* The thread has previously exited. We need to delete it now
|
/* The thread has previously exited. We need to delete it
|
||||||
because in the case of NPTL threads, there won't be an
|
now because, for some vendor 2.4 kernels with NPTL
|
||||||
exit event unless it is the main thread. */
|
support backported, there won't be an exit event unless
|
||||||
|
it is the main thread. 2.6 kernels will report an exit
|
||||||
|
event for each thread that exits, as expected. */
|
||||||
thread_dead = 1;
|
thread_dead = 1;
|
||||||
if (debug_lin_lwp)
|
if (debug_lin_lwp)
|
||||||
fprintf_unfiltered (gdb_stdlog, "WL: %s vanished.\n",
|
fprintf_unfiltered (gdb_stdlog, "WL: %s vanished.\n",
|
||||||
|
@ -658,6 +701,17 @@ wait_lwp (struct lwp_info *lp)
|
||||||
|
|
||||||
gdb_assert (WIFSTOPPED (status));
|
gdb_assert (WIFSTOPPED (status));
|
||||||
|
|
||||||
|
/* Handle GNU/Linux's extended waitstatus for trace events. */
|
||||||
|
if (WIFSTOPPED (status) && WSTOPSIG (status) == SIGTRAP && status >> 16 != 0)
|
||||||
|
{
|
||||||
|
if (debug_lin_lwp)
|
||||||
|
fprintf_unfiltered (gdb_stdlog,
|
||||||
|
"WL: Handling extended status 0x%06x\n",
|
||||||
|
status);
|
||||||
|
if (lin_lwp_handle_extended (lp, status))
|
||||||
|
return wait_lwp (lp);
|
||||||
|
}
|
||||||
|
|
||||||
return status;
|
return status;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1097,6 +1151,8 @@ child_wait (ptid_t ptid, struct target_waitstatus *ourstatus)
|
||||||
int status;
|
int status;
|
||||||
pid_t pid;
|
pid_t pid;
|
||||||
|
|
||||||
|
ourstatus->kind = TARGET_WAITKIND_IGNORE;
|
||||||
|
|
||||||
do
|
do
|
||||||
{
|
{
|
||||||
set_sigint_trap (); /* Causes SIGINT to be passed on to the
|
set_sigint_trap (); /* Causes SIGINT to be passed on to the
|
||||||
|
@ -1143,6 +1199,25 @@ child_wait (ptid_t ptid, struct target_waitstatus *ourstatus)
|
||||||
save_errno = EINTR;
|
save_errno = EINTR;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Handle GNU/Linux's extended waitstatus for trace events. */
|
||||||
|
if (pid != -1 && WIFSTOPPED (status) && WSTOPSIG (status) == SIGTRAP
|
||||||
|
&& status >> 16 != 0)
|
||||||
|
{
|
||||||
|
linux_handle_extended_wait (pid, status, ourstatus);
|
||||||
|
|
||||||
|
/* If we see a clone event, detach the child, and don't
|
||||||
|
report the event. It would be nice to offer some way to
|
||||||
|
switch into a non-thread-db based threaded mode at this
|
||||||
|
point. */
|
||||||
|
if (ourstatus->kind == TARGET_WAITKIND_SPURIOUS)
|
||||||
|
{
|
||||||
|
ptrace (PTRACE_DETACH, ourstatus->value.related_pid, 0, 0);
|
||||||
|
ourstatus->kind = TARGET_WAITKIND_IGNORE;
|
||||||
|
pid = -1;
|
||||||
|
save_errno = EINTR;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
clear_sigio_trap ();
|
clear_sigio_trap ();
|
||||||
clear_sigint_trap ();
|
clear_sigint_trap ();
|
||||||
}
|
}
|
||||||
|
@ -1159,11 +1234,9 @@ child_wait (ptid_t ptid, struct target_waitstatus *ourstatus)
|
||||||
return minus_one_ptid;
|
return minus_one_ptid;
|
||||||
}
|
}
|
||||||
|
|
||||||
/* Handle GNU/Linux's extended waitstatus for trace events. */
|
if (ourstatus->kind == TARGET_WAITKIND_IGNORE)
|
||||||
if (WIFSTOPPED (status) && WSTOPSIG (status) == SIGTRAP && status >> 16 != 0)
|
|
||||||
return linux_handle_extended_wait (pid, status, ourstatus);
|
|
||||||
|
|
||||||
store_waitstatus (ourstatus, status);
|
store_waitstatus (ourstatus, status);
|
||||||
|
|
||||||
return pid_to_ptid (pid);
|
return pid_to_ptid (pid);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1371,6 +1444,20 @@ retry:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Handle GNU/Linux's extended waitstatus for trace events. */
|
||||||
|
if (WIFSTOPPED (status) && WSTOPSIG (status) == SIGTRAP && status >> 16 != 0)
|
||||||
|
{
|
||||||
|
if (debug_lin_lwp)
|
||||||
|
fprintf_unfiltered (gdb_stdlog,
|
||||||
|
"LLW: Handling extended status 0x%06x\n",
|
||||||
|
status);
|
||||||
|
if (lin_lwp_handle_extended (lp, status))
|
||||||
|
{
|
||||||
|
status = 0;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* Check if the thread has exited. */
|
/* Check if the thread has exited. */
|
||||||
if ((WIFEXITED (status) || WIFSIGNALED (status)) && num_lwps > 1)
|
if ((WIFEXITED (status) || WIFSIGNALED (status)) && num_lwps > 1)
|
||||||
{
|
{
|
||||||
|
@ -1588,14 +1675,14 @@ retry:
|
||||||
else
|
else
|
||||||
trap_ptid = null_ptid;
|
trap_ptid = null_ptid;
|
||||||
|
|
||||||
/* Handle GNU/Linux's extended waitstatus for trace events. */
|
if (lp->waitstatus.kind != TARGET_WAITKIND_IGNORE)
|
||||||
if (WIFSTOPPED (status) && WSTOPSIG (status) == SIGTRAP && status >> 16 != 0)
|
|
||||||
{
|
{
|
||||||
linux_handle_extended_wait (GET_LWP (lp->ptid), status, ourstatus);
|
*ourstatus = lp->waitstatus;
|
||||||
return trap_ptid;
|
lp->waitstatus.kind = TARGET_WAITKIND_IGNORE;
|
||||||
}
|
}
|
||||||
|
else
|
||||||
store_waitstatus (ourstatus, status);
|
store_waitstatus (ourstatus, status);
|
||||||
|
|
||||||
return (threaded ? lp->ptid : pid_to_ptid (GET_LWP (lp->ptid)));
|
return (threaded ? lp->ptid : pid_to_ptid (GET_LWP (lp->ptid)));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/* GNU/Linux native-dependent code common to multiple platforms.
|
/* GNU/Linux native-dependent code common to multiple platforms.
|
||||||
Copyright (C) 2003 Free Software Foundation, Inc.
|
Copyright (C) 2003, 2004 Free Software Foundation, Inc.
|
||||||
|
|
||||||
This file is part of GDB.
|
This file is part of GDB.
|
||||||
|
|
||||||
|
@ -224,7 +224,8 @@ linux_enable_event_reporting (ptid_t ptid)
|
||||||
if (! linux_supports_tracefork ())
|
if (! linux_supports_tracefork ())
|
||||||
return;
|
return;
|
||||||
|
|
||||||
options = PTRACE_O_TRACEFORK | PTRACE_O_TRACEVFORK | PTRACE_O_TRACEEXEC;
|
options = PTRACE_O_TRACEFORK | PTRACE_O_TRACEVFORK | PTRACE_O_TRACEEXEC
|
||||||
|
| PTRACE_O_TRACECLONE;
|
||||||
if (linux_supports_tracevforkdone ())
|
if (linux_supports_tracevforkdone ())
|
||||||
options |= PTRACE_O_TRACEVFORKDONE;
|
options |= PTRACE_O_TRACEVFORKDONE;
|
||||||
|
|
||||||
|
@ -391,11 +392,8 @@ linux_handle_extended_wait (int pid, int status,
|
||||||
{
|
{
|
||||||
int event = status >> 16;
|
int event = status >> 16;
|
||||||
|
|
||||||
if (event == PTRACE_EVENT_CLONE)
|
if (event == PTRACE_EVENT_FORK || event == PTRACE_EVENT_VFORK
|
||||||
internal_error (__FILE__, __LINE__,
|
|| event == PTRACE_EVENT_CLONE)
|
||||||
"unexpected clone event");
|
|
||||||
|
|
||||||
if (event == PTRACE_EVENT_FORK || event == PTRACE_EVENT_VFORK)
|
|
||||||
{
|
{
|
||||||
unsigned long new_pid;
|
unsigned long new_pid;
|
||||||
int ret;
|
int ret;
|
||||||
|
@ -406,12 +404,10 @@ linux_handle_extended_wait (int pid, int status,
|
||||||
if (! pull_pid_from_list (&stopped_pids, new_pid))
|
if (! pull_pid_from_list (&stopped_pids, new_pid))
|
||||||
{
|
{
|
||||||
/* The new child has a pending SIGSTOP. We can't affect it until it
|
/* The new child has a pending SIGSTOP. We can't affect it until it
|
||||||
hits the SIGSTOP, but we're already attached.
|
hits the SIGSTOP, but we're already attached. */
|
||||||
|
|
||||||
It won't be a clone (we didn't ask for clones in the event mask)
|
|
||||||
so we can just call waitpid and wait for the SIGSTOP. */
|
|
||||||
do {
|
do {
|
||||||
ret = waitpid (new_pid, &status, 0);
|
ret = waitpid (new_pid, &status,
|
||||||
|
(event == PTRACE_EVENT_CLONE) ? __WCLONE : 0);
|
||||||
} while (ret == -1 && errno == EINTR);
|
} while (ret == -1 && errno == EINTR);
|
||||||
if (ret == -1)
|
if (ret == -1)
|
||||||
perror_with_name ("waiting for new child");
|
perror_with_name ("waiting for new child");
|
||||||
|
@ -423,8 +419,13 @@ linux_handle_extended_wait (int pid, int status,
|
||||||
"wait returned unexpected status 0x%x", status);
|
"wait returned unexpected status 0x%x", status);
|
||||||
}
|
}
|
||||||
|
|
||||||
ourstatus->kind = (event == PTRACE_EVENT_FORK)
|
if (event == PTRACE_EVENT_FORK)
|
||||||
? TARGET_WAITKIND_FORKED : TARGET_WAITKIND_VFORKED;
|
ourstatus->kind = TARGET_WAITKIND_FORKED;
|
||||||
|
else if (event == PTRACE_EVENT_VFORK)
|
||||||
|
ourstatus->kind = TARGET_WAITKIND_VFORKED;
|
||||||
|
else
|
||||||
|
ourstatus->kind = TARGET_WAITKIND_SPURIOUS;
|
||||||
|
|
||||||
ourstatus->value.related_pid = new_pid;
|
ourstatus->value.related_pid = new_pid;
|
||||||
return inferior_ptid;
|
return inferior_ptid;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,5 +1,5 @@
|
||||||
/* Native debugging support for GNU/Linux (LWP layer).
|
/* Native debugging support for GNU/Linux (LWP layer).
|
||||||
Copyright 2000, 2001, 2002, 2003 Free Software Foundation, Inc.
|
Copyright 2000, 2001, 2002, 2003, 2004 Free Software Foundation, Inc.
|
||||||
|
|
||||||
This file is part of GDB.
|
This file is part of GDB.
|
||||||
|
|
||||||
|
@ -18,6 +18,8 @@
|
||||||
Foundation, Inc., 59 Temple Place - Suite 330,
|
Foundation, Inc., 59 Temple Place - Suite 330,
|
||||||
Boston, MA 02111-1307, USA. */
|
Boston, MA 02111-1307, USA. */
|
||||||
|
|
||||||
|
#include "target.h"
|
||||||
|
|
||||||
/* Structure describing an LWP. */
|
/* Structure describing an LWP. */
|
||||||
|
|
||||||
struct lwp_info
|
struct lwp_info
|
||||||
|
@ -52,6 +54,11 @@ struct lwp_info
|
||||||
/* Non-zero if we were stepping this LWP. */
|
/* Non-zero if we were stepping this LWP. */
|
||||||
int step;
|
int step;
|
||||||
|
|
||||||
|
/* If WAITSTATUS->KIND != TARGET_WAITKIND_SPURIOUS, the waitstatus
|
||||||
|
for this LWP's last event. This may correspond to STATUS above,
|
||||||
|
or to a local variable in lin_lwp_wait. */
|
||||||
|
struct target_waitstatus waitstatus;
|
||||||
|
|
||||||
/* Next LWP in list. */
|
/* Next LWP in list. */
|
||||||
struct lwp_info *next;
|
struct lwp_info *next;
|
||||||
};
|
};
|
||||||
|
@ -60,7 +67,6 @@ struct lwp_info
|
||||||
system". */
|
system". */
|
||||||
struct mem_attrib;
|
struct mem_attrib;
|
||||||
struct target_ops;
|
struct target_ops;
|
||||||
struct target_waitstatus;
|
|
||||||
|
|
||||||
extern int linux_proc_xfer_memory (CORE_ADDR addr, char *myaddr, int len,
|
extern int linux_proc_xfer_memory (CORE_ADDR addr, char *myaddr, int len,
|
||||||
int write, struct mem_attrib *attrib,
|
int write, struct mem_attrib *attrib,
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
/* libthread_db assisted debugging support, generic parts.
|
/* libthread_db assisted debugging support, generic parts.
|
||||||
|
|
||||||
Copyright 1999, 2000, 2001, 2003 Free Software Foundation, Inc.
|
Copyright 1999, 2000, 2001, 2003, 2004 Free Software Foundation, Inc.
|
||||||
|
|
||||||
This file is part of GDB.
|
This file is part of GDB.
|
||||||
|
|
||||||
|
@ -35,6 +35,10 @@
|
||||||
#include "regcache.h"
|
#include "regcache.h"
|
||||||
#include "solib-svr4.h"
|
#include "solib-svr4.h"
|
||||||
|
|
||||||
|
#ifdef HAVE_GNU_LIBC_VERSION_H
|
||||||
|
#include <gnu/libc-version.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
#ifndef LIBTHREAD_DB_SO
|
#ifndef LIBTHREAD_DB_SO
|
||||||
#define LIBTHREAD_DB_SO "libthread_db.so.1"
|
#define LIBTHREAD_DB_SO "libthread_db.so.1"
|
||||||
#endif
|
#endif
|
||||||
|
@ -130,6 +134,7 @@ static CORE_ADDR td_death_bp_addr;
|
||||||
static void thread_db_find_new_threads (void);
|
static void thread_db_find_new_threads (void);
|
||||||
static void attach_thread (ptid_t ptid, const td_thrhandle_t *th_p,
|
static void attach_thread (ptid_t ptid, const td_thrhandle_t *th_p,
|
||||||
const td_thrinfo_t *ti_p, int verbose);
|
const td_thrinfo_t *ti_p, int verbose);
|
||||||
|
static void detach_thread (ptid_t ptid, int verbose);
|
||||||
|
|
||||||
|
|
||||||
/* Building process ids. */
|
/* Building process ids. */
|
||||||
|
@ -150,6 +155,9 @@ static void attach_thread (ptid_t ptid, const td_thrhandle_t *th_p,
|
||||||
|
|
||||||
struct private_thread_info
|
struct private_thread_info
|
||||||
{
|
{
|
||||||
|
/* Flag set when we see a TD_DEATH event for this thread. */
|
||||||
|
unsigned int dying:1;
|
||||||
|
|
||||||
/* Cached thread state. */
|
/* Cached thread state. */
|
||||||
unsigned int th_valid:1;
|
unsigned int th_valid:1;
|
||||||
unsigned int ti_valid:1;
|
unsigned int ti_valid:1;
|
||||||
|
@ -491,6 +499,10 @@ enable_thread_event_reporting (void)
|
||||||
td_thr_events_t events;
|
td_thr_events_t events;
|
||||||
td_notify_t notify;
|
td_notify_t notify;
|
||||||
td_err_e err;
|
td_err_e err;
|
||||||
|
#ifdef HAVE_GNU_LIBC_VERSION_H
|
||||||
|
const char *libc_version;
|
||||||
|
int libc_major, libc_minor;
|
||||||
|
#endif
|
||||||
|
|
||||||
/* We cannot use the thread event reporting facility if these
|
/* We cannot use the thread event reporting facility if these
|
||||||
functions aren't available. */
|
functions aren't available. */
|
||||||
|
@ -501,12 +513,16 @@ enable_thread_event_reporting (void)
|
||||||
/* Set the process wide mask saying which events we're interested in. */
|
/* Set the process wide mask saying which events we're interested in. */
|
||||||
td_event_emptyset (&events);
|
td_event_emptyset (&events);
|
||||||
td_event_addset (&events, TD_CREATE);
|
td_event_addset (&events, TD_CREATE);
|
||||||
#if 0
|
|
||||||
|
#ifdef HAVE_GNU_LIBC_VERSION_H
|
||||||
/* FIXME: kettenis/2000-04-23: The event reporting facility is
|
/* FIXME: kettenis/2000-04-23: The event reporting facility is
|
||||||
broken for TD_DEATH events in glibc 2.1.3, so don't enable it for
|
broken for TD_DEATH events in glibc 2.1.3, so don't enable it for
|
||||||
now. */
|
now. */
|
||||||
td_event_addset (&events, TD_DEATH);
|
libc_version = gnu_get_libc_version ();
|
||||||
|
if (sscanf (libc_version, "%d.%d", &libc_major, &libc_minor) == 2
|
||||||
|
&& (libc_major > 2 || (libc_major == 2 && libc_minor > 1)))
|
||||||
#endif
|
#endif
|
||||||
|
td_event_addset (&events, TD_DEATH);
|
||||||
|
|
||||||
err = td_ta_set_event_p (thread_agent, &events);
|
err = td_ta_set_event_p (thread_agent, &events);
|
||||||
if (err != TD_OK)
|
if (err != TD_OK)
|
||||||
|
@ -689,6 +705,10 @@ quit:
|
||||||
target_new_objfile_chain (objfile);
|
target_new_objfile_chain (objfile);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Attach to a new thread. This function is called when we receive a
|
||||||
|
TD_CREATE event or when we iterate over all threads and find one
|
||||||
|
that wasn't already in our list. */
|
||||||
|
|
||||||
static void
|
static void
|
||||||
attach_thread (ptid_t ptid, const td_thrhandle_t *th_p,
|
attach_thread (ptid_t ptid, const td_thrhandle_t *th_p,
|
||||||
const td_thrinfo_t *ti_p, int verbose)
|
const td_thrinfo_t *ti_p, int verbose)
|
||||||
|
@ -696,6 +716,27 @@ attach_thread (ptid_t ptid, const td_thrhandle_t *th_p,
|
||||||
struct thread_info *tp;
|
struct thread_info *tp;
|
||||||
td_err_e err;
|
td_err_e err;
|
||||||
|
|
||||||
|
/* If we're being called after a TD_CREATE event, we may already
|
||||||
|
know about this thread. There are two ways this can happen. We
|
||||||
|
may have iterated over all threads between the thread creation
|
||||||
|
and the TD_CREATE event, for instance when the user has issued
|
||||||
|
the `info threads' command before the SIGTRAP for hitting the
|
||||||
|
thread creation breakpoint was reported. Alternatively, the
|
||||||
|
thread may have exited and a new one been created with the same
|
||||||
|
thread ID. In the first case we don't need to do anything; in
|
||||||
|
the second case we should discard information about the dead
|
||||||
|
thread and attach to the new one. */
|
||||||
|
if (in_thread_list (ptid))
|
||||||
|
{
|
||||||
|
tp = find_thread_pid (ptid);
|
||||||
|
gdb_assert (tp != NULL);
|
||||||
|
|
||||||
|
if (!tp->private->dying)
|
||||||
|
return;
|
||||||
|
|
||||||
|
delete_thread (ptid);
|
||||||
|
}
|
||||||
|
|
||||||
check_thread_signals ();
|
check_thread_signals ();
|
||||||
|
|
||||||
/* Add the thread to GDB's thread list. */
|
/* Add the thread to GDB's thread list. */
|
||||||
|
@ -741,8 +782,21 @@ thread_db_attach (char *args, int from_tty)
|
||||||
static void
|
static void
|
||||||
detach_thread (ptid_t ptid, int verbose)
|
detach_thread (ptid_t ptid, int verbose)
|
||||||
{
|
{
|
||||||
|
struct thread_info *thread_info;
|
||||||
|
|
||||||
if (verbose)
|
if (verbose)
|
||||||
printf_unfiltered ("[%s exited]\n", target_pid_to_str (ptid));
|
printf_unfiltered ("[%s exited]\n", target_pid_to_str (ptid));
|
||||||
|
|
||||||
|
/* Don't delete the thread now, because it still reports as active
|
||||||
|
until it has executed a few instructions after the event
|
||||||
|
breakpoint - if we deleted it now, "info threads" would cause us
|
||||||
|
to re-attach to it. Just mark it as having had a TD_DEATH
|
||||||
|
event. This means that we won't delete it from our thread list
|
||||||
|
until we notice that it's dead (via prune_threads), or until
|
||||||
|
something re-uses its thread ID. */
|
||||||
|
thread_info = find_thread_pid (ptid);
|
||||||
|
gdb_assert (thread_info != NULL);
|
||||||
|
thread_info->private->dying = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
|
@ -847,11 +901,8 @@ check_event (ptid_t ptid)
|
||||||
switch (msg.event)
|
switch (msg.event)
|
||||||
{
|
{
|
||||||
case TD_CREATE:
|
case TD_CREATE:
|
||||||
|
/* Call attach_thread whether or not we already know about a
|
||||||
/* We may already know about this thread, for instance when the
|
thread with this thread ID. */
|
||||||
user has issued the `info threads' command before the SIGTRAP
|
|
||||||
for hitting the thread creation breakpoint was reported. */
|
|
||||||
if (!in_thread_list (ptid))
|
|
||||||
attach_thread (ptid, msg.th_p, &ti, 1);
|
attach_thread (ptid, msg.th_p, &ti, 1);
|
||||||
|
|
||||||
break;
|
break;
|
||||||
|
|
Loading…
Reference in New Issue