This is the mail archive of the gdb-patches@sourceware.org mailing list for the GDB project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[commit] gdbserver support for debugging without libthread_db


GDB and gdbserver both use libthread_db to get extra information from
the system libraries about threads.  For gdbserver especially, this
is occasionally troublesome: if the connected gdb can not find the
right copy of libpthread.so and ld.so, there's a good chance it won't
work at all.  The symptoms are no entries in "info threads" and your
program vanishing with an unexpected SIGTRAP the first time one of
your threads stumbles over code with a breakpoint in it.

This patch teaches gdbserver to work without libthread_db in some
cases.  If you have a 2.6 or later kernel, you can get away without
libthread_db as long as (A) you do not use --attach to connect to a
multi-threaded program, and (B) you do not try to print thread-local
variables.  It's good enough for minimal debugging and to figure out
what's wrong with your shared library debugging setup.

I've tested this on x86_64-linux and checked it in.  NEWS entry coming
up next.

-- 
Daniel Jacobowitz
CodeSourcery

2007-10-23  Daniel Jacobowitz  <dan@codesourcery.com>

	* inferiors.c (change_inferior_id): Delete.
	(add_pid_to_list, pull_pid_from_list): New.
	* linux-low.c (PTRACE_SETOPTIONS, PTRACE_GETEVENTMSG)
	(PTRACE_O_TRACESYSGOOD, PTRACE_O_TRACEFORK, PTRACE_O_TRACEVFORK)
	(PTRACE_O_TRACECLONE, PTRACE_O_TRACEEXEC, PTRACE_O_TRACEVFORKDONE)
	(PTRACE_O_TRACEEXIT, PTRACE_EVENT_FORK, PTRACE_EVENT_VFORK)
	(PTRACE_EVENT_CLONE, PTRACE_EVENT_EXEC, PTRACE_EVENT_VFORK_DONE)
	(PTRACE_EVENT_EXIT, __WALL): Provide default definitions.
	(stopped_pids, thread_db_active, must_set_ptrace_flags): New variables.
	(using_threads): Always set to 1.
	(handle_extended_wait): New.
	(add_process): Do not set TID.
	(linux_create_inferior): Set must_set_ptrace_flags.
	(linux_attach_lwp): Remove TID argument.  Do not check using_threads.
	Use PTRACE_SETOPTIONS.  Call new_thread_notify.  Update all callers.
	(linux_thread_alive): Rename TID argument to LWPID.
	(linux_wait_for_process): Handle unknown processes.  Do not use TID.
	(linux_wait_for_event): Do not use TID or check using_threads.  Update
	call to dead_thread_notify.  Call handle_extended_wait.
	(linux_create_inferior): Use PTRACE_SETOPTIONS.
	(send_sigstop): Delete sigstop_sent.
	(wait_for_sigstop): Avoid TID.
	(linux_supports_tracefork_flag, linux_tracefork_child, my_waitpid)
	(linux_test_for_tracefork): New.
	(linux_lookup_signals): Use thread_db_active and
	linux_supports_tracefork_flag.
	(initialize_low): Use thread_db_active and linux_test_for_tracefork.
	* linux-low.h (get_process_thread): Avoid TID.
	(struct process_ifo): Move thread_known and tid to the end.  Remove
	sigstop_sent.
	(linux_attach_lwp, thread_db_init): Update prototypes.
	* server.h (change_inferior_id): Delete prototype.
	(add_pid_to_list, pull_pid_from_list): New prototypes.
	* thread-db.c (thread_db_use_events): New.
	(find_first_thread): Rename to...
	(find_one_thread): ...this.  Update callers and messages.  Do not
	call fatal.  Check thread_db_use_events.  Do not call
	change_inferior_id or new_thread_notify.
	(maybe_attach_thread): Update.  Do not call new_thread_notify.
	(thread_db_init): Set thread_db_use_events.  Check use_events.
	* utils.c (fatal, warning): Correct message prefix.

Index: inferiors.c
===================================================================
RCS file: /cvs/src/src/gdb/gdbserver/inferiors.c,v
retrieving revision 1.12
diff -u -p -r1.12 inferiors.c
--- inferiors.c	23 Aug 2007 18:08:48 -0000	1.12
+++ inferiors.c	23 Oct 2007 19:55:57 -0000
@@ -65,21 +65,6 @@ for_each_inferior (struct inferior_list 
     }
 }
 
-/* When debugging a single-threaded program, the threads list (such as
-   it is) is indexed by PID.  When debugging a multi-threaded program,
-   we index by TID.  This ugly routine replaces the
-   first-debugged-thread's PID with its TID.  */
-
-void
-change_inferior_id (struct inferior_list *list,
-		    unsigned long new_id)
-{
-  if (list->head != list->tail)
-    error ("tried to change thread ID after multiple threads are created");
-
-  list->head->id = new_id;
-}
-
 void
 remove_inferior (struct inferior_list *list,
 		 struct inferior_list_entry *entry)
@@ -318,3 +303,32 @@ clear_inferiors (void)
   clear_list (&all_threads);
   clear_list (&all_dlls);
 }
+
+/* Two utility functions for a truly degenerate inferior_list: a simple
+   PID listing.  */
+
+void
+add_pid_to_list (struct inferior_list *list, unsigned long pid)
+{
+  struct inferior_list_entry *new_entry;
+
+  new_entry = malloc (sizeof (struct inferior_list_entry));
+  new_entry->id = pid;
+  add_inferior_to_list (list, new_entry);
+}
+
+int
+pull_pid_from_list (struct inferior_list *list, unsigned long pid)
+{
+  struct inferior_list_entry *new_entry;
+
+  new_entry = find_inferior_id (list, pid);
+  if (new_entry == NULL)
+    return 0;
+  else
+    {
+      remove_inferior (list, new_entry);
+      free (new_entry);
+      return 1;
+    }
+}
Index: linux-low.c
===================================================================
RCS file: /cvs/src/src/gdb/gdbserver/linux-low.c,v
retrieving revision 1.62
diff -u -p -r1.62 linux-low.c
--- linux-low.c	19 Sep 2007 14:41:50 -0000	1.62
+++ linux-low.c	23 Oct 2007 19:55:57 -0000
@@ -44,26 +44,67 @@
 #define O_LARGEFILE 0
 #endif
 
+/* If the system headers did not provide the constants, hard-code the normal
+   values.  */
+#ifndef PTRACE_EVENT_FORK
+
+#define PTRACE_SETOPTIONS	0x4200
+#define PTRACE_GETEVENTMSG	0x4201
+
+/* options set using PTRACE_SETOPTIONS */
+#define PTRACE_O_TRACESYSGOOD	0x00000001
+#define PTRACE_O_TRACEFORK	0x00000002
+#define PTRACE_O_TRACEVFORK	0x00000004
+#define PTRACE_O_TRACECLONE	0x00000008
+#define PTRACE_O_TRACEEXEC	0x00000010
+#define PTRACE_O_TRACEVFORKDONE	0x00000020
+#define PTRACE_O_TRACEEXIT	0x00000040
+
+/* Wait extended result codes for the above trace options.  */
+#define PTRACE_EVENT_FORK	1
+#define PTRACE_EVENT_VFORK	2
+#define PTRACE_EVENT_CLONE	3
+#define PTRACE_EVENT_EXEC	4
+#define PTRACE_EVENT_VFORK_DONE	5
+#define PTRACE_EVENT_EXIT	6
+
+#endif /* PTRACE_EVENT_FORK */
+
+/* We can't always assume that this flag is available, but all systems
+   with the ptrace event handlers also have __WALL, so it's safe to use
+   in some contexts.  */
+#ifndef __WALL
+#define __WALL          0x40000000 /* Wait for any child.  */
+#endif
+
 #ifdef __UCLIBC__
 #if !(defined(__UCLIBC_HAS_MMU__) || defined(__ARCH_HAS_MMU__))
 #define HAS_NOMMU
 #endif
 #endif
 
-/* ``all_threads'' is keyed by the LWP ID - it should be the thread ID instead,
-   however.  This requires changing the ID in place when we go from !using_threads
-   to using_threads, immediately.
+/* ``all_threads'' is keyed by the LWP ID, which we use as the GDB protocol
+   representation of the thread ID.
 
    ``all_processes'' is keyed by the process ID - which on Linux is (presently)
    the same as the LWP ID.  */
 
 struct inferior_list all_processes;
 
+/* A list of all unknown processes which receive stop signals.  Some other
+   process will presumably claim each of these as forked children
+   momentarily.  */
+
+struct inferior_list stopped_pids;
+
 /* FIXME this is a bit of a hack, and could be removed.  */
 int stopping_threads;
 
 /* FIXME make into a target method?  */
-int using_threads;
+int using_threads = 1;
+static int thread_db_active;
+
+static int must_set_ptrace_flags;
 
 static void linux_resume_one_process (struct inferior_list_entry *entry,
 				      int step, int signal, siginfo_t *info);
@@ -71,6 +112,7 @@ static void linux_resume (struct thread_
 static void stop_all_processes (void);
 static int linux_wait_for_event (struct thread_info *child);
 static int check_removed_breakpoint (struct process_info *event_child);
+static void *add_process (unsigned long pid);
 
 struct pending_signals
 {
@@ -91,6 +133,56 @@ static int use_regsets_p = 1;
 /* FIXME: Delete eventually.  */
 #define inferior_pid (pid_of (get_thread_process (current_inferior)))
 
+static void
+handle_extended_wait (struct process_info *event_child, int wstat)
+{
+  int event = wstat >> 16;
+  struct process_info *new_process;
+
+  if (event == PTRACE_EVENT_CLONE)
+    {
+      unsigned long new_pid;
+      int ret, status;
+
+      ptrace (PTRACE_GETEVENTMSG, inferior_pid, 0, &new_pid);
+
+      /* If we haven't already seen the new PID stop, wait for it now.  */
+      if (! pull_pid_from_list (&stopped_pids, new_pid))
+	{
+	  /* The new child has a pending SIGSTOP.  We can't affect it until it
+	     hits the SIGSTOP, but we're already attached.  */
+
+	  do {
+	    ret = waitpid (new_pid, &status, __WALL);
+	  } while (ret == -1 && errno == EINTR);
+
+	  if (ret == -1)
+	    perror_with_name ("waiting for new child");
+	  else if (ret != new_pid)
+	    warning ("wait returned unexpected PID %d", ret);
+	  else if (!WIFSTOPPED (status) || WSTOPSIG (status) != SIGSTOP)
+	    warning ("wait returned unexpected status 0x%x", status);
+	}
+
+      ptrace (PTRACE_SETOPTIONS, new_pid, 0, PTRACE_O_TRACECLONE);
+
+      new_process = (struct process_info *) add_process (new_pid);
+      add_thread (new_pid, new_process, new_pid);
+      new_thread_notify (thread_id_to_gdb_id (new_process->lwpid));
+
+      if (stopping_threads)
+	new_process->stopped = 1;
+      else
+	ptrace (PTRACE_CONT, new_pid, 0, 0);
+
+      /* Always resume the current thread.  If we are stopping
+	 threads, it will have a pending SIGSTOP; we may as well
+	 collect it now.  */
+      linux_resume_one_process (&event_child->head,
+				event_child->stepping, 0, NULL);
+    }
+}
+
 /* This function should only be called if the process got a SIGTRAP.
    The SIGTRAP could mean several things.
 
@@ -133,9 +225,6 @@ add_process (unsigned long pid)
   memset (process, 0, sizeof (*process));
 
   process->head.id = pid;
-
-  /* Default to tid == lwpid == pid.  */
-  process->tid = pid;
   process->lwpid = pid;
 
   add_inferior_to_list (&all_processes, &process->head);
@@ -180,6 +269,7 @@ linux_create_inferior (char *program, ch
 
   new_process = add_process (pid);
   add_thread (pid, new_process, pid);
+  must_set_ptrace_flags = 1;
 
   return pid;
 }
@@ -187,7 +277,7 @@ linux_create_inferior (char *program, ch
 /* Attach to an inferior process.  */
 
 void
-linux_attach_lwp (unsigned long pid, unsigned long tid)
+linux_attach_lwp (unsigned long pid)
 {
   struct process_info *new_process;
 
@@ -198,13 +288,16 @@ linux_attach_lwp (unsigned long pid, uns
       fflush (stderr);
 
       /* If we fail to attach to an LWP, just return.  */
-      if (!using_threads)
+      if (all_threads.head == NULL)
 	_exit (0177);
       return;
     }
 
+  ptrace (PTRACE_SETOPTIONS, pid, 0, PTRACE_O_TRACECLONE);
+
   new_process = (struct process_info *) add_process (pid);
-  add_thread (tid, new_process, pid);
+  add_thread (pid, new_process, pid);
+  new_thread_notify (thread_id_to_gdb_id (new_process->lwpid));
 
   /* The next time we wait for this LWP we'll see a SIGSTOP as PTRACE_ATTACH
      brings it to a halt.  We should ignore that SIGSTOP and resume the process
@@ -225,7 +318,7 @@ linux_attach (unsigned long pid)
 {
   struct process_info *process;
 
-  linux_attach_lwp (pid, pid);
+  linux_attach_lwp (pid);
 
   /* Don't ignore the initial SIGSTOP if we just attached to this process.
      It will be collected by wait shortly.  */
@@ -338,9 +431,9 @@ linux_join (void)
 
 /* Return nonzero if the given thread is still alive.  */
 static int
-linux_thread_alive (unsigned long tid)
+linux_thread_alive (unsigned long lwpid)
 {
-  if (find_inferior_id (&all_threads, tid) != NULL)
+  if (find_inferior_id (&all_threads, lwpid) != NULL)
     return 1;
   else
     return 0;
@@ -440,6 +533,7 @@ linux_wait_for_process (struct process_i
   if (*childp != NULL)
     to_wait_for = (*childp)->lwpid;
 
+retry:
   while (1)
     {
       ret = waitpid (to_wait_for, wstatp, WNOHANG);
@@ -474,6 +568,18 @@ linux_wait_for_process (struct process_i
   if (to_wait_for == -1)
     *childp = (struct process_info *) find_inferior_id (&all_processes, ret);
 
+  /* If we didn't find a process, one of two things presumably happened:
+     - A process we started and then detached from has exited.  Ignore it.
+     - A process we are controlling has forked and the new child's stop
+     was reported to us by the kernel.  Save its PID.  */
+  if (*childp == NULL && WIFSTOPPED (*wstatp))
+    {
+      add_pid_to_list (&stopped_pids, ret);
+      goto retry;
+    }
+  else if (*childp == NULL)
+    goto retry;
+
   (*childp)->stopped = 1;
   (*childp)->pending_is_breakpoint = 0;
 
@@ -483,7 +589,7 @@ linux_wait_for_process (struct process_i
       && WIFSTOPPED (*wstatp))
     {
       current_inferior = (struct thread_info *)
-	find_inferior_id (&all_threads, (*childp)->tid);
+	find_inferior_id (&all_threads, (*childp)->lwpid);
       /* For testing only; i386_stop_pc prints out a diagnostic.  */
       if (the_low_target.get_pc != NULL)
 	get_stop_pc ();
@@ -548,20 +654,19 @@ linux_wait_for_event (struct thread_info
 	error ("event from unknown child");
 
       current_inferior = (struct thread_info *)
-	find_inferior_id (&all_threads, event_child->tid);
+	find_inferior_id (&all_threads, event_child->lwpid);
 
       /* Check for thread exit.  */
-      if (using_threads && ! WIFSTOPPED (wstat))
+      if (! WIFSTOPPED (wstat))
 	{
 	  if (debug_threads)
-	    fprintf (stderr, "Thread %ld (LWP %ld) exiting\n",
-		     event_child->tid, event_child->head.id);
+	    fprintf (stderr, "LWP %ld exiting\n", event_child->head.id);
 
 	  /* If the last thread is exiting, just return.  */
 	  if (all_threads.head == all_threads.tail)
 	    return wstat;
 
-	  dead_thread_notify (event_child->tid);
+	  dead_thread_notify (thread_id_to_gdb_id (event_child->lwpid));
 
 	  remove_inferior (&all_processes, &event_child->head);
 	  free (event_child);
@@ -577,8 +682,7 @@ linux_wait_for_event (struct thread_info
 	  continue;
 	}
 
-      if (using_threads
-	  && WIFSTOPPED (wstat)
+      if (WIFSTOPPED (wstat)
 	  && WSTOPSIG (wstat) == SIGSTOP
 	  && event_child->stop_expected)
 	{
@@ -590,6 +694,13 @@ linux_wait_for_event (struct thread_info
 	  continue;
 	}
 
+      if (WIFSTOPPED (wstat) && WSTOPSIG (wstat) == SIGTRAP
+	  && wstat >> 16 != 0)
+	{
+	  handle_extended_wait (event_child, wstat);
+	  continue;
+	}
+
       /* If GDB is not interested in this signal, don't stop other
 	 threads, and don't report it to GDB.  Just resume the
 	 inferior right away.  We do this for threading-related
@@ -601,18 +712,20 @@ linux_wait_for_event (struct thread_info
 	 thread library?  */
       if (WIFSTOPPED (wstat)
 	  && !event_child->stepping
-	  && ((using_threads && (WSTOPSIG (wstat) == __SIGRTMIN
-				 || WSTOPSIG (wstat) == __SIGRTMIN + 1))
-	      || (pass_signals[target_signal_from_host (WSTOPSIG (wstat))]
-		  && (WSTOPSIG (wstat) != SIGSTOP
-		      || !event_child->sigstop_sent))))
+	  && (
+#ifdef USE_THREAD_DB
+	      (thread_db_active && (WSTOPSIG (wstat) == __SIGRTMIN
+				    || WSTOPSIG (wstat) == __SIGRTMIN + 1))
+	      ||
+#endif
+	      (pass_signals[target_signal_from_host (WSTOPSIG (wstat))]
+	       && (WSTOPSIG (wstat) != SIGSTOP || !stopping_threads))))
 	{
 	  siginfo_t info, *info_p;
 
 	  if (debug_threads)
-	    fprintf (stderr, "Ignored signal %d for %ld (LWP %ld).\n",
-		     WSTOPSIG (wstat), event_child->tid,
-		     event_child->head.id);
+	    fprintf (stderr, "Ignored signal %d for LWP %ld.\n",
+		     WSTOPSIG (wstat), event_child->head.id);
 
 	  if (ptrace (PTRACE_GETSIGINFO, event_child->lwpid, 0, &info) == 0)
 	    info_p = &info;
@@ -769,6 +882,12 @@ retry:
   stop_all_processes ();
   disable_async_io ();
 
+  if (must_set_ptrace_flags)
+    {
+      ptrace (PTRACE_SETOPTIONS, inferior_pid, 0, PTRACE_O_TRACECLONE);
+      must_set_ptrace_flags = 0;
+    }
+
   /* If we are waiting for a particular child, and it exited,
      linux_wait_for_event will return its exit status.  Similarly if
      the last child exited.  If this is not the last child, however,
@@ -863,7 +982,6 @@ send_sigstop (struct inferior_list_entry
     fprintf (stderr, "Sending sigstop to process %ld\n", process->head.id);
 
   kill_lwp (process->head.id, SIGSTOP);
-  process->sigstop_sent = 1;
 }
 
 static void
@@ -880,7 +998,7 @@ wait_for_sigstop (struct inferior_list_e
   saved_inferior = current_inferior;
   saved_tid = ((struct inferior_list_entry *) saved_inferior)->id;
   thread = (struct thread_info *) find_inferior_id (&all_threads,
-						    process->tid);
+						    process->lwpid);
   wstat = linux_wait_for_event (thread);
 
   /* If we stopped with a non-SIGSTOP signal, save it for later
@@ -890,9 +1008,8 @@ wait_for_sigstop (struct inferior_list_e
       && WSTOPSIG (wstat) != SIGSTOP)
     {
       if (debug_threads)
-	fprintf (stderr, "Process %ld (thread %ld) "
-		 "stopped with non-sigstop status %06x\n",
-		 process->lwpid, process->tid, wstat);
+	fprintf (stderr, "LWP %ld stopped with non-sigstop status %06x\n",
+		 process->lwpid, wstat);
       process->status_pending_p = 1;
       process->status_pending = wstat;
       process->stop_expected = 1;
@@ -1593,14 +1710,127 @@ linux_write_memory (CORE_ADDR memaddr, c
   return 0;
 }
 
+static int linux_supports_tracefork_flag;
+
+/* A helper function for linux_test_for_tracefork, called after fork ().  */
+
+static void
+linux_tracefork_child (void)
+{
+  ptrace (PTRACE_TRACEME, 0, 0, 0);
+  kill (getpid (), SIGSTOP);
+  fork ();
+  _exit (0);
+}
+
+/* Wrapper function for waitpid which handles EINTR.  */
+
+static int
+my_waitpid (int pid, int *status, int flags)
+{
+  int ret;
+  do
+    {
+      ret = waitpid (pid, status, flags);
+    }
+  while (ret == -1 && errno == EINTR);
+
+  return ret;
+}
+
+/* Determine if PTRACE_O_TRACEFORK can be used to follow fork events.  Make
+   sure that we can enable the option, and that it had the desired
+   effect.  */
+
+static void
+linux_test_for_tracefork (void)
+{
+  int child_pid, ret, status;
+  long second_pid;
+
+  linux_supports_tracefork_flag = 0;
+
+  child_pid = fork ();
+  if (child_pid == -1)
+    perror_with_name ("fork");
+
+  if (child_pid == 0)
+    linux_tracefork_child ();
+
+  ret = my_waitpid (child_pid, &status, 0);
+  if (ret == -1)
+    perror_with_name ("waitpid");
+  else if (ret != child_pid)
+    error ("linux_test_for_tracefork: waitpid: unexpected result %d.", ret);
+  if (! WIFSTOPPED (status))
+    error ("linux_test_for_tracefork: waitpid: unexpected status %d.", status);
+
+  ret = ptrace (PTRACE_SETOPTIONS, child_pid, 0, PTRACE_O_TRACEFORK);
+  if (ret != 0)
+    {
+      ret = ptrace (PTRACE_KILL, child_pid, 0, 0);
+      if (ret != 0)
+	{
+	  warning ("linux_test_for_tracefork: failed to kill child");
+	  return;
+	}
+
+      ret = my_waitpid (child_pid, &status, 0);
+      if (ret != child_pid)
+	warning ("linux_test_for_tracefork: failed to wait for killed child");
+      else if (!WIFSIGNALED (status))
+	warning ("linux_test_for_tracefork: unexpected wait status 0x%x from "
+		 "killed child", status);
+
+      return;
+    }
+
+  ret = ptrace (PTRACE_CONT, child_pid, 0, 0);
+  if (ret != 0)
+    warning ("linux_test_for_tracefork: failed to resume child");
+
+  ret = my_waitpid (child_pid, &status, 0);
+
+  if (ret == child_pid && WIFSTOPPED (status)
+      && status >> 16 == PTRACE_EVENT_FORK)
+    {
+      second_pid = 0;
+      ret = ptrace (PTRACE_GETEVENTMSG, child_pid, 0, &second_pid);
+      if (ret == 0 && second_pid != 0)
+	{
+	  int second_status;
+
+	  linux_supports_tracefork_flag = 1;
+	  my_waitpid (second_pid, &second_status, 0);
+	  ret = ptrace (PTRACE_KILL, second_pid, 0, 0);
+	  if (ret != 0)
+	    warning ("linux_test_for_tracefork: failed to kill second child");
+	  my_waitpid (second_pid, &status, 0);
+	}
+    }
+  else
+    warning ("linux_test_for_tracefork: unexpected result from waitpid "
+	     "(%d, status 0x%x)", ret, status);
+
+  do
+    {
+      ret = ptrace (PTRACE_KILL, child_pid, 0, 0);
+      if (ret != 0)
+	warning ("linux_test_for_tracefork: failed to kill child");
+      my_waitpid (child_pid, &status, 0);
+    }
+  while (WIFSTOPPED (status));
+}
+
+
 static void
 linux_look_up_symbols (void)
 {
 #ifdef USE_THREAD_DB
-  if (using_threads)
+  if (thread_db_active)
     return;
 
-  using_threads = thread_db_init ();
+  thread_db_active = thread_db_init (!linux_supports_tracefork_flag);
 #endif
 }
 
@@ -1782,10 +2012,11 @@ linux_init_signals ()
 void
 initialize_low (void)
 {
-  using_threads = 0;
+  thread_db_active = 0;
   set_target_ops (&linux_target_ops);
   set_breakpoint_data (the_low_target.breakpoint,
 		       the_low_target.breakpoint_len);
   init_registers ();
   linux_init_signals ();
+  linux_test_for_tracefork ();
 }
Index: linux-low.h
===================================================================
RCS file: /cvs/src/src/gdb/gdbserver/linux-low.h,v
retrieving revision 1.18
diff -u -p -r1.18 linux-low.h
--- linux-low.h	23 Aug 2007 18:08:48 -0000	1.18
+++ linux-low.h	23 Oct 2007 19:55:57 -0000
@@ -81,14 +81,12 @@ extern struct linux_target_ops the_low_t
 #define get_thread_process(thr) (get_process (inferior_target_data (thr)))
 #define get_process_thread(proc) ((struct thread_info *) \
 				  find_inferior_id (&all_threads, \
-				  get_process (proc)->tid))
+				  get_process (proc)->lwpid))
 
 struct process_info
 {
   struct inferior_list_entry head;
-  int thread_known;
   unsigned long lwpid;
-  unsigned long tid;
 
   /* If this flag is set, the next SIGSTOP will be ignored (the
      process will be immediately resumed).  This means that either we
@@ -105,10 +103,6 @@ struct process_info
   /* When stopped is set, the last wait status recorded for this process.  */
   int last_status;
 
-  /* If this flag is set, we have sent a SIGSTOP to this process and are
-     waiting for it to stop.  */
-  int sigstop_sent;
-
   /* If this flag is set, STATUS_PENDING is a waitstatus that has not yet
      been reported.  */
   int status_pending_p;
@@ -135,16 +129,19 @@ struct process_info
 
   struct thread_resume *resume;
 
+  int thread_known;
+  unsigned long tid;
 #ifdef HAVE_THREAD_DB_H
-  /* The thread handle, used for e.g. TLS access.  */
+  /* The thread handle, used for e.g. TLS access.  Only valid if
+     THREAD_KNOWN is set.  */
   td_thrhandle_t th;
 #endif
 };
 
 extern struct inferior_list all_processes;
 
-void linux_attach_lwp (unsigned long pid, unsigned long tid);
+void linux_attach_lwp (unsigned long pid);
 
-int thread_db_init (void);
+int thread_db_init (int use_events);
 int thread_db_get_tls_address (struct thread_info *thread, CORE_ADDR offset,
 			       CORE_ADDR load_module, CORE_ADDR *address);
Index: server.h
===================================================================
RCS file: /cvs/src/src/gdb/gdbserver/server.h,v
retrieving revision 1.35
diff -u -p -r1.35 server.h
--- server.h	23 Aug 2007 18:08:48 -0000	1.35
+++ server.h	23 Oct 2007 19:55:57 -0000
@@ -137,8 +137,8 @@ void *inferior_target_data (struct threa
 void set_inferior_target_data (struct thread_info *, void *);
 void *inferior_regcache_data (struct thread_info *);
 void set_inferior_regcache_data (struct thread_info *, void *);
-void change_inferior_id (struct inferior_list *list,
-			 unsigned long new_id);
+void add_pid_to_list (struct inferior_list *list, unsigned long pid);
+int pull_pid_from_list (struct inferior_list *list, unsigned long pid);
 
 void loaded_dll (const char *name, CORE_ADDR base_addr);
 void unloaded_dll (const char *name, CORE_ADDR base_addr);
Index: thread-db.c
===================================================================
RCS file: /cvs/src/src/gdb/gdbserver/thread-db.c,v
retrieving revision 1.12
diff -u -p -r1.12 thread-db.c
--- thread-db.c	23 Aug 2007 18:08:48 -0000	1.12
+++ thread-db.c	23 Oct 2007 19:55:57 -0000
@@ -24,6 +24,8 @@
 
 extern int debug_threads;
 
+static int thread_db_use_events;
+
 #ifdef HAVE_THREAD_DB_H
 #include <thread_db.h>
 #endif
@@ -39,7 +41,7 @@ static struct ps_prochandle proc_handle;
 /* Connection to the libthread_db library.  */
 static td_thragent_t *thread_agent;
 
-static int find_first_thread (void);
+static int find_one_thread (int);
 static int find_new_threads_callback (const td_thrhandle_t *th_p, void *data);
 
 static char *
@@ -152,7 +154,7 @@ thread_db_create_event (CORE_ADDR where)
      created threads.  */
   process = get_thread_process (current_inferior);
   if (process->thread_known == 0)
-    find_first_thread ();
+    find_one_thread (process->lwpid);
 
   /* msg.event == TD_EVENT_CREATE */
 
@@ -224,7 +226,7 @@ thread_db_enable_reporting ()
 }
 
 static int
-find_first_thread (void)
+find_one_thread (int lwpid)
 {
   td_thrhandle_t th;
   td_thrinfo_t ti;
@@ -232,54 +234,50 @@ find_first_thread (void)
   struct thread_info *inferior;
   struct process_info *process;
 
-  inferior = (struct thread_info *) all_threads.head;
+  inferior = (struct thread_info *) find_inferior_id (&all_threads, lwpid);
   process = get_thread_process (inferior);
   if (process->thread_known)
     return 1;
 
-  /* Get information about the one thread we know we have.  */
+  /* Get information about this thread.  */
   err = td_ta_map_lwp2thr (thread_agent, process->lwpid, &th);
   if (err != TD_OK)
-    error ("Cannot get first thread handle: %s", thread_db_err_str (err));
+    error ("Cannot get thread handle for LWP %d: %s",
+	   lwpid, thread_db_err_str (err));
 
   err = td_thr_get_info (&th, &ti);
   if (err != TD_OK)
-    error ("Cannot get first thread info: %s", thread_db_err_str (err));
+    error ("Cannot get thread info for LWP %d: %s",
+	   lwpid, thread_db_err_str (err));
 
   if (debug_threads)
-    fprintf (stderr, "Found first thread %ld (LWP %d)\n",
+    fprintf (stderr, "Found thread %ld (LWP %d)\n",
 	     ti.ti_tid, ti.ti_lid);
 
   if (process->lwpid != ti.ti_lid)
-    fatal ("PID mismatch!  Expected %ld, got %ld",
-	   (long) process->lwpid, (long) ti.ti_lid);
+    {
+      warning ("PID mismatch!  Expected %ld, got %ld",
+	       (long) process->lwpid, (long) ti.ti_lid);
+      return 0;
+    }
 
-  /* If the new thread ID is zero, a final thread ID will be available
-     later.  Do not enable thread debugging yet.  */
-  if (ti.ti_tid == 0)
+  if (thread_db_use_events)
     {
       err = td_thr_event_enable (&th, 1);
       if (err != TD_OK)
 	error ("Cannot enable thread event reporting for %d: %s",
 	       ti.ti_lid, thread_db_err_str (err));
-      return 0;
     }
 
-  /* Switch to indexing the threads list by TID.  */
-  change_inferior_id (&all_threads, ti.ti_tid);
-
-  new_thread_notify (ti.ti_tid);
+  /* If the new thread ID is zero, a final thread ID will be available
+     later.  Do not enable thread debugging yet.  */
+  if (ti.ti_tid == 0)
+    return 0;
 
-  process->tid = ti.ti_tid;
-  process->lwpid = ti.ti_lid;
   process->thread_known = 1;
+  process->tid = ti.ti_tid;
   process->th = th;
 
-  err = td_thr_event_enable (&th, 1);
-  if (err != TD_OK)
-    error ("Cannot enable thread event reporting for %d: %s",
-           ti.ti_lid, thread_db_err_str (err));
-
   return 1;
 }
 
@@ -291,16 +289,16 @@ maybe_attach_thread (const td_thrhandle_
   struct process_info *process;
 
   inferior = (struct thread_info *) find_inferior_id (&all_threads,
-						      ti_p->ti_tid);
+						      ti_p->ti_lid);
   if (inferior != NULL)
     return;
 
   if (debug_threads)
     fprintf (stderr, "Attaching to thread %ld (LWP %d)\n",
 	     ti_p->ti_tid, ti_p->ti_lid);
-  linux_attach_lwp (ti_p->ti_lid, ti_p->ti_tid);
+  linux_attach_lwp (ti_p->ti_lid);
   inferior = (struct thread_info *) find_inferior_id (&all_threads,
-						      ti_p->ti_tid);
+						      ti_p->ti_lid);
   if (inferior == NULL)
     {
       warning ("Could not attach to thread %ld (LWP %d)\n",
@@ -310,17 +308,17 @@ maybe_attach_thread (const td_thrhandle_
 
   process = inferior_target_data (inferior);
 
-  new_thread_notify (ti_p->ti_tid);
-
   process->tid = ti_p->ti_tid;
-  process->lwpid = ti_p->ti_lid;
-
   process->thread_known = 1;
   process->th = *th_p;
-  err = td_thr_event_enable (th_p, 1);
-  if (err != TD_OK)
-    error ("Cannot enable thread event reporting for %d: %s",
-           ti_p->ti_lid, thread_db_err_str (err));
+
+  if (thread_db_use_events)
+    {
+      err = td_thr_event_enable (th_p, 1);
+      if (err != TD_OK)
+	error ("Cannot enable thread event reporting for %d: %s",
+	       ti_p->ti_lid, thread_db_err_str (err));
+    }
 }
 
 static int
@@ -350,7 +348,7 @@ thread_db_find_new_threads (void)
   /* This function is only called when we first initialize thread_db.
      First locate the initial thread.  If it is not ready for
      debugging yet, then stop.  */
-  if (find_first_thread () == 0)
+  if (find_one_thread (all_threads.head->id) == 0)
     return;
 
   /* Iterate over all user-space threads to discover new threads.  */
@@ -387,7 +385,7 @@ thread_db_get_tls_address (struct thread
 
   process = get_thread_process (thread);
   if (!process->thread_known)
-    find_first_thread ();
+    find_one_thread (process->lwpid);
   if (!process->thread_known)
     return TD_NOTHR;
 
@@ -409,7 +407,7 @@ thread_db_get_tls_address (struct thread
 }
 
 int
-thread_db_init ()
+thread_db_init (int use_events)
 {
   int err;
 
@@ -428,6 +426,8 @@ thread_db_init ()
   /* Allow new symbol lookups.  */
   all_symbols_looked_up = 0;
 
+  thread_db_use_events = use_events;
+
   err = td_ta_new (&proc_handle, &thread_agent);
   switch (err)
     {
@@ -438,7 +438,7 @@ thread_db_init ()
     case TD_OK:
       /* The thread library was detected.  */
 
-      if (thread_db_enable_reporting () == 0)
+      if (use_events && thread_db_enable_reporting () == 0)
 	return 0;
       thread_db_find_new_threads ();
       thread_db_look_up_symbols ();
Index: utils.c
===================================================================
RCS file: /cvs/src/src/gdb/gdbserver/utils.c,v
retrieving revision 1.12
diff -u -p -r1.12 utils.c
--- utils.c	23 Aug 2007 18:08:48 -0000	1.12
+++ utils.c	23 Oct 2007 19:55:57 -0000
@@ -78,7 +78,7 @@ fatal (const char *string,...)
 {
   va_list args;
   va_start (args, string);
-  fprintf (stderr, "gdb: ");
+  fprintf (stderr, "gdbserver: ");
   vfprintf (stderr, string, args);
   fprintf (stderr, "\n");
   va_end (args);
@@ -91,7 +91,7 @@ warning (const char *string,...)
 {
   va_list args;
   va_start (args, string);
-  fprintf (stderr, "gdb: ");
+  fprintf (stderr, "gdbserver: ");
   vfprintf (stderr, string, args);
   fprintf (stderr, "\n");
   va_end (args);


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]