* linux-low.c (linux_kill_one_lwp): Assume the lwp is stopped.

(linux_kill): Stop all lwps here.  Don't delete the main lwp here.
	(linux_detach_one_lwp): Assume the lwp is stopped.
	(any_thread_of): Delete.
	(linux_detach): Stop all lwps here.  Don't blindly delete all
	breakpoints.
	(delete_lwp_callback): New.
	(linux_mourn): Delete all lwps of the process that is gone.
	(linux_wait_1): Don't delete the last lwp of the process here.
	* mem-break.h (mark_breakpoints_out): Declare.
	* mem-break.c (mark_breakpoints_out): New.
	(free_all_breakpoints): Use it.
	* server.c (handle_target_event): If the process is gone, mark
	breakpoints out.
	* thread-db.c (struct thread_db) <create_bp>: New field.
	(thread_db_enable_reporting): Fix prototype.  Store a thread event
	breakpoint reference in the thread_db struct.
	(thread_db_load_search): Clear the thread_db object.
	(try_thread_db_load_1): Ditto.
	(switch_to_process): New.
	(disable_thread_event_reporting): Use it.
	(remove_thread_event_breakpoints): New.
	(thread_db_detach, thread_db_mourn): Use it.
This commit is contained in:
Pedro Alves 2010-05-02 00:47:34 +00:00
parent 9dbc5bd275
commit f9e39928dc
6 changed files with 136 additions and 71 deletions

View File

@ -1,3 +1,29 @@
2010-05-02 Pedro Alves <pedro@codesourcery.com>
* linux-low.c (linux_kill_one_lwp): Assume the lwp is stopped.
(linux_kill): Stop all lwps here. Don't delete the main lwp here.
(linux_detach_one_lwp): Assume the lwp is stopped.
(any_thread_of): Delete.
(linux_detach): Stop all lwps here. Don't blindly delete all
breakpoints.
(delete_lwp_callback): New.
(linux_mourn): Delete all lwps of the process that is gone.
(linux_wait_1): Don't delete the last lwp of the process here.
* mem-break.h (mark_breakpoints_out): Declare.
* mem-break.c (mark_breakpoints_out): New.
(free_all_breakpoints): Use it.
* server.c (handle_target_event): If the process is gone, mark
breakpoints out.
* thread-db.c (struct thread_db) <create_bp>: New field.
(thread_db_enable_reporting): Fix prototype. Store a thread event
breakpoint reference in the thread_db struct.
(thread_db_load_search): Clear the thread_db object.
(try_thread_db_load_1): Ditto.
(switch_to_process): New.
(disable_thread_event_reporting): Use it.
(remove_thread_event_breakpoints): New.
(thread_db_detach, thread_db_mourn): Use it.
2010-05-01 Pedro Alves <pedro@codesourcery.com>
* linux-low.c (linux_enable_event_reporting): New.

View File

@ -739,11 +739,6 @@ linux_kill_one_lwp (struct inferior_list_entry *entry, void *args)
return 0;
}
/* If we're killing a running inferior, make sure it is stopped
first, as PTRACE_KILL will not work otherwise. */
if (!lwp->stopped)
send_sigstop (lwp);
do
{
ptrace (PTRACE_KILL, lwpid_of (lwp), 0, 0);
@ -768,6 +763,10 @@ linux_kill (int pid)
if (process == NULL)
return -1;
/* If we're killing a running inferior, make sure it is stopped
first, as PTRACE_KILL will not work otherwise. */
stop_all_lwps ();
find_inferior (&all_threads, linux_kill_one_lwp, &pid);
/* See the comment in linux_kill_one_lwp. We did not kill the first
@ -779,11 +778,6 @@ linux_kill (int pid)
fprintf (stderr, "lk_1: killing lwp %ld, for pid: %d\n",
lwpid_of (lwp), pid);
/* If we're killing a running inferior, make sure it is stopped
first, as PTRACE_KILL will not work otherwise. */
if (!lwp->stopped)
send_sigstop (lwp);
do
{
ptrace (PTRACE_KILL, lwpid_of (lwp), 0, 0);
@ -792,9 +786,11 @@ linux_kill (int pid)
lwpid = linux_wait_for_event (lwp->head.id, &wstat, __WALL);
} while (lwpid > 0 && WIFSTOPPED (wstat));
delete_lwp (lwp);
the_target->mourn (process);
/* Since we presently can only stop all lwps of all processes, we
need to unstop lwps of other processes. */
unstop_all_lwps (NULL);
return 0;
}
@ -808,28 +804,6 @@ linux_detach_one_lwp (struct inferior_list_entry *entry, void *args)
if (ptid_get_pid (entry->id) != pid)
return 0;
/* If we're detaching from a running inferior, make sure it is
stopped first, as PTRACE_DETACH will not work otherwise. */
if (!lwp->stopped)
{
int lwpid = lwpid_of (lwp);
stopping_threads = 1;
send_sigstop (lwp);
/* If this detects a new thread through a clone event, the new
thread is appended to the end of the lwp list, so we'll
eventually detach from it. */
wait_for_sigstop (&lwp->head);
stopping_threads = 0;
/* If LWP exits while we're trying to stop it, there's nothing
left to do. */
lwp = find_lwp_pid (pid_to_ptid (lwpid));
if (lwp == NULL)
return 0;
}
/* If this process is stopped but is expecting a SIGSTOP, then make
sure we take care of that now. This isn't absolutely guaranteed
to collect the SIGSTOP, but is fairly likely to. */
@ -838,8 +812,7 @@ linux_detach_one_lwp (struct inferior_list_entry *entry, void *args)
int wstat;
/* Clear stop_expected, so that the SIGSTOP will be reported. */
lwp->stop_expected = 0;
if (lwp->stopped)
linux_resume_one_lwp (lwp, 0, 0, NULL);
linux_resume_one_lwp (lwp, 0, 0, NULL);
linux_wait_for_event (lwp->head.id, &wstat, __WALL);
}
@ -854,17 +827,6 @@ linux_detach_one_lwp (struct inferior_list_entry *entry, void *args)
return 0;
}
static int
any_thread_of (struct inferior_list_entry *entry, void *args)
{
int *pid_p = args;
if (ptid_get_pid (entry->id) == *pid_p)
return 1;
return 0;
}
static int
linux_detach (int pid)
{
@ -874,17 +836,37 @@ linux_detach (int pid)
if (process == NULL)
return -1;
/* Stop all threads before detaching. First, ptrace requires that
the thread is stopped to sucessfully detach. Second, thread_db
may need to uninstall thread event breakpoints from memory, which
only works with a stopped process anyway. */
stop_all_lwps ();
#ifdef USE_THREAD_DB
thread_db_detach (process);
#endif
current_inferior =
(struct thread_info *) find_inferior (&all_threads, any_thread_of, &pid);
delete_all_breakpoints ();
find_inferior (&all_threads, linux_detach_one_lwp, &pid);
the_target->mourn (process);
/* Since we presently can only stop all lwps of all processes, we
need to unstop lwps of other processes. */
unstop_all_lwps (NULL);
return 0;
}
/* Remove all LWPs that belong to process PROC from the lwp list. */
static int
delete_lwp_callback (struct inferior_list_entry *entry, void *proc)
{
struct lwp_info *lwp = (struct lwp_info *) entry;
struct process_info *process = proc;
if (pid_of (lwp) == pid_of (process))
delete_lwp (lwp);
return 0;
}
@ -897,6 +879,8 @@ linux_mourn (struct process_info *process)
thread_db_mourn (process);
#endif
find_inferior (&all_lwps, delete_lwp_callback, process);
/* Freeing all private data. */
priv = process->private;
free (priv->arch_private);
@ -1695,10 +1679,6 @@ retry:
{
if (WIFEXITED (w) || WIFSIGNALED (w))
{
delete_lwp (event_child);
current_inferior = NULL;
if (WIFEXITED (w))
{
ourstatus->kind = TARGET_WAITKIND_EXITED;

View File

@ -716,16 +716,24 @@ delete_all_breakpoints (void)
delete_breakpoint_1 (proc, proc->breakpoints);
}
/* Clear the "inserted" flag in all breakpoints. */
void
mark_breakpoints_out (struct process_info *proc)
{
struct raw_breakpoint *raw_bp;
for (raw_bp = proc->raw_breakpoints; raw_bp != NULL; raw_bp = raw_bp->next)
raw_bp->inserted = 0;
}
/* Release all breakpoints, but do not try to un-insert them from the
inferior. */
void
free_all_breakpoints (struct process_info *proc)
{
struct raw_breakpoint *raw_bp;
for (raw_bp = proc->raw_breakpoints; raw_bp != NULL; raw_bp = raw_bp->next)
raw_bp->inserted = 0;
mark_breakpoints_out (proc);
/* Note: use PROC explicitly instead of deferring to
delete_all_breakpoints --- CURRENT_INFERIOR may already have been

View File

@ -103,6 +103,10 @@ void set_breakpoint_data (const unsigned char *bp_data, int bp_len);
void delete_all_breakpoints (void);
/* Clear the "inserted" flag in all breakpoints of PROC. */
void mark_breakpoints_out (struct process_info *proc);
/* Delete all breakpoints, but do not try to un-insert them from the
inferior. */

View File

@ -3031,7 +3031,10 @@ handle_target_event (int err, gdb_client_data client_data)
if (last_status.kind == TARGET_WAITKIND_EXITED
|| last_status.kind == TARGET_WAITKIND_SIGNALLED)
mourn_inferior (process);
{
mark_breakpoints_out (process);
mourn_inferior (process);
}
if (forward_event)
{

View File

@ -52,6 +52,16 @@ struct thread_db
void *handle;
#endif
/* Thread creation event breakpoint. The code at this location in
the child process will be called by the pthread library whenever
a new thread is created. By setting a special breakpoint at this
location, GDB can detect when a new thread is created. We obtain
this location via the td_ta_event_addr call. Note that if the
running kernel supports tracing clones, then we don't need to use
(and in fact don't use) this magic thread event breakpoint to
learn about threads. */
struct breakpoint *td_create_bp;
/* Addresses of libthread_db functions. */
td_err_e (*td_ta_new_p) (struct ps_prochandle * ps, td_thragent_t **ta);
td_err_e (*td_ta_event_getmsg_p) (const td_thragent_t *ta,
@ -205,7 +215,7 @@ thread_db_create_event (CORE_ADDR where)
}
static int
thread_db_enable_reporting ()
thread_db_enable_reporting (void)
{
td_thr_events_t events;
td_notify_t notify;
@ -239,8 +249,9 @@ thread_db_enable_reporting ()
thread_db_err_str (err));
return 0;
}
set_breakpoint_at ((CORE_ADDR) (unsigned long) notify.u.bptaddr,
thread_db_create_event);
thread_db->td_create_bp
= set_breakpoint_at ((CORE_ADDR) (unsigned long) notify.u.bptaddr,
thread_db_create_event);
return 1;
}
@ -501,6 +512,8 @@ thread_db_load_search (void)
if (proc->private->thread_db != NULL)
fatal ("unexpected: proc->private->thread_db != NULL");
memset (&tdb, 0, sizeof (tdb));
tdb.td_ta_new_p = &td_ta_new;
/* Attempt to open a connection to the thread library. */
@ -544,6 +557,8 @@ try_thread_db_load_1 (void *handle)
if (proc->private->thread_db != NULL)
fatal ("unexpected: proc->private->thread_db != NULL");
memset (&tdb, 0, sizeof (tdb));
tdb.handle = handle;
/* Initialize pointers to the dynamic library functions we will use.
@ -766,6 +781,16 @@ any_thread_of (struct inferior_list_entry *entry, void *args)
return 0;
}
static void
switch_to_process (struct process_info *proc)
{
int pid = pid_of (proc);
current_inferior =
(struct thread_info *) find_inferior (&all_threads,
any_thread_of, &pid);
}
/* Disconnect from libthread_db and free resources. */
static void
@ -785,15 +810,10 @@ disable_thread_event_reporting (struct process_info *proc)
if (td_ta_clear_event_p != NULL)
{
struct thread_info *saved_inferior;
struct thread_info *saved_inferior = current_inferior;
td_thr_events_t events;
int pid;
pid = pid_of (proc);
saved_inferior = current_inferior;
current_inferior =
(struct thread_info *) find_inferior (&all_threads,
any_thread_of, &pid);
switch_to_process (proc);
/* Set the process wide mask saying we aren't interested
in any events anymore. */
@ -805,10 +825,34 @@ disable_thread_event_reporting (struct process_info *proc)
}
}
static void
remove_thread_event_breakpoints (struct process_info *proc)
{
struct thread_db *thread_db = proc->private->thread_db;
if (thread_db->td_create_bp != NULL)
{
struct thread_info *saved_inferior = current_inferior;
switch_to_process (proc);
delete_breakpoint (thread_db->td_create_bp);
thread_db->td_create_bp = NULL;
current_inferior = saved_inferior;
}
}
void
thread_db_detach (struct process_info *proc)
{
disable_thread_event_reporting (proc);
struct thread_db *thread_db = proc->private->thread_db;
if (thread_db)
{
disable_thread_event_reporting (proc);
remove_thread_event_breakpoints (proc);
}
}
/* Disconnect from libthread_db and free resources. */