Implement attach/detach for multi-threaded programs on Linux.
* thread-db.c (keep_thread_db): Adjust comment. (deactivate_target): Removed. (thread_db_new_objfile): Don't call deactivate_target. Implement guts of deactivate_target inline instead. (attach_thread): Call ATTACH_LWP unconditionally if defined. (thread_db_attach): New function. (thread_db_detach): Don't call deactivate_target. Do necessary cleanup inline instead. Set inferior_ptid to LWP corresponding to the current user-level thread. (thread_db_kill): Set inferior_ptid to LWP corresponding to the current user-level thread. (thread_db_create_inferior): Deactivate target vector if KEEP_THREAD_DB is zero. (thread_db_mourn_inferior): Don't call deactivate_target. Do necessary cleanup inline instead. (init_thread_db_ops): Initialize to_attach field to thread_db_attach. * lin-lwp.c (lin_lwp_mourn_inferior): Remove prototype. (stop_wait_callback): Add prototype. (init_lwp_list): Add comment about when to re-initialize the LWP list. (lin_lwp_attach_lwp): Only call ptrace for cloned processes. Avoid adding publicates to the LWP list. Only mark an LWP as signalled if it doesn't correspond to a cloned process. (lin_lwp_attach): Add initial process to the LWP list. Make sure it's stopped and fake a SIGSTOP. (detach_callback): New function. (lin_lwp_detach): Implement. (lin_lwp_create_inferior): Don't re-initialize LWP list here. Call child_ops.to_create_inferior directly instead of via target_beneath local. (lin_lwp_mourn_inferior): Call child_ops.to_mourn_inferior directly instead of via target_beneath local.
This commit is contained in:
parent
d8708f403e
commit
c194fbe18b
3 changed files with 173 additions and 51 deletions
|
@ -1,3 +1,40 @@
|
|||
2001-05-06 Mark Kettenis <kettenis@gnu.org>
|
||||
|
||||
Implement attach/detach for multi-threaded programs on Linux.
|
||||
* thread-db.c (keep_thread_db): Adjust comment.
|
||||
(deactivate_target): Removed.
|
||||
(thread_db_new_objfile): Don't call deactivate_target. Implement
|
||||
guts of deactivate_target inline instead.
|
||||
(attach_thread): Call ATTACH_LWP unconditionally if defined.
|
||||
(thread_db_attach): New function.
|
||||
(thread_db_detach): Don't call deactivate_target. Do necessary
|
||||
cleanup inline instead. Set inferior_ptid to LWP corresponding to
|
||||
the current user-level thread.
|
||||
(thread_db_kill): Set inferior_ptid to LWP corresponding to the
|
||||
current user-level thread.
|
||||
(thread_db_create_inferior): Deactivate target vector if
|
||||
KEEP_THREAD_DB is zero.
|
||||
(thread_db_mourn_inferior): Don't call deactivate_target. Do
|
||||
necessary cleanup inline instead.
|
||||
(init_thread_db_ops): Initialize to_attach field to
|
||||
thread_db_attach.
|
||||
* lin-lwp.c (lin_lwp_mourn_inferior): Remove prototype.
|
||||
(stop_wait_callback): Add prototype.
|
||||
(init_lwp_list): Add comment about when to re-initialize the LWP
|
||||
list.
|
||||
(lin_lwp_attach_lwp): Only call ptrace for cloned processes.
|
||||
Avoid adding publicates to the LWP list. Only mark an LWP as
|
||||
signalled if it doesn't correspond to a cloned process.
|
||||
(lin_lwp_attach): Add initial process to the LWP list. Make sure
|
||||
it's stopped and fake a SIGSTOP.
|
||||
(detach_callback): New function.
|
||||
(lin_lwp_detach): Implement.
|
||||
(lin_lwp_create_inferior): Don't re-initialize LWP list here.
|
||||
Call child_ops.to_create_inferior directly instead of via
|
||||
target_beneath local.
|
||||
(lin_lwp_mourn_inferior): Call child_ops.to_mourn_inferior
|
||||
directly instead of via target_beneath local.
|
||||
|
||||
2001-05-06 Eli Zaretskii <eliz@is.elta.co.il>
|
||||
|
||||
* symtab.c (lookup_symtab_1, lookup_partial_symtab): Use basename
|
||||
|
|
114
gdb/lin-lwp.c
114
gdb/lin-lwp.c
|
@ -151,10 +151,13 @@ static sigset_t blocked_mask;
|
|||
|
||||
|
||||
/* Prototypes for local functions. */
|
||||
static void lin_lwp_mourn_inferior (void);
|
||||
static int stop_wait_callback (struct lwp_info *lp, void *data);
|
||||
|
||||
|
||||
/* Initialize the list of LWPs. */
|
||||
/* Initialize the list of LWPs. Note that this module, contrary to
|
||||
what GDB's generic threads layer does for its thread list,
|
||||
re-initializes the LWP lists whenever we mourn or detach (which
|
||||
doesn't involve mourning) the inferior. */
|
||||
|
||||
static void
|
||||
init_lwp_list (void)
|
||||
|
@ -344,26 +347,96 @@ lin_lwp_attach_lwp (ptid_t ptid, int verbose)
|
|||
if (verbose)
|
||||
printf_filtered ("[New %s]\n", target_pid_to_str (ptid));
|
||||
|
||||
if (ptrace (PTRACE_ATTACH, GET_LWP (ptid), 0, 0) < 0)
|
||||
/* We assume that we're already tracing the initial process. */
|
||||
if (is_cloned (ptid) && ptrace (PTRACE_ATTACH, GET_LWP (ptid), 0, 0) < 0)
|
||||
error ("Can't attach %s: %s", target_pid_to_str (ptid), strerror (errno));
|
||||
|
||||
lp = add_lwp (ptid);
|
||||
lp->signalled = 1;
|
||||
lp = find_lwp_pid (ptid);
|
||||
if (lp == NULL)
|
||||
lp = add_lwp (ptid);
|
||||
|
||||
if (is_cloned (ptid))
|
||||
lp->signalled = 1;
|
||||
}
|
||||
|
||||
static void
|
||||
lin_lwp_attach (char *args, int from_tty)
|
||||
{
|
||||
struct lwp_info *lp;
|
||||
|
||||
/* FIXME: We should probably accept a list of process id's, and
|
||||
attach all of them. */
|
||||
error("Not implemented yet");
|
||||
child_ops.to_attach (args, from_tty);
|
||||
|
||||
/* Add the initial process as the first LWP to the list. */
|
||||
lp = add_lwp (BUILD_LWP (inferior_ptid, inferior_ptid));
|
||||
|
||||
/* Make sure the initial process is stopped. The user-level threads
|
||||
layer might want to poke around in the inferior, and that won't
|
||||
work if things haven't stabilized yet. */
|
||||
lp->signalled = 1;
|
||||
stop_wait_callback (lp, NULL);
|
||||
gdb_assert (lp->status == 0);
|
||||
|
||||
/* Fake the SIGSTOP that core GDB expects. */
|
||||
lp->status = W_STOPCODE (SIGSTOP);
|
||||
}
|
||||
|
||||
static int
|
||||
detach_callback (struct lwp_info *lp, void *data)
|
||||
{
|
||||
gdb_assert (lp->status == 0 || WIFSTOPPED (lp->status));
|
||||
|
||||
if (debug_lin_lwp && lp->status)
|
||||
fprintf_unfiltered (gdb_stdlog, "Pending %s for LWP %d on detach.\n",
|
||||
strsignal (WSTOPSIG (lp->status)), GET_LWP (lp->ptid));
|
||||
|
||||
while (lp->signalled && lp->stopped)
|
||||
{
|
||||
if (ptrace (PTRACE_CONT, GET_LWP (lp->ptid), 0,
|
||||
WSTOPSIG (lp->status)) < 0)
|
||||
error ("Can't continue %s: %s", target_pid_to_str (lp->ptid),
|
||||
strerror (errno));
|
||||
|
||||
lp->stopped = 0;
|
||||
lp->status = 0;
|
||||
stop_wait_callback (lp, NULL);
|
||||
|
||||
gdb_assert (lp->status == 0 || WIFSTOPPED (lp->status));
|
||||
}
|
||||
|
||||
if (is_cloned (lp->ptid))
|
||||
{
|
||||
if (ptrace (PTRACE_DETACH, GET_LWP (lp->ptid), 0,
|
||||
WSTOPSIG (lp->status)) < 0)
|
||||
error ("Can't detach %s: %s", target_pid_to_str (lp->ptid),
|
||||
strerror (errno));
|
||||
|
||||
delete_lwp (lp->ptid);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void
|
||||
lin_lwp_detach (char *args, int from_tty)
|
||||
{
|
||||
/* FIXME: Provide implementation when we implement lin_lwp_attach. */
|
||||
error ("Not implemented yet");
|
||||
iterate_over_lwps (detach_callback, NULL);
|
||||
|
||||
/* Only the initial (uncloned) process should be left right now. */
|
||||
gdb_assert (num_lwps == 1);
|
||||
|
||||
trap_ptid = null_ptid;
|
||||
|
||||
/* Destroy LWP info; it's no longer valid. */
|
||||
init_lwp_list ();
|
||||
|
||||
/* Restore the original signal mask. */
|
||||
sigprocmask (SIG_SETMASK, &normal_mask, NULL);
|
||||
sigemptyset (&blocked_mask);
|
||||
|
||||
inferior_ptid = GET_PID (inferior_ptid);
|
||||
child_ops.to_detach (args, from_tty);
|
||||
}
|
||||
|
||||
|
||||
|
@ -899,37 +972,22 @@ lin_lwp_kill (void)
|
|||
static void
|
||||
lin_lwp_create_inferior (char *exec_file, char *allargs, char **env)
|
||||
{
|
||||
struct target_ops *target_beneath;
|
||||
|
||||
init_lwp_list ();
|
||||
|
||||
#if 0
|
||||
target_beneath = find_target_beneath (&lin_lwp_ops);
|
||||
#else
|
||||
target_beneath = &child_ops;
|
||||
#endif
|
||||
target_beneath->to_create_inferior (exec_file, allargs, env);
|
||||
child_ops.to_create_inferior (exec_file, allargs, env);
|
||||
}
|
||||
|
||||
static void
|
||||
lin_lwp_mourn_inferior (void)
|
||||
{
|
||||
struct target_ops *target_beneath;
|
||||
|
||||
init_lwp_list ();
|
||||
|
||||
trap_ptid = null_ptid;
|
||||
|
||||
/* Destroy LWP info; it's no longer valid. */
|
||||
init_lwp_list ();
|
||||
|
||||
/* Restore the original signal mask. */
|
||||
sigprocmask (SIG_SETMASK, &normal_mask, NULL);
|
||||
sigemptyset (&blocked_mask);
|
||||
|
||||
#if 0
|
||||
target_beneath = find_target_beneath (&lin_lwp_ops);
|
||||
#else
|
||||
target_beneath = &child_ops;
|
||||
#endif
|
||||
target_beneath->to_mourn_inferior ();
|
||||
child_ops.to_mourn_inferior ();
|
||||
}
|
||||
|
||||
static void
|
||||
|
|
|
@ -56,7 +56,8 @@ static void (*target_new_objfile_chain) (struct objfile *objfile);
|
|||
/* Non-zero if we're using this module's target vector. */
|
||||
static int using_thread_db;
|
||||
|
||||
/* Non-zero if we musn't deactivate this module's target vector. */
|
||||
/* Non-zero if we have to keep this module's target vector active
|
||||
across re-runs. */
|
||||
static int keep_thread_db;
|
||||
|
||||
/* Non-zero if we have determined the signals used by the threads
|
||||
|
@ -506,20 +507,6 @@ disable_thread_signals (void)
|
|||
#endif
|
||||
}
|
||||
|
||||
static void
|
||||
deactivate_target (void)
|
||||
{
|
||||
/* Forget about the child's process ID. We shouldn't need it
|
||||
anymore. */
|
||||
proc_handle.pid = 0;
|
||||
|
||||
if (! keep_thread_db)
|
||||
{
|
||||
using_thread_db = 0;
|
||||
unpush_target (&thread_db_ops);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
thread_db_new_objfile (struct objfile *objfile)
|
||||
{
|
||||
|
@ -528,11 +515,15 @@ thread_db_new_objfile (struct objfile *objfile)
|
|||
if (objfile == NULL)
|
||||
{
|
||||
/* All symbols have been discarded. If the thread_db target is
|
||||
active, deactivate it now, even if the application was linked
|
||||
statically against the thread library. */
|
||||
keep_thread_db = 0;
|
||||
active, deactivate it now. */
|
||||
if (using_thread_db)
|
||||
deactivate_target ();
|
||||
{
|
||||
gdb_assert (proc_handle.pid == 0);
|
||||
unpush_target (&thread_db_ops);
|
||||
using_thread_db = 0;
|
||||
}
|
||||
|
||||
keep_thread_db = 0;
|
||||
|
||||
goto quit;
|
||||
}
|
||||
|
@ -612,8 +603,7 @@ attach_thread (ptid_t ptid, const td_thrhandle_t *th_p,
|
|||
|
||||
/* Under Linux, we have to attach to each and every thread. */
|
||||
#ifdef ATTACH_LWP
|
||||
if (ti_p->ti_lid != GET_PID (ptid))
|
||||
ATTACH_LWP (BUILD_LWP (ti_p->ti_lid, GET_PID (ptid)), 0);
|
||||
ATTACH_LWP (BUILD_LWP (ti_p->ti_lid, GET_PID (ptid)), 0);
|
||||
#endif
|
||||
|
||||
/* Enable thread event reporting for this thread. */
|
||||
|
@ -623,6 +613,23 @@ attach_thread (ptid_t ptid, const td_thrhandle_t *th_p,
|
|||
target_pid_to_str (ptid), thread_db_err_str (err));
|
||||
}
|
||||
|
||||
static void
|
||||
thread_db_attach (char *args, int from_tty)
|
||||
{
|
||||
target_beneath->to_attach (args, from_tty);
|
||||
|
||||
/* Destroy thread info; it's no longer valid. */
|
||||
init_thread_list ();
|
||||
|
||||
/* The child process is now the actual multi-threaded
|
||||
program. Snatch its process ID... */
|
||||
proc_handle.pid = GET_PID (inferior_ptid);
|
||||
|
||||
/* ...and perform the remaining initialization steps. */
|
||||
enable_thread_event_reporting ();
|
||||
thread_db_find_new_threads();
|
||||
}
|
||||
|
||||
static void
|
||||
detach_thread (ptid_t ptid, int verbose)
|
||||
{
|
||||
|
@ -634,7 +641,14 @@ static void
|
|||
thread_db_detach (char *args, int from_tty)
|
||||
{
|
||||
disable_thread_event_reporting ();
|
||||
deactivate_target ();
|
||||
|
||||
/* There's no need to save & restore inferior_ptid here, since the
|
||||
inferior is supposed to be survive this function call. */
|
||||
inferior_ptid = lwp_from_thread (inferior_ptid);
|
||||
|
||||
/* Forget about the child's process ID. We shouldn't need it
|
||||
anymore. */
|
||||
proc_handle.pid = 0;
|
||||
|
||||
target_beneath->to_detach (args, from_tty);
|
||||
}
|
||||
|
@ -860,12 +874,21 @@ thread_db_store_registers (int regno)
|
|||
static void
|
||||
thread_db_kill (void)
|
||||
{
|
||||
/* There's no need to save & restore inferior_ptid here, since the
|
||||
inferior isn't supposed to survive this function call. */
|
||||
inferior_ptid = lwp_from_thread (inferior_ptid);
|
||||
target_beneath->to_kill ();
|
||||
}
|
||||
|
||||
static void
|
||||
thread_db_create_inferior (char *exec_file, char *allargs, char **env)
|
||||
{
|
||||
if (! keep_thread_db)
|
||||
{
|
||||
unpush_target (&thread_db_ops);
|
||||
using_thread_db = 0;
|
||||
}
|
||||
|
||||
target_beneath->to_create_inferior (exec_file, allargs, env);
|
||||
}
|
||||
|
||||
|
@ -888,7 +911,10 @@ static void
|
|||
thread_db_mourn_inferior (void)
|
||||
{
|
||||
remove_thread_event_breakpoints ();
|
||||
deactivate_target ();
|
||||
|
||||
/* Forget about the child's process ID. We shouldn't need it
|
||||
anymore. */
|
||||
proc_handle.pid = 0;
|
||||
|
||||
target_beneath->to_mourn_inferior ();
|
||||
}
|
||||
|
@ -996,6 +1022,7 @@ init_thread_db_ops (void)
|
|||
thread_db_ops.to_shortname = "multi-thread";
|
||||
thread_db_ops.to_longname = "multi-threaded child process.";
|
||||
thread_db_ops.to_doc = "Threads and pthreads support.";
|
||||
thread_db_ops.to_attach = thread_db_attach;
|
||||
thread_db_ops.to_detach = thread_db_detach;
|
||||
thread_db_ops.to_resume = thread_db_resume;
|
||||
thread_db_ops.to_wait = thread_db_wait;
|
||||
|
|
Loading…
Reference in a new issue