This is the mail archive of the
gdb-patches@sourceware.org
mailing list for the GDB project.
Fix gdbserver detach crash
- From: Pedro Alves <pedro at codesourcery dot com>
- To: gdb-patches at sourceware dot org
- Date: Mon, 28 Dec 2009 16:09:52 +0000
- Subject: Fix gdbserver detach crash
This gdbserver patch:
2009-12-28 Pedro Alves <pedro@codesourcery.com>
gdb/gdbserver/
* linux-low.c (linux_remove_process): Remove `detaching'
parameter. Don't release/detach from thread_db here.
(linux_kill): Release/detach from thread_db here, ...
(linux_detach): ... and here, before actually detaching.
(linux_wait_1): ... and here, when a process exits.
* thread-db.c (any_thread_of): New.
(thread_db_free): Switch the current inferior to a thread of the
passed in process.
fixes a gdbserver crash Joel reported on IRC:
<brobecke>: (Using the) pthread_cond_wait.c (test). To reproduce; connect gdb, break on break_me, cont, and then detach.
#0 0x0000000000408324 in look_up_one_symbol (
name=0x7f04271723a2 "__nptl_threads_events", addrp=0x7fff2faf8df8)
at /.amd/nas/homes/brobecke/act/gdb-public/gdb/gdbserver/remote-utils.c:1374
#1 0x000000000041a353 in ps_pglobal_lookup (ph=0x7fff2faf7ad0,
obj=0x7f0427172261 "libpthread.so.0",
name=0x7f04271723a2 "__nptl_threads_events", sym_addr=0x62fd00)
at /.amd/nas/homes/brobecke/act/gdb-public/gdb/gdbserver/proc-service.c:68
#2 0x00007f042717160d in td_ta_clear_event () from /lib/libthread_db.so.1
#3 0x000000000041a1dd in thread_db_free (proc=0x62f190, detaching=1)
at /.amd/nas/homes/brobecke/act/gdb-public/gdb/gdbserver/thread-db.c:785
#4 0x00000000004113b1 in linux_remove_process (process=0x62f190, detaching=1)
at /.amd/nas/homes/brobecke/act/gdb-public/gdb/gdbserver/linux-low.c:266
#5 0x000000000041234b in linux_detach (pid=32447)
at /.amd/nas/homes/brobecke/act/gdb-public/gdb/gdbserver/linux-low.c:829
linux_detach deletes all lwps and threads before calling linux_remove_process,
leaving the current_inferior global (and by consequence, the
current_process function) dangling. Note that look_up_one_symbol and
proc-service.c rely on the current process: I've added the missing
inferior switching to thread_db_free. I think all code paths ended up
with the right current inferior by accident, but (readability, maintainability,
and cleanliness wise) we better not rely on that when we have an
explicit `struct process *' parameter (in thread_db_free).
We should be detaching from thread_db before actually detaching from
all lwps, like gdb itself does. For kill/process exit, I just added
explicit thread_db_free calls, instead of introducing a target_mourn
concept.
Tested on x86_64-linux, native gdbserver. I'm applying it in a bit.
--
Pedro Alves
---
gdb/gdbserver/linux-low.c | 22 ++++++++++++++--------
gdb/gdbserver/thread-db.c | 20 ++++++++++++++++++++
2 files changed, 34 insertions(+), 8 deletions(-)
Index: src/gdb/gdbserver/linux-low.c
===================================================================
--- src.orig/gdb/gdbserver/linux-low.c 2009-12-28 14:18:23.000000000 +0000
+++ src/gdb/gdbserver/linux-low.c 2009-12-28 15:16:24.000000000 +0000
@@ -258,14 +258,10 @@ linux_add_process (int pid, int attached
also freeing all private data. */
static void
-linux_remove_process (struct process_info *process, int detaching)
+linux_remove_process (struct process_info *process)
{
struct process_info_private *priv = process->private;
-#ifdef USE_THREAD_DB
- thread_db_free (process, detaching);
-#endif
-
free (priv->arch_private);
free (priv);
remove_process (process);
@@ -736,8 +732,11 @@ linux_kill (int pid)
lwpid = linux_wait_for_event (lwp->head.id, &wstat, __WALL);
} while (lwpid > 0 && WIFSTOPPED (wstat));
+#ifdef USE_THREAD_DB
+ thread_db_free (process, 0);
+#endif
delete_lwp (lwp);
- linux_remove_process (process, 0);
+ linux_remove_process (process);
return 0;
}
@@ -821,12 +820,16 @@ linux_detach (int pid)
if (process == NULL)
return -1;
+#ifdef USE_THREAD_DB
+ thread_db_free (process, 1);
+#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);
- linux_remove_process (process, 1);
+ linux_remove_process (process);
return 0;
}
@@ -1451,8 +1454,11 @@ retry:
int pid = pid_of (lwp);
struct process_info *process = find_process_pid (pid);
+#ifdef USE_THREAD_DB
+ thread_db_free (process, 0);
+#endif
delete_lwp (lwp);
- linux_remove_process (process, 0);
+ linux_remove_process (process);
current_inferior = NULL;
Index: src/gdb/gdbserver/thread-db.c
===================================================================
--- src.orig/gdb/gdbserver/thread-db.c 2009-12-28 14:38:18.000000000 +0000
+++ src/gdb/gdbserver/thread-db.c 2009-12-28 15:18:17.000000000 +0000
@@ -755,6 +755,17 @@ thread_db_init (int use_events)
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;
+}
+
/* Disconnect from libthread_db and free resources. */
void
@@ -763,6 +774,8 @@ thread_db_free (struct process_info *pro
struct thread_db *thread_db = proc->private->thread_db;
if (thread_db)
{
+ struct thread_info *saved_inferior;
+ int pid;
td_err_e (*td_ta_delete_p) (td_thragent_t *);
td_err_e (*td_ta_clear_event_p) (const td_thragent_t *ta,
td_thr_events_t *event);
@@ -775,6 +788,12 @@ thread_db_free (struct process_info *pro
td_ta_clear_event_p = &td_ta_clear_event;
#endif
+ pid = pid_of (proc);
+ saved_inferior = current_inferior;
+ current_inferior =
+ (struct thread_info *) find_inferior (&all_threads,
+ any_thread_of, &pid);
+
if (detaching && td_ta_clear_event_p != NULL)
{
td_thr_events_t events;
@@ -794,6 +813,7 @@ thread_db_free (struct process_info *pro
free (thread_db);
proc->private->thread_db = NULL;
+ current_inferior = saved_inferior;
}
}