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]

[gdbserver/RFC/RFA] Implement multiprocess extensions, add linux multiproces support.


Hi,

This patch adds multiprocess support to gdbserver.

 - implements the remote protocol multiprocess extensions.
 - borrows ptid_t from GDB.
 - adds multiprocess support to the linux target
 - adds a `struct process_info' structure to represent a process.  Adds a per-process
   target specific data mechanism (process->private).  Moves per-process data to
   process_info or to the private data.  This actually fixes a couple of current
   bugs in --multi/extended mode, where we don't clear the symbol cache or
   thread_db_active correctly across runs.
 - adjusts the other targets so they keep working, but does not attempt to add
   multiprocess support to them (windows, spu).

This applies on top of the non-stop mode support patches.

Tested on x86_64-linux-gnu without regressions.  With a couple of small patches
to GDB, I can debug multiple linux processes with a simple gdbserver, as long
as they all use the same process image/executable.  Support for multi-exec to
GDB will have to be added so we can debug multiple executables, but, I don't
except any major change to gdbserver to support that.

I've just managed to finish testing windows gdbserver with the non-stop support
on (no regressions, yay!), I'm going test this patch there next.  In any case, 
windows changes are only mechanical changes to adjust to new interfaces.  I've
also adjust the spu target, but as before, I've no way to test it.  Hope I haven't
borked it much.

-- 
Pedro Alves

2009-03-30  Pedro Alves  <pedro@codesourcery.com>

	Implement the multiprocess extensions, and add linux multiprocess
	support.

	* server.h (ULONGEST): Declare.
	(struct ptid, ptid_t): New.
	(minus_one_ptid, null_ptid): Declare.
	(ptid_build, pid_to_ptid, ptid_get_pid, ptid_get_lwp)
	(ptid_get_tid, ptid_equal, ptid_is_pid): Declare.
	(struct inferior_list_entry): Change `id' type from unsigned from
	to ptid_t.
	(struct sym_cache, struct breakpoint, struct
	process_info_private): Forward declare.
	(struct process_info): Declare.
	(current_process): Declare.
	(all_processes): Declare.
	(initialize_inferiors): Declare.
	(add_thread): Adjust to use ptid_t.
	(thread_id_to_gdb_id, thread_to_gdb_id, gdb_id_to_thread_id): Ditto.
	(add_process, remove_process, find_thread_pid): Declare.
	(find_inferior_id): Adjust to use ptid_t.
	(cont_thread, general_thread, step_thread): Change type to ptid_t.
	(multi_process): Declare.
	(push_event): Adjust to use ptid_t.
	(read_ptid, write_ptid): Declare.
	(prepare_resume_reply): Adjust to use ptid_t.
	(clear_symbol_cache): Declare.
	* inferiors.c (all_processes): New.
	(null_ptid, minus_one_ptid): New.
	(ptid_build, pid_to_ptid, ptid_get_pid, ptid_get_lwp)
	(ptid_get_tid, ptid_equal, ptid_is_pid): New.
	(add_thread): Change unsigned long to ptid.  Remove gdb_id
	parameter.  Adjust.
	(thread_id_to_gdb_id, thread_to_gdb_id): Change unsigned long to ptid.
	(gdb_id_to_thread): Rename to ...
	(find_thread_pid): ... this.  Change unsigned long to ptid.
	(gdb_id_to_thread_id, find_inferior_id): Change unsigned long to ptid.
	(loaded_dll, pull_pid_from_list): Adjust.
	(add_process, remove_process, find_process_pid)
	(get_thread_process, current_process, initialize_inferiors): New.
	* target.h (struct thread_resume) <thread>: Change type to ptid_t.
	(struct target_waitstatus) <related_pid>: Ditto.
	(struct target_ops) <kill, detach>: Add `pid' argument.  Change
	return type to int.
	(struct target_ops) <join>: Add `pid' argument.
	(struct target_ops) <thread_alive>: Change pid's type to ptid_t.
	(struct target_ops) <wait>: Add `ptid' field.  Change return type
	to ptid.
	(kill_inferior, detach_inferior, join_inferior): Add `pid' argument.
	(mywait): Add `ptid' argument.  Change return type to ptid_t.
	(target_pid_to_str): Declare.
	* target.c (set_desired_inferior): Adjust to use ptids.
	(mywait): Add new `ptid' argument.  Adjust.
	(target_pid_to_str): New.
	* mem-break.h (free_all_breakpoints): Declare.
	* mem-break.c (breakpoints): Delelete.
	(set_breakpoint_at, delete_breakpoint, find_breakpoint_at)
	(check_mem_read, check_mem_write, delete_all_breakpoints): Adjust
	to use per-process breakpoint list.
	(free_all_breakpoints): New.
	* proc-service.c (ps_lgetregs): Use find_lwp_pid.
	(ps_getpid): Return the pid of the current inferior.
	* remote-utils.c (struct sym_cache) <name>: Drop `const'.
	(symbol_cache, all_symbols_looked_up): Delete.
	(hexchars): New.
	(ishex, unpack_varlen_hex, write_ptid, hex_or_minus_one,
	read_ptid): New.
	(prepare_resume_reply): Change ptid argument's type from unsigned
	long to ptid_t.  Adjust.  Implement W;process and X;process.
	(free_sym_cache, clear_symbol_cache): New.
	(look_up_one_symbol): Adjust to per-process symbol cache.  *
	server.c (cont_thread, general_thread, step_thread): Change type
	to ptid_t.
	(attached): Delete.
	(multi_process): New.
	(last_ptid): Change type to ptid_t.
	(struct vstop_notif) <ptid>: Change type to ptid_t.
	(queue_stop_reply, push_event): Change `ptid' argument's type to
	ptid_t.
	(discard_queued_stop_replies): Add `pid' argument.
	(start_inferior): Adjust to use ptids.  Adjust to mywait interface
	changes.  Don't reference the `attached' global.
	(attach_inferior): Adjust to mywait interface changes.
	(handle_query): Adjust to use ptids.  Parse GDB's qSupported
	features.  Handle and report "multiprocess+".  Handle
	"qAttached:PID".
	(handle_v_cont): Adjust to use ptids.  Adjust to mywait interface
	changes.
	(handle_v_kill): New.
	(handle_v_stopped): Adjust to use target_pid_to_str.
	(handle_v_requests): Allow multiple attaches and runs when
	multiprocess extensions are in effect.  Handle "vKill".
	(myresume): Adjust to use ptids.
	(queue_stop_reply_callback): Add `arg' parameter.  Handle it.
	(handle_status): Adjust to discard_queued_stop_replies interface
	change.
	(first_thread_of, kill_inferior_callback)
	(detach_or_kill_inferior_callback, join_inferiors_callback): New.
	(main): Call initialize_inferiors.  Adjust to use ptids, killing
	and detaching from all inferiors.  Handle multiprocess packet
	variants.
	* linux-low.h: Include gdb_proc_service.h.
	(struct process_info_private): New.
	(struct linux_target_ops) <pid_of>: Use ptid_get_pid.
	<lwpid_of>: Use ptid_get_lwp.
	(get_lwp_thread): Adjust.
	(struct lwp_info): Add `dead' member.
	(find_lwp_pid): Declare.
	* linux-low.c (thread_db_active): Delete.
	(new_inferior): Adjust comment.
	(inferior_pid): Delete.
	(linux_add_process): New.
	(handle_extended_wait): Adjust.
	(add_lwp): Change unsigned long to ptid.
	(linux_create_inferior): Add process to processes table.  Adjust
	to use ptids.  Don't set new_inferior here.
	(linux_attach_lwp): Rename to ...
	(linux_attach_lwp_1): ... this.  Add `initial' argument.  Handle
	it.  Adjust to use ptids.
	(linux_attach_lwp): New.
	(linux_attach): Add process to processes table.  Don't set
	new_inferior here.
	(struct counter): New.
	(second_thread_of_pid_p, last_thread_of_process_p): New.
	(linux_kill_one_lwp): Add `args' parameter.  Handle it.  Adjust to
	multiple processes.
	(linux_kill): Add `pid' argument.  Handle it.  Adjust to multiple
	processes.  Remove process from process table.
	(linux_detach_one_lwp): Add `args' parameter.  Handle it.  Adjust
	to multiple processes.
	(any_thread_of): New.
	(linux_detach): Add `pid' argument, and handle it.  Remove process
	from processes table.
	(linux_join): Add `pid' argument.  Handle it.
	(linux_thread_alive): Change unsighed long argument to ptid_t.
	Consider dead lwps as not being alive.
	(status_pending_p): Rename `dummy' argument to `arg'.  Filter out
	threads we're not interested in.
	(same_lwp, find_lwp_pid): New.
	(linux_wait_for_lwp): Change `pid' argument's type from int to
	ptid_t.  Adjust.
	(linux_wait_for_event): Rename to ...
	(linux_wait_for_event_1): ... this.  Change `pid' argument's type
	from int to ptid_t.  Adjust.
	(linux_wait_for_event): New.
	(linux_wait_1): Add `ptid' argument.  Change return type to
	ptid_t.  Adjust.  Use last_thread_of_process_p.  Remove processes
	that exit from the process table.
	(linux_wait): Add `ptid' argument.  Change return type to ptid_t.
	Adjust.
	(mark_lwp_dead): New.
	(wait_for_sigstop): Adjust to use ptids.  If a process exits while
	stopping all threads, mark its main lwp as dead.
	(linux_set_resume_request, linux_resume_one_thread): Adjust to use
	ptids.
	(fetch_register, usr_store_inferior_registers)
	(regsets_fetch_inferior_registers)
	(regsets_store_inferior_registers, linux_read_memory)
	(linux_write_memory): Inline `inferior_pid'.
	(linux_look_up_symbols): Adjust to use per-process
	`thread_db_active'.
	(linux_request_interrupt): Adjust to use ptids.
	(linux_read_auxv): Inline `inferior_pid'.
	(initialize_low): Don't reference thread_db_active.
	* gdb_proc_service.h (struct ps_prochandle) <pid>: Remove.
	* thread-db.c (proc_handle, thread_agent): Delete.
	(thread_db_create_event, thread_db_enable_reporting): Adjust to
	per-process data.
	(find_one_thread): Change argument type to ptid_t.  Adjust to
	per-process data.
	(maybe_attach_thread): Adjust to per-process data and ptids.
	(thread_db_find_new_threads): Ditto.
	(thread_db_init): Ditto.
	* spu-low.c (spu_create_inferior, spu_attach): Add process to
	processes table.  Adjust to use ptids.
	(spu_kill, spu_detach): Remove it.
	(spu_wait): Adjust interface.  Remove process from processes
	table.  Adjust to use ptids.
	* win32-low.c (current_inferior_tid): Delete.
	(current_inferior_ptid): New.
	(thread_rec): Take a ptid.  Adjust.
	(child_add_thread): Add `pid' argument.  Adjust to use ptids.
	(child_delete_thread): Take a ptid.  Adjust.
	(do_initial_child_stuff): Add `attached' argument.  Add process to
	processes table.
	(child_fetch_inferior_registers, child_store_inferior_registers):
	Adjust.
	(win32_create_inferior): Pass 0 to do_initial_child_stuff.
	(win32_attach): Pass 1 to do_initial_child_stuff.
	(win32_kill): Remove process from processes table.
	(win32_detach): Ditto.
	(win32_resume): Adjust to use ptids.
	(win32_wait): Remove exiting process from processes table.

---
 gdb/gdbserver/gdb_proc_service.h |    4 
 gdb/gdbserver/inferiors.c        |  169 ++++++++++--
 gdb/gdbserver/linux-low.c        |  537 ++++++++++++++++++++++++++++-----------
 gdb/gdbserver/linux-low.h        |   28 +-
 gdb/gdbserver/mem-break.c        |   47 ++-
 gdb/gdbserver/mem-break.h        |    5 
 gdb/gdbserver/proc-service.c     |    5 
 gdb/gdbserver/remote-utils.c     |  194 ++++++++++++--
 gdb/gdbserver/server.c           |  364 +++++++++++++++++++-------
 gdb/gdbserver/server.h           |  132 ++++++++-
 gdb/gdbserver/spu-low.c          |   28 +-
 gdb/gdbserver/target.c           |   49 ++-
 gdb/gdbserver/target.h           |   51 ++-
 gdb/gdbserver/thread-db.c        |   69 ++---
 gdb/gdbserver/win32-low.c        |   49 ++-
 15 files changed, 1321 insertions(+), 410 deletions(-)

Index: src/gdb/gdbserver/inferiors.c
===================================================================
--- src.orig/gdb/gdbserver/inferiors.c	2009-03-30 01:19:42.000000000 +0100
+++ src/gdb/gdbserver/inferiors.c	2009-03-30 12:30:55.000000000 +0100
@@ -30,12 +30,88 @@ struct thread_info
   unsigned int gdb_id;
 };
 
+struct inferior_list all_processes;
 struct inferior_list all_threads;
 struct inferior_list all_dlls;
 int dlls_changed;
 
 struct thread_info *current_inferior;
 
+
+/* Oft used ptids */
+ptid_t null_ptid;
+ptid_t minus_one_ptid;
+
+/* Create a ptid given the necessary PID, LWP, and TID components.  */
+
+ptid_t
+ptid_build (int pid, long lwp, long tid)
+{
+  ptid_t ptid;
+
+  ptid.pid = pid;
+  ptid.lwp = lwp;
+  ptid.tid = tid;
+  return ptid;
+}
+
+/* Create a ptid from just a pid.  */
+
+ptid_t
+pid_to_ptid (int pid)
+{
+  return ptid_build (pid, 0, 0);
+}
+
+/* Fetch the pid (process id) component from a ptid.  */
+
+int
+ptid_get_pid (ptid_t ptid)
+{
+  return ptid.pid;
+}
+
+/* Fetch the lwp (lightweight process) component from a ptid.  */
+
+long
+ptid_get_lwp (ptid_t ptid)
+{
+  return ptid.lwp;
+}
+
+/* Fetch the tid (thread id) component from a ptid.  */
+
+long
+ptid_get_tid (ptid_t ptid)
+{
+  return ptid.tid;
+}
+
+/* ptid_equal() is used to test equality of two ptids.  */
+
+int
+ptid_equal (ptid_t ptid1, ptid_t ptid2)
+{
+  return (ptid1.pid == ptid2.pid
+	  && ptid1.lwp == ptid2.lwp
+	  && ptid1.tid == ptid2.tid);
+}
+
+/* Return true if this ptid represents a process.  */
+
+int
+ptid_is_pid (ptid_t ptid)
+{
+  if (ptid_equal (minus_one_ptid, ptid))
+    return 0;
+  if (ptid_equal (null_ptid, ptid))
+    return 0;
+
+  return (ptid_get_pid (ptid) != 0
+	  && ptid_get_lwp (ptid) == 0
+	  && ptid_get_tid (ptid) == 0);
+}
+
 #define get_thread(inf) ((struct thread_info *)(inf))
 #define get_dll(inf) ((struct dll_info *)(inf))
 
@@ -93,7 +169,7 @@ remove_inferior (struct inferior_list *l
 }
 
 void
-add_thread (unsigned long thread_id, void *target_data, unsigned int gdb_id)
+add_thread (ptid_t thread_id, void *target_data)
 {
   struct thread_info *new_thread = xmalloc (sizeof (*new_thread));
 
@@ -108,40 +184,38 @@ add_thread (unsigned long thread_id, voi
 
   new_thread->target_data = target_data;
   set_inferior_regcache_data (new_thread, new_register_cache ());
-  new_thread->gdb_id = gdb_id;
 }
 
-unsigned int
-thread_id_to_gdb_id (unsigned long thread_id)
+ptid_t
+thread_id_to_gdb_id (ptid_t thread_id)
 {
   struct inferior_list_entry *inf = all_threads.head;
 
   while (inf != NULL)
     {
-      struct thread_info *thread = get_thread (inf);
-      if (inf->id == thread_id)
-	return thread->gdb_id;
+      if (ptid_equal (inf->id, thread_id))
+	return thread_id;
       inf = inf->next;
     }
 
-  return 0;
+  return null_ptid;
 }
 
-unsigned int
+ptid_t
 thread_to_gdb_id (struct thread_info *thread)
 {
-  return thread->gdb_id;
+  return thread->entry.id;
 }
 
 struct thread_info *
-gdb_id_to_thread (unsigned int gdb_id)
+find_thread_pid (ptid_t ptid)
 {
   struct inferior_list_entry *inf = all_threads.head;
 
   while (inf != NULL)
     {
       struct thread_info *thread = get_thread (inf);
-      if (thread->gdb_id == gdb_id)
+      if (ptid_equal (thread->entry.id, ptid))
 	return thread;
       inf = inf->next;
     }
@@ -149,12 +223,12 @@ gdb_id_to_thread (unsigned int gdb_id)
   return NULL;
 }
 
-unsigned long
-gdb_id_to_thread_id (unsigned int gdb_id)
+ptid_t
+gdb_id_to_thread_id (ptid_t gdb_id)
 {
-  struct thread_info *thread = gdb_id_to_thread (gdb_id);
+  struct thread_info *thread = find_thread_pid (gdb_id);
 
-  return thread ? thread->entry.id : 0;
+  return thread ? thread->entry.id : null_ptid;
 }
 
 static void
@@ -192,13 +266,13 @@ find_inferior (struct inferior_list *lis
 }
 
 struct inferior_list_entry *
-find_inferior_id (struct inferior_list *list, unsigned long id)
+find_inferior_id (struct inferior_list *list, ptid_t id)
 {
   struct inferior_list_entry *inf = list->head;
 
   while (inf != NULL)
     {
-      if (inf->id == id)
+      if (ptid_equal (inf->id, id))
 	return inf;
       inf = inf->next;
     }
@@ -267,7 +341,7 @@ loaded_dll (const char *name, CORE_ADDR 
   struct dll_info *new_dll = xmalloc (sizeof (*new_dll));
   memset (new_dll, 0, sizeof (*new_dll));
 
-  new_dll->entry.id = -1;
+  new_dll->entry.id = minus_one_ptid;
 
   new_dll->name = xstrdup (name);
   new_dll->base_addr = base_addr;
@@ -318,7 +392,7 @@ add_pid_to_list (struct inferior_list *l
   struct inferior_list_entry *new_entry;
 
   new_entry = xmalloc (sizeof (struct inferior_list_entry));
-  new_entry->id = pid;
+  new_entry->id = pid_to_ptid (pid);
   add_inferior_to_list (list, new_entry);
 }
 
@@ -327,7 +401,7 @@ pull_pid_from_list (struct inferior_list
 {
   struct inferior_list_entry *new_entry;
 
-  new_entry = find_inferior_id (list, pid);
+  new_entry = find_inferior_id (list, pid_to_ptid (pid));
   if (new_entry == NULL)
     return 0;
   else
@@ -337,3 +411,56 @@ pull_pid_from_list (struct inferior_list
       return 1;
     }
 }
+
+struct process_info *
+add_process (int pid, int attached)
+{
+  struct process_info *process;
+
+  process = xcalloc (1, sizeof (*process));
+
+  process->head.id = pid_to_ptid (pid);
+  process->attached = attached;
+
+  add_inferior_to_list (&all_processes, &process->head);
+
+  return process;
+}
+
+void
+remove_process (struct process_info *process)
+{
+  clear_symbol_cache (&process->symbol_cache);
+  free_all_breakpoints (process);
+  remove_inferior (&all_processes, &process->head);
+}
+
+struct process_info *
+find_process_pid (int pid)
+{
+  return (struct process_info *)
+    find_inferior_id (&all_processes, pid_to_ptid (pid));
+}
+
+static struct process_info *
+get_thread_process (struct thread_info *thread)
+{
+  int pid = ptid_get_pid (thread->entry.id);
+  return find_process_pid (pid);
+}
+
+struct process_info *
+current_process (void)
+{
+  if (current_inferior == NULL)
+    fatal ("Current inferior requested, but current_inferior is NULL\n");
+
+  return get_thread_process (current_inferior);
+}
+
+void
+initialize_inferiors (void)
+{
+  null_ptid = ptid_build (0, 0, 0);
+  minus_one_ptid = ptid_build (-1, 0, 0);
+}
Index: src/gdb/gdbserver/linux-low.c
===================================================================
--- src.orig/gdb/gdbserver/linux-low.c	2009-03-30 01:20:27.000000000 +0100
+++ src/gdb/gdbserver/linux-low.c	2009-03-30 12:42:48.000000000 +0100
@@ -90,7 +90,10 @@
    representation of the thread ID.
 
    ``all_lwps'' is keyed by the process ID - which on Linux is (presently)
-   the same as the LWP ID.  */
+   the same as the LWP ID.
+
+   ``all_processes'' is keyed by the "overall process ID", which
+   GNU/Linux calls tgid, "thread group ID".  */
 
 struct inferior_list all_lwps;
 
@@ -105,24 +108,28 @@ int stopping_threads;
 
 /* FIXME make into a target method?  */
 int using_threads = 1;
-static int thread_db_active;
 
 static int must_set_ptrace_flags;
 
-/* This flag is true iff we've just created or attached to a new inferior
-   but it has not stopped yet.  As soon as it does, we need to call the
-   low target's arch_setup callback.  */
+/* This flag is true iff we've just created or attached to our first
+   inferior but it has not stopped yet.  As soon as it does, we need
+   to call the low target's arch_setup callback.  Doing this only on
+   the first inferior avoids reinializing the architecture on every
+   inferior, and avoids messing with the register caches of the
+   already running inferiors.  NOTE: this assumes all inferiors under
+   control of gdbserver have the same architecture.  */
 static int new_inferior;
 
 static void linux_resume_one_lwp (struct inferior_list_entry *entry,
 				  int step, int signal, siginfo_t *info);
 static void linux_resume (struct thread_resume *resume_info, size_t n);
 static void stop_all_lwps (void);
-static int linux_wait_for_event (int pid, int *wstat, int options);
+static int linux_wait_for_event (ptid_t ptid, int *wstat, int options);
 static int check_removed_breakpoint (struct lwp_info *event_child);
-static void *add_lwp (unsigned long pid);
+static void *add_lwp (ptid_t ptid);
 static int my_waitpid (int pid, int *status, int flags);
 static int linux_stopped_by_watchpoint (void);
+static void mark_lwp_dead (struct lwp_info *lwp, int wstat);
 
 struct pending_signals
 {
@@ -139,9 +146,6 @@ static char *disabled_regsets;
 static int num_regsets;
 #endif
 
-/* FIXME: Delete eventually.  */
-#define inferior_pid (lwpid_of (get_thread_lwp (current_inferior)))
-
 /* The read/write ends of the pipe registered as waitable file in the
    event loop.  */
 static int linux_event_pipe[2] = { -1, -1 };
@@ -160,6 +164,24 @@ delete_lwp (struct lwp_info *lwp)
   free (lwp);
 }
 
+/* Add a process to the common process list, and set its private
+   data.  */
+
+static struct process_info *
+linux_add_process (int pid, int attached)
+{
+  struct process_info *proc;
+
+  /* Is this the first process?  If so, then set the arch.  */
+  if (all_processes.head == NULL)
+    new_inferior = 1;
+
+  proc = add_process (pid, attached);
+  proc->private = xcalloc (1, sizeof (*proc->private));
+
+  return proc;
+}
+
 /* Handle a GNU/Linux extended wait response.  If we see a clone
    event, we need to add the new LWP to our list (and not report the
    trap to higher layers).  */
@@ -172,6 +194,7 @@ handle_extended_wait (struct lwp_info *e
 
   if (event == PTRACE_EVENT_CLONE)
     {
+      ptid_t ptid;
       unsigned long new_pid;
       int ret, status = W_STOPCODE (SIGSTOP);
 
@@ -195,9 +218,9 @@ handle_extended_wait (struct lwp_info *e
 
       ptrace (PTRACE_SETOPTIONS, new_pid, 0, PTRACE_O_TRACECLONE);
 
-      new_lwp = (struct lwp_info *) add_lwp (new_pid);
-      add_thread (new_pid, new_lwp, new_pid);
-      new_thread_notify (thread_id_to_gdb_id (lwpid_of (new_lwp)));
+      ptid = ptid_build (pid_of (event_child), new_pid, 0);
+      new_lwp = (struct lwp_info *) add_lwp (ptid);
+      add_thread (ptid, new_lwp);
 
       /* Normally we will get the pending SIGSTOP.  But in some cases
 	 we might get another signal delivered to the group first.
@@ -266,14 +289,14 @@ get_stop_pc (void)
 }
 
 static void *
-add_lwp (unsigned long pid)
+add_lwp (ptid_t ptid)
 {
   struct lwp_info *lwp;
 
   lwp = (struct lwp_info *) xmalloc (sizeof (*lwp));
   memset (lwp, 0, sizeof (*lwp));
 
-  lwp->head.id = pid;
+  lwp->head.id = ptid;
 
   add_inferior_to_list (&all_lwps, &lwp->head);
 
@@ -288,6 +311,7 @@ linux_create_inferior (char *program, ch
 {
   void *new_lwp;
   int pid;
+  ptid_t ptid;
 
 #if defined(__UCLIBC__) && defined(HAS_NOMMU)
   pid = vfork ();
@@ -315,44 +339,58 @@ linux_create_inferior (char *program, ch
       _exit (0177);
     }
 
-  new_lwp = add_lwp (pid);
-  add_thread (pid, new_lwp, pid);
+  linux_add_process (pid, 0);
+
+  ptid = ptid_build (pid, pid, 0);
+  new_lwp = add_lwp (ptid);
+  add_thread (ptid, new_lwp);
   must_set_ptrace_flags = 1;
-  new_inferior = 1;
 
   return pid;
 }
 
 /* Attach to an inferior process.  */
 
-void
-linux_attach_lwp (unsigned long pid)
+static void
+linux_attach_lwp_1 (unsigned long lwpid, int initial)
 {
+  ptid_t ptid;
   struct lwp_info *new_lwp;
 
-  if (ptrace (PTRACE_ATTACH, pid, 0, 0) != 0)
+  if (ptrace (PTRACE_ATTACH, lwpid, 0, 0) != 0)
     {
-      if (all_threads.head != NULL)
+      if (!initial)
 	{
 	  /* If we fail to attach to an LWP, just warn.  */
-	  fprintf (stderr, "Cannot attach to lwp %ld: %s (%d)\n", pid,
+	  fprintf (stderr, "Cannot attach to lwp %ld: %s (%d)\n", lwpid,
 		   strerror (errno), errno);
 	  fflush (stderr);
 	  return;
 	}
       else
 	/* If we fail to attach to a process, report an error.  */
-	error ("Cannot attach to lwp %ld: %s (%d)\n", pid,
+	error ("Cannot attach to lwp %ld: %s (%d)\n", lwpid,
 	       strerror (errno), errno);
     }
 
   /* FIXME: This intermittently fails.
      We need to wait for SIGSTOP first.  */
-  ptrace (PTRACE_SETOPTIONS, pid, 0, PTRACE_O_TRACECLONE);
+  ptrace (PTRACE_SETOPTIONS, lwpid, 0, PTRACE_O_TRACECLONE);
+
+  if (initial)
+    /* NOTE/FIXME: This lwp might have not been the tgid.  */
+    ptid = ptid_build (lwpid, lwpid, 0);
+  else
+    {
+      /* Note that extracting the pid from the current inferior is
+	 safe, since we're always called in the context of the same
+	 process as this new thread.  */
+      int pid = pid_of (get_thread_lwp (current_inferior));
+      ptid = ptid_build (pid, lwpid, 0);
+    }
 
-  new_lwp = (struct lwp_info *) add_lwp (pid);
-  add_thread (pid, new_lwp, pid);
-  new_thread_notify (thread_id_to_gdb_id (lwpid_of (new_lwp)));
+  new_lwp = (struct lwp_info *) add_lwp (ptid);
+  add_thread (ptid, new_lwp);
 
   /* The next time we wait for this LWP we'll see a SIGSTOP as PTRACE_ATTACH
      brings it to a halt.
@@ -389,42 +427,89 @@ linux_attach_lwp (unsigned long pid)
     new_lwp->stop_expected = 1;
 }
 
+void
+linux_attach_lwp (unsigned long lwpid)
+{
+  linux_attach_lwp_1 (lwpid, 0);
+}
+
 int
 linux_attach (unsigned long pid)
 {
   struct lwp_info *lwp;
 
-  linux_attach_lwp (pid);
+  linux_attach_lwp_1 (pid, 1);
+
+  linux_add_process (pid, 1);
 
   if (!non_stop)
     {
       /* Don't ignore the initial SIGSTOP if we just attached to this
 	 process.  It will be collected by wait shortly.  */
-      lwp = (struct lwp_info *) find_inferior_id (&all_lwps, pid);
+      lwp = (struct lwp_info *) find_inferior_id (&all_lwps,
+						  ptid_build (pid, pid, 0));
       lwp->stop_expected = 0;
     }
 
-  new_inferior = 1;
+  return 0;
+}
+
+struct counter
+{
+  int pid;
+  int count;
+};
+
+static int
+second_thread_of_pid_p (struct inferior_list_entry *entry, void *args)
+{
+  struct counter *counter = args;
+
+  if (ptid_get_pid (entry->id) == counter->pid)
+    {
+      if (++counter->count > 1)
+	return 1;
+    }
 
   return 0;
 }
 
-/* Kill the inferior process.  Make us have no inferior.  */
+static int
+last_thread_of_process_p (struct thread_info *thread)
+{
+  ptid_t ptid = ((struct inferior_list_entry *)thread)->id;
+  int pid = ptid_get_pid (ptid);
+  struct counter counter = { pid , 0 };
 
-static void
-linux_kill_one_lwp (struct inferior_list_entry *entry)
+  return (find_inferior (&all_threads,
+			 second_thread_of_pid_p, &counter) == NULL);
+}
+
+/* Kill the inferior lwp.  */
+
+static int
+linux_kill_one_lwp (struct inferior_list_entry *entry, void *args)
 {
   struct thread_info *thread = (struct thread_info *) entry;
   struct lwp_info *lwp = get_thread_lwp (thread);
-  int pid;
   int wstat;
+  int pid = * (int *) args;
+
+  if (ptid_get_pid (entry->id) != pid)
+    return 0;
 
   /* We avoid killing the first thread here, because of a Linux kernel (at
      least 2.6.0-test7 through 2.6.8-rc4) bug; if we kill the parent before
      the children get a chance to be reaped, it will remain a zombie
      forever.  */
-  if (entry == all_threads.head)
-    return;
+
+  if (last_thread_of_process_p (thread))
+    {
+      if (debug_threads)
+	fprintf (stderr, "lkop: is last of process %s\n",
+		 target_pid_to_str (entry->id));
+      return 0;
+    }
 
   /* If we're killing a running inferior, make sure it is stopped
      first, as PTRACE_KILL will not work otherwise.  */
@@ -436,29 +521,35 @@ linux_kill_one_lwp (struct inferior_list
       ptrace (PTRACE_KILL, lwpid_of (lwp), 0, 0);
 
       /* Make sure it died.  The loop is most likely unnecessary.  */
-      pid = linux_wait_for_event (lwpid_of (lwp), &wstat, __WALL);
+      pid = linux_wait_for_event (lwp->head.id, &wstat, __WALL);
     } while (pid > 0 && WIFSTOPPED (wstat));
+
+  return 0;
 }
 
-static void
-linux_kill (void)
+static int
+linux_kill (int pid)
 {
-  struct thread_info *thread = (struct thread_info *) all_threads.head;
+  struct process_info *process;
   struct lwp_info *lwp;
+  struct thread_info *thread;
   int wstat;
-  int pid;
+  int lwpid;
 
-  if (thread == NULL)
-    return;
+  process = find_process_pid (pid);
+  if (process == NULL)
+    return -1;
 
-  for_each_inferior (&all_threads, linux_kill_one_lwp);
+  find_inferior (&all_threads, linux_kill_one_lwp, &pid);
 
   /* See the comment in linux_kill_one_lwp.  We did not kill the first
      thread in the list, so do so now.  */
-  lwp = get_thread_lwp (thread);
+  lwp = find_lwp_pid (pid_to_ptid (pid));
+  thread = get_lwp_thread (lwp);
 
   if (debug_threads)
-    fprintf (stderr, "lk_1: killing lwp %ld\n", lwpid_of (lwp));
+    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.  */
@@ -470,24 +561,29 @@ linux_kill (void)
       ptrace (PTRACE_KILL, lwpid_of (lwp), 0, 0);
 
       /* Make sure it died.  The loop is most likely unnecessary.  */
-      pid = linux_wait_for_event (lwpid_of (lwp), &wstat, __WALL);
-    } while (pid > 0 && WIFSTOPPED (wstat));
+      lwpid = linux_wait_for_event (lwp->head.id, &wstat, __WALL);
+    } while (lwpid > 0 && WIFSTOPPED (wstat));
 
   delete_lwp (lwp);
-  clear_inferiors ();
+  remove_process (process);
+  return 0;
 }
 
-static void
-linux_detach_one_lwp (struct inferior_list_entry *entry)
+static int
+linux_detach_one_lwp (struct inferior_list_entry *entry, void *args)
 {
   struct thread_info *thread = (struct thread_info *) entry;
   struct lwp_info *lwp = get_thread_lwp (thread);
+  int pid = * (int *) 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 pid = lwpid_of (lwp);
+      int lwpid = lwpid_of (lwp);
 
       stopping_threads = 1;
       send_sigstop (&lwp->head);
@@ -500,9 +596,9 @@ linux_detach_one_lwp (struct inferior_li
 
       /* If LWP exits while we're trying to stop it, there's nothing
 	 left to do.  */
-      lwp = (struct lwp_info *) find_inferior_id (&all_lwps, pid);
+      lwp = find_lwp_pid (pid_to_ptid (lwpid));
       if (lwp == NULL)
-	return;
+	return 0;
     }
 
   /* Make sure the process isn't stopped at a breakpoint that's
@@ -519,7 +615,7 @@ linux_detach_one_lwp (struct inferior_li
       lwp->stop_expected = 0;
       if (lwp->stopped)
 	linux_resume_one_lwp (&lwp->head, 0, 0, NULL);
-      linux_wait_for_event (lwpid_of (lwp), &wstat, __WALL);
+      linux_wait_for_event (lwp->head.id, &wstat, __WALL);
     }
 
   /* Flush any pending changes to the process's registers.  */
@@ -530,29 +626,50 @@ linux_detach_one_lwp (struct inferior_li
   ptrace (PTRACE_DETACH, lwpid_of (lwp), 0, 0);
 
   delete_lwp (lwp);
+  return 0;
 }
 
 static int
-linux_detach (void)
+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)
+{
+  struct process_info *process;
+
+  process = find_process_pid (pid);
+  if (process == NULL)
+    return -1;
+
+  current_inferior =
+    (struct thread_info *) find_inferior (&all_threads, any_thread_of, &pid);
+
   delete_all_breakpoints ();
-  for_each_inferior (&all_threads, linux_detach_one_lwp);
-  clear_inferiors ();
+  find_inferior (&all_threads, linux_detach_one_lwp, &pid);
+  remove_process (process);
   return 0;
 }
 
 static void
-linux_join (void)
+linux_join (int pid)
 {
   int status, ret;
-  struct thread_info *thread;
-  struct lwp_info *lwp;
+  struct process_info *process;
 
-  thread = (struct thread_info *) all_threads.head;
-  lwp = get_thread_lwp (thread);
+  process = find_process_pid (pid);
+  if (process == NULL)
+    return;
 
   do {
-    ret = my_waitpid (lwpid_of (lwp), &status, 0);
+    ret = my_waitpid (pid, &status, 0);
     if (WIFEXITED (status) || WIFSIGNALED (status))
       break;
   } while (ret != -1 || errno != ECHILD);
@@ -560,10 +677,15 @@ linux_join (void)
 
 /* Return nonzero if the given thread is still alive.  */
 static int
-linux_thread_alive (unsigned long lwpid)
+linux_thread_alive (ptid_t ptid)
 {
-  if (find_inferior_id (&all_threads, lwpid) != NULL)
-    return 1;
+  struct lwp_info *lwp = find_lwp_pid (ptid);
+
+  /* We assume we always know if a thread exits.  If a whole process
+     exited but we still haven't been able to report it to GDB, we'll
+     hold on to the last lwp of the dead process.  */
+  if (lwp != NULL)
+    return !lwp->dead;
   else
     return 0;
 }
@@ -633,9 +755,16 @@ check_removed_breakpoint (struct lwp_inf
 /* Return 1 if this lwp has an interesting status pending.  This
    function may silently resume an inferior lwp.  */
 static int
-status_pending_p (struct inferior_list_entry *entry, void *dummy)
+status_pending_p (struct inferior_list_entry *entry, void *arg)
 {
   struct lwp_info *lwp = (struct lwp_info *) entry;
+  ptid_t ptid = * (ptid_t *) arg;
+
+  /* Check if we're only interested in events from a specific process
+     or its lwps.  */
+  if (!ptid_equal (minus_one_ptid, ptid)
+      && ptid_get_pid (ptid) != ptid_get_pid (lwp->head.id))
+    return 0;
 
   if (lwp->status_pending_p && !lwp->suspended)
     if (check_removed_breakpoint (lwp))
@@ -653,15 +782,43 @@ status_pending_p (struct inferior_list_e
   return (lwp->status_pending_p && !lwp->suspended);
 }
 
+static int
+same_lwp (struct inferior_list_entry *entry, void *data)
+{
+  ptid_t ptid = *(ptid_t *) data;
+  int lwp;
+
+  if (ptid_get_lwp (ptid) != 0)
+    lwp = ptid_get_lwp (ptid);
+  else
+    lwp = ptid_get_pid (ptid);
+
+  if (ptid_get_lwp (entry->id) == lwp)
+    return 1;
+
+  return 0;
+}
+
+struct lwp_info *
+find_lwp_pid (ptid_t ptid)
+{
+  return (struct lwp_info*) find_inferior (&all_lwps, same_lwp, &ptid);
+}
+
 static struct lwp_info *
-linux_wait_for_lwp (int pid, int *wstatp, int options)
+linux_wait_for_lwp (ptid_t ptid, int *wstatp, int options)
 {
   int ret;
-  int to_wait_for = pid;
+  int to_wait_for = -1;
   struct lwp_info *child = NULL;
 
   if (debug_threads)
-    fprintf (stderr, "linux_wait_for_lwp: %d\n", pid);
+    fprintf (stderr, "linux_wait_for_lwp: %s\n", target_pid_to_str (ptid));
+
+  if (ptid_equal (ptid, minus_one_ptid))
+    to_wait_for = -1;			/* any child */
+  else
+    to_wait_for = ptid_get_lwp (ptid);	/* this lwp only */
 
   options |= __WALL;
 
@@ -679,7 +836,7 @@ retry:
 	      && WSTOPSIG (*wstatp) != 33)))
     fprintf (stderr, "Got an event from %d (%x)\n", ret, *wstatp);
 
-  child = (struct lwp_info *) find_inferior_id (&all_lwps, ret);
+  child = find_lwp_pid (pid_to_ptid (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.
@@ -716,7 +873,7 @@ retry:
     {
       struct thread_info *saved_inferior = current_inferior;
       current_inferior = (struct thread_info *)
-	find_inferior_id (&all_threads, lwpid_of (child));
+	find_inferior_id (&all_threads, child->head.id);
       /* For testing only; i386_stop_pc prints out a diagnostic.  */
       if (the_low_target.get_pc != NULL)
 	get_stop_pc ();
@@ -733,29 +890,29 @@ retry:
    the stopped child otherwise.  */
 
 static int
-linux_wait_for_event (int pid, int *wstat, int options)
+linux_wait_for_event_1 (ptid_t ptid, int *wstat, int options)
 {
   CORE_ADDR stop_pc;
   struct lwp_info *event_child = NULL;
   int bp_status;
   struct lwp_info *requested_child = NULL;
 
-  /* Check for a process with a pending status.  */
+  /* Check for a lwp with a pending status.  */
   /* It is possible that the user changed the pending task's registers since
      it stopped.  We correctly handle the change of PC if we hit a breakpoint
      (in check_removed_breakpoint); signals should be reported anyway.  */
 
-  if (pid == -1)
+  if (ptid_equal (ptid, minus_one_ptid)
+      || ptid_equal (pid_to_ptid (ptid_get_pid (ptid)), ptid))
     {
       event_child = (struct lwp_info *)
-	find_inferior (&all_lwps, status_pending_p, NULL);
+	find_inferior (&all_lwps, status_pending_p, &ptid);
       if (debug_threads && event_child)
 	fprintf (stderr, "Got a pending child %ld\n", lwpid_of (event_child));
     }
   else
     {
-      requested_child = (struct lwp_info *)
-	find_inferior_id (&all_lwps, pid);
+      requested_child = find_lwp_pid (ptid);
       if (requested_child->status_pending_p
 	  && !check_removed_breakpoint (requested_child))
 	event_child = requested_child;
@@ -779,7 +936,7 @@ linux_wait_for_event (int pid, int *wsta
      events.  */
   while (1)
     {
-      event_child = linux_wait_for_lwp (pid, wstat, options);
+      event_child = linux_wait_for_lwp (ptid, wstat, options);
 
       if ((options & WNOHANG) && event_child == NULL)
 	return 0;
@@ -792,19 +949,18 @@ linux_wait_for_event (int pid, int *wsta
       /* Check for thread exit.  */
       if (! WIFSTOPPED (*wstat))
 	{
-	  int lwpid = lwpid_of (event_child);
 	  if (debug_threads)
-	    fprintf (stderr, "LWP %d exiting\n", lwpid);
+	    fprintf (stderr, "LWP %ld exiting\n", lwpid_of (event_child));
 
 	  /* If the last thread is exiting, just return.  */
-	  if (all_threads.head == all_threads.tail)
+	  if (last_thread_of_process_p (current_inferior))
 	    {
 	      if (debug_threads)
-		fprintf (stderr, "LWP %d is last lwp of process\n", lwpid);
+		fprintf (stderr, "LWP %ld is last lwp of process\n",
+			 lwpid_of (event_child));
 	      return lwpid_of (event_child);
 	    }
 
-	  dead_thread_notify (thread_id_to_gdb_id (lwpid_of (event_child)));
 	  delete_lwp (event_child);
 
 	  if (!non_stop)
@@ -824,7 +980,7 @@ linux_wait_for_event (int pid, int *wsta
 	  /* If we were waiting for this particular child to do something...
 	     well, it did something.  */
 	  if (requested_child != NULL)
-	    return lwpid;
+	    return lwpid_of (event_child);
 
 	  /* Wait for a more interesting event.  */
 	  continue;
@@ -862,7 +1018,7 @@ linux_wait_for_event (int pid, int *wsta
 	  && !event_child->stepping
 	  && (
 #ifdef USE_THREAD_DB
-	      (thread_db_active
+	      (current_process ()->private->thread_db_active
 	       && (WSTOPSIG (*wstat) == __SIGRTMIN
 		   || WSTOPSIG (*wstat) == __SIGRTMIN + 1))
 	      ||
@@ -1000,16 +1156,56 @@ linux_wait_for_event (int pid, int *wsta
   return 0;
 }
 
+static int
+linux_wait_for_event (ptid_t ptid, int *wstat, int options)
+{
+  ptid_t wait_ptid;
+
+  if (ptid_is_pid (ptid))
+    {
+      /* A request to wait for a specific tgid.  This is not possible
+	 with waitpid, so instead, we wait for any child, and leave
+	 children we're not interested in right now with a pending
+	 status to report later.  */
+      wait_ptid = minus_one_ptid;
+    }
+  else
+    wait_ptid = ptid;
+
+  while (1)
+    {
+      int event_pid;
+
+      event_pid = linux_wait_for_event_1 (wait_ptid, wstat, options);
+
+      if (event_pid > 0
+	  && ptid_is_pid (ptid) && ptid_get_pid (ptid) != event_pid)
+	{
+	  struct lwp_info *event_child = find_lwp_pid (pid_to_ptid (event_pid));
+
+	  if (! WIFSTOPPED (*wstat))
+	    mark_lwp_dead (event_child, *wstat);
+	  else
+	    {
+	      event_child->status_pending_p = 1;
+	      event_child->status_pending = *wstat;
+	    }
+	}
+      else
+	return event_pid;
+    }
+}
+
 /* Wait for process, returns status.  */
 
-static unsigned long
-linux_wait_1 (struct target_waitstatus *ourstatus, int target_options)
+static ptid_t
+linux_wait_1 (ptid_t ptid,
+	      struct target_waitstatus *ourstatus, int target_options)
 {
   int w;
   struct thread_info *thread = NULL;
   struct lwp_info *lwp = NULL;
   int options;
-  int wait_pid = -1;
   int pid;
 
   /* Translate generic target options into linux options.  */
@@ -1026,7 +1222,9 @@ retry:
      then we need to make sure we restart the other threads.  We could
      pick a thread at random or restart all; restarting all is less
      arbitrary.  */
-  if (!non_stop && cont_thread != 0 && cont_thread != -1)
+  if (!non_stop
+      && !ptid_equal (cont_thread, null_ptid)
+      && !ptid_equal (cont_thread, minus_one_ptid))
     {
       thread = (struct thread_info *) find_inferior_id (&all_threads,
 							cont_thread);
@@ -1035,18 +1233,18 @@ retry:
       if (thread == NULL)
 	{
 	  struct thread_resume resume_info;
-	  resume_info.thread = -1;
+	  resume_info.thread = minus_one_ptid;
 	  resume_info.kind = resume_continue;
 	  resume_info.sig = 0;
 	  linux_resume (&resume_info, 1);
 	}
       else
-	wait_pid = cont_thread;
+	ptid = cont_thread;
     }
 
-  pid = linux_wait_for_event (wait_pid, &w, options);
+  pid = linux_wait_for_event (ptid, &w, options);
   if (pid == 0) /* only if TARGET_WNOHANG */
-    return pid;
+    return null_ptid;
 
   lwp = get_thread_lwp (current_inferior);
 
@@ -1067,16 +1265,15 @@ retry:
      Report the exit status of the last thread to exit.  This matches
      LinuxThreads' behavior.  */
 
-  if (all_threads.head == all_threads.tail)
+  if (last_thread_of_process_p (current_inferior))
     {
       if (WIFEXITED (w) || WIFSIGNALED (w))
 	{
-	  int pid;
-
-	  pid = pid_of (lwp);
+	  int pid = pid_of (lwp);
+	  struct process_info *process = find_process_pid (pid);
 
 	  delete_lwp (lwp);
-	  clear_inferiors ();
+	  remove_process (process);
 
 	  current_inferior = NULL;
 
@@ -1098,7 +1295,7 @@ retry:
 
 	    }
 
-	  return pid;
+	  return pid_to_ptid (pid);
 	}
     }
   else
@@ -1135,12 +1332,12 @@ retry:
     }
 
   if (debug_threads)
-    fprintf (stderr, "linux_wait ret = %ld, %d, %d\n",
-	     lwpid_of (lwp),
+    fprintf (stderr, "linux_wait ret = %s, %d, %d\n",
+	     target_pid_to_str (lwp->head.id),
 	     ourstatus->kind,
 	     ourstatus->value.sig);
 
-  return lwpid_of (lwp);
+  return lwp->head.id;
 }
 
 /* Get rid of any pending event in the pipe.  */
@@ -1171,25 +1368,26 @@ async_file_mark (void)
      be awakened anyway.  */
 }
 
-static unsigned long
-linux_wait (struct target_waitstatus *ourstatus, int target_options)
+static ptid_t
+linux_wait (ptid_t ptid,
+	    struct target_waitstatus *ourstatus, int target_options)
 {
-  unsigned long event_ptid;
+  ptid_t event_ptid;
 
   if (debug_threads)
-    fprintf (stderr, "linux_wait\n");
+    fprintf (stderr, "linux_wait: [%s]\n", target_pid_to_str (ptid));
 
   /* Flush the async file first.  */
   if (target_is_async_p ())
     async_file_flush ();
 
-  event_ptid = linux_wait_1 (ourstatus, target_options);
+  event_ptid = linux_wait_1 (ptid, ourstatus, target_options);
 
   /* If at least one stop was reported, there may be more.  A single
      SIGCHLD can signal more than one child stop.  */
   if (target_is_async_p ()
       && (target_options & TARGET_WNOHANG) != 0
-      && event_ptid != 0)
+      && !ptid_equal (event_ptid, null_ptid))
     async_file_mark ();
 
   return event_ptid;
@@ -1251,13 +1449,34 @@ send_sigstop (struct inferior_list_entry
 }
 
 static void
+mark_lwp_dead (struct lwp_info *lwp, int wstat)
+{
+  /* It's dead, really.  */
+  lwp->dead = 1;
+
+  /* Store the exit status for later.  */
+  lwp->status_pending_p = 1;
+  lwp->status_pending = wstat;
+
+  /* So that check_removed_breakpoint doesn't try to figure out if
+     this is stopped at a breakpoint.  */
+  lwp->pending_is_breakpoint = 0;
+
+  /* Prevent trying to stop it.  */
+  lwp->stopped = 1;
+
+  /* No further stops are expected from a dead lwp.  */
+  lwp->stop_expected = 0;
+}
+
+static void
 wait_for_sigstop (struct inferior_list_entry *entry)
 {
   struct lwp_info *lwp = (struct lwp_info *) entry;
   struct thread_info *saved_inferior;
   int wstat;
-  unsigned long saved_tid;
-  unsigned long ptid;
+  ptid_t saved_tid;
+  ptid_t ptid;
 
   if (lwp->stopped)
     return;
@@ -1268,7 +1487,7 @@ wait_for_sigstop (struct inferior_list_e
   else
     saved_tid = null_ptid; /* avoid bogus unused warning */
 
-  ptid = lwpid_of (lwp);
+  ptid = lwp->head.id;
 
   linux_wait_for_event (ptid, &wstat, __WALL);
 
@@ -1301,6 +1520,18 @@ wait_for_sigstop (struct inferior_list_e
 	}
       lwp->stop_expected = 1;
     }
+  else if (!WIFSTOPPED (wstat))
+    {
+      if (debug_threads)
+	fprintf (stderr, "Process %ld exited while stopping LWPs\n",
+		 lwpid_of (lwp));
+
+      /* Leave this status pending for the next time we're able to
+	 report it.  In the mean time, we'll report this lwp as dead
+	 to GDB, so GDB doesn't try to read registers and memory from
+	 it.  */
+      mark_lwp_dead (lwp, wstat);
+    }
 
   if (saved_inferior == NULL || linux_thread_alive (saved_tid))
     current_inferior = saved_inferior;
@@ -1474,11 +1705,19 @@ linux_set_resume_request (struct inferio
   r = arg;
 
   for (ndx = 0; ndx < r->n; ndx++)
-    if (r->resume[ndx].thread == -1 || r->resume[ndx].thread == entry->id)
-      {
-	lwp->resume = &r->resume[ndx];
-	return 0;
-      }
+    {
+      ptid_t ptid = r->resume[ndx].thread;
+      if (ptid_equal (ptid, minus_one_ptid)
+	  || ptid_equal (ptid, entry->id)
+	  || (ptid_is_pid (ptid)
+	      && (ptid_get_pid (ptid) == pid_of (lwp)))
+	  || (ptid_get_lwp (ptid) == -1
+	      && (ptid_get_pid (ptid) == pid_of (lwp))))
+	{
+	  lwp->resume = &r->resume[ndx];
+	  return 0;
+	}
+    }
 
   /* No resume action for this thread.  */
   lwp->resume = NULL;
@@ -1550,7 +1789,7 @@ linux_resume_one_thread (struct inferior
       if (!lwp->stopped)
 	{
 	  if (debug_threads)
-	    fprintf (stderr, "running -> suspending %ld\n", lwpid_of (lwp));
+	    fprintf (stderr, "running -> suspending LWP %ld\n", lwpid_of (lwp));
 
 	  lwp->suspended = 1;
 	  send_sigstop (&lwp->head);
@@ -1596,7 +1835,7 @@ linux_resume_one_thread (struct inferior
       if (debug_threads)
 	fprintf (stderr, "resuming LWP %ld\n", lwpid_of (lwp));
 
-      if (lwp->resume->thread == -1
+      if (ptid_equal (lwp->resume->thread, minus_one_ptid)
 	  && lwp->stepping
 	  && lwp->pending_is_breakpoint)
 	step = 1;
@@ -1685,6 +1924,7 @@ fetch_register (int regno)
   CORE_ADDR regaddr;
   int i, size;
   char *buf;
+  int pid;
 
   if (regno >= the_low_target.num_regs)
     return;
@@ -1694,6 +1934,8 @@ fetch_register (int regno)
   regaddr = register_addr (regno);
   if (regaddr == -1)
     return;
+
+  pid = lwpid_of (get_thread_lwp (current_inferior));
   size = ((register_size (regno) + sizeof (PTRACE_XFER_TYPE) - 1)
 	  & - sizeof (PTRACE_XFER_TYPE));
   buf = alloca (size);
@@ -1701,7 +1943,7 @@ fetch_register (int regno)
     {
       errno = 0;
       *(PTRACE_XFER_TYPE *) (buf + i) =
-	ptrace (PTRACE_PEEKUSER, inferior_pid, (PTRACE_ARG3_TYPE) regaddr, 0);
+	ptrace (PTRACE_PEEKUSER, pid, (PTRACE_ARG3_TYPE) regaddr, 0);
       regaddr += sizeof (PTRACE_XFER_TYPE);
       if (errno != 0)
 	{
@@ -1766,10 +2008,11 @@ usr_store_inferior_registers (int regno)
       else
 	collect_register (regno, buf);
 
+      pid = lwpid_of (get_thread_lwp (current_inferior));
       for (i = 0; i < size; i += sizeof (PTRACE_XFER_TYPE))
 	{
 	  errno = 0;
-	  ptrace (PTRACE_POKEUSER, inferior_pid, (PTRACE_ARG3_TYPE) regaddr,
+	  ptrace (PTRACE_POKEUSER, pid, (PTRACE_ARG3_TYPE) regaddr,
 		  *(PTRACE_XFER_TYPE *) (buf + i));
 	  if (errno != 0)
 	    {
@@ -1808,9 +2051,11 @@ regsets_fetch_inferior_registers ()
 {
   struct regset_info *regset;
   int saw_general_regs = 0;
+  int pid;
 
   regset = target_regsets;
 
+  pid = lwpid_of (get_thread_lwp (current_inferior));
   while (regset->size >= 0)
     {
       void *buf;
@@ -1824,9 +2069,9 @@ regsets_fetch_inferior_registers ()
 
       buf = xmalloc (regset->size);
 #ifndef __sparc__
-      res = ptrace (regset->get_request, inferior_pid, 0, buf);
+      res = ptrace (regset->get_request, pid, 0, buf);
 #else
-      res = ptrace (regset->get_request, inferior_pid, buf, 0);
+      res = ptrace (regset->get_request, pid, buf, 0);
 #endif
       if (res < 0)
 	{
@@ -1840,8 +2085,8 @@ regsets_fetch_inferior_registers ()
 	  else
 	    {
 	      char s[256];
-	      sprintf (s, "ptrace(regsets_fetch_inferior_registers) PID=%ld",
-		       inferior_pid);
+	      sprintf (s, "ptrace(regsets_fetch_inferior_registers) PID=%d",
+		       pid);
 	      perror (s);
 	    }
 	}
@@ -1861,9 +2106,11 @@ regsets_store_inferior_registers ()
 {
   struct regset_info *regset;
   int saw_general_regs = 0;
+  int pid;
 
   regset = target_regsets;
 
+  pid = lwpid_of (get_thread_lwp (current_inferior));
   while (regset->size >= 0)
     {
       void *buf;
@@ -1881,9 +2128,9 @@ regsets_store_inferior_registers ()
 	 in case there are any items in the kernel's regset that are
 	 not in gdbserver's regcache.  */
 #ifndef __sparc__
-      res = ptrace (regset->get_request, inferior_pid, 0, buf);
+      res = ptrace (regset->get_request, pid, 0, buf);
 #else
-      res = ptrace (regset->get_request, inferior_pid, buf, 0);
+      res = ptrace (regset->get_request, pid, buf, 0);
 #endif
 
       if (res == 0)
@@ -1893,9 +2140,9 @@ regsets_store_inferior_registers ()
 
 	  /* Only now do we write the register set.  */
 #ifndef __sparc__
-	  res = ptrace (regset->set_request, inferior_pid, 0, buf);
+	  res = ptrace (regset->set_request, pid, 0, buf);
 #else
-	  res = ptrace (regset->set_request, inferior_pid, buf, 0);
+	  res = ptrace (regset->set_request, pid, buf, 0);
 #endif
 	}
 
@@ -1979,13 +2226,14 @@ linux_read_memory (CORE_ADDR memaddr, un
     = (PTRACE_XFER_TYPE *) alloca (count * sizeof (PTRACE_XFER_TYPE));
   int fd;
   char filename[64];
+  int pid = lwpid_of (get_thread_lwp (current_inferior));
 
   /* Try using /proc.  Don't bother for one word.  */
   if (len >= 3 * sizeof (long))
     {
       /* We could keep this file open and cache it - possibly one per
 	 thread.  That requires some juggling, but is even faster.  */
-      sprintf (filename, "/proc/%ld/mem", inferior_pid);
+      sprintf (filename, "/proc/%d/mem", pid);
       fd = open (filename, O_RDONLY | O_LARGEFILE);
       if (fd == -1)
 	goto no_proc;
@@ -2013,8 +2261,7 @@ linux_read_memory (CORE_ADDR memaddr, un
   for (i = 0; i < count; i++, addr += sizeof (PTRACE_XFER_TYPE))
     {
       errno = 0;
-      buffer[i] = ptrace (PTRACE_PEEKTEXT, inferior_pid,
-			  (PTRACE_ARG3_TYPE) addr, 0);
+      buffer[i] = ptrace (PTRACE_PEEKTEXT, pid, (PTRACE_ARG3_TYPE) addr, 0);
       if (errno)
 	return errno;
     }
@@ -2043,6 +2290,7 @@ linux_write_memory (CORE_ADDR memaddr, c
   = (((memaddr + len) - addr) + sizeof (PTRACE_XFER_TYPE) - 1) / sizeof (PTRACE_XFER_TYPE);
   /* Allocate buffer of that many longwords.  */
   register PTRACE_XFER_TYPE *buffer = (PTRACE_XFER_TYPE *) alloca (count * sizeof (PTRACE_XFER_TYPE));
+  int pid = lwpid_of (get_thread_lwp (current_inferior));
 
   if (debug_threads)
     {
@@ -2051,13 +2299,12 @@ linux_write_memory (CORE_ADDR memaddr, c
 
   /* Fill start and end extra bytes of buffer with existing memory data.  */
 
-  buffer[0] = ptrace (PTRACE_PEEKTEXT, inferior_pid,
-		      (PTRACE_ARG3_TYPE) addr, 0);
+  buffer[0] = ptrace (PTRACE_PEEKTEXT, pid, (PTRACE_ARG3_TYPE) addr, 0);
 
   if (count > 1)
     {
       buffer[count - 1]
-	= ptrace (PTRACE_PEEKTEXT, inferior_pid,
+	= ptrace (PTRACE_PEEKTEXT, pid,
 		  (PTRACE_ARG3_TYPE) (addr + (count - 1)
 				      * sizeof (PTRACE_XFER_TYPE)),
 		  0);
@@ -2072,7 +2319,7 @@ linux_write_memory (CORE_ADDR memaddr, c
   for (i = 0; i < count; i++, addr += sizeof (PTRACE_XFER_TYPE))
     {
       errno = 0;
-      ptrace (PTRACE_POKETEXT, inferior_pid, (PTRACE_ARG3_TYPE) addr, buffer[i]);
+      ptrace (PTRACE_POKETEXT, pid, (PTRACE_ARG3_TYPE) addr, buffer[i]);
       if (errno)
 	return errno;
     }
@@ -2278,10 +2525,13 @@ static void
 linux_look_up_symbols (void)
 {
 #ifdef USE_THREAD_DB
-  if (thread_db_active)
+  struct process_info *proc = current_process ();
+
+  if (proc->private->thread_db_active)
     return;
 
-  thread_db_active = thread_db_init (!linux_supports_tracefork_flag);
+  proc->private->thread_db_active
+    = thread_db_init (!linux_supports_tracefork_flag);
 #endif
 }
 
@@ -2290,7 +2540,8 @@ linux_request_interrupt (void)
 {
   extern unsigned long signal_pid;
 
-  if (cont_thread != 0 && cont_thread != -1)
+  if (!ptid_equal (cont_thread, null_ptid)
+      && !ptid_equal (cont_thread, minus_one_ptid))
     {
       struct lwp_info *lwp;
       int lwpid;
@@ -2311,8 +2562,9 @@ linux_read_auxv (CORE_ADDR offset, unsig
 {
   char filename[PATH_MAX];
   int fd, n;
+  int pid = lwpid_of (get_thread_lwp (current_inferior));
 
-  snprintf (filename, sizeof filename, "/proc/%ld/auxv", inferior_pid);
+  snprintf (filename, sizeof filename, "/proc/%d/auxv", pid);
 
   fd = open (filename, O_RDONLY);
   if (fd < 0)
@@ -2685,7 +2937,6 @@ initialize_low (void)
 {
   struct sigaction sigchld_action;
   memset (&sigchld_action, 0, sizeof (sigchld_action));
-  thread_db_active = 0;
   set_target_ops (&linux_target_ops);
   set_breakpoint_data (the_low_target.breakpoint,
 		       the_low_target.breakpoint_len);
Index: src/gdb/gdbserver/linux-low.h
===================================================================
--- src.orig/gdb/gdbserver/linux-low.h	2009-03-30 01:20:27.000000000 +0100
+++ src/gdb/gdbserver/linux-low.h	2009-03-30 01:20:28.000000000 +0100
@@ -21,6 +21,8 @@
 #include <thread_db.h>
 #endif
 
+#include "gdb_proc_service.h"
+
 #ifdef HAVE_LINUX_REGSETS
 typedef void (*regset_fill_func) (void *);
 typedef void (*regset_store_func) (const void *);
@@ -41,6 +43,19 @@ struct regset_info
 extern struct regset_info target_regsets[];
 #endif
 
+struct process_info_private
+{
+  /* True if this process has loaded thread_db, and it is active.  */
+  int thread_db_active;
+
+  /* Structure that identifies the child process for the
+     <proc_service.h> interface.  */
+  struct ps_prochandle proc_handle;
+
+  /* Connection to the libthread_db library.  */
+  td_thragent_t *thread_agent;
+};
+
 struct linux_target_ops
 {
   /* Architecture-specific setup.  */
@@ -78,14 +93,14 @@ struct linux_target_ops
 
 extern struct linux_target_ops the_low_target;
 
-#define pid_of(proc) ((proc)->head.id)
-#define lwpid_of(proc) ((proc)->head.id)
+#define pid_of(proc) ptid_get_pid ((proc)->head.id)
+#define lwpid_of(proc) ptid_get_lwp ((proc)->head.id)
 
 #define get_lwp(inf) ((struct lwp_info *)(inf))
 #define get_thread_lwp(thr) (get_lwp (inferior_target_data (thr)))
 #define get_lwp_thread(proc) ((struct thread_info *)			\
 			      find_inferior_id (&all_threads,		\
-						lwpid_of (get_lwp (proc))))
+						get_lwp (proc)->head.id))
 
 struct lwp_info
 {
@@ -106,6 +121,11 @@ struct lwp_info
      event already received in a wait()).  */
   int stopped;
 
+  /* If this flag is set, the lwp is known to be dead already (exit
+     event already received in a wait(), and is cached in
+     status_pending).  */
+  int dead;
+
   /* When stopped is set, the last wait status recorded for this lwp.  */
   int last_status;
 
@@ -150,3 +170,5 @@ void linux_attach_lwp (unsigned long pid
 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);
+
+struct lwp_info *find_lwp_pid (ptid_t ptid);
Index: src/gdb/gdbserver/mem-break.c
===================================================================
--- src.orig/gdb/gdbserver/mem-break.c	2009-03-30 01:19:41.000000000 +0100
+++ src/gdb/gdbserver/mem-break.c	2009-03-30 01:20:28.000000000 +0100
@@ -46,11 +46,10 @@ struct breakpoint
   int (*handler) (CORE_ADDR);
 };
 
-struct breakpoint *breakpoints;
-
 void
 set_breakpoint_at (CORE_ADDR where, int (*handler) (CORE_ADDR))
 {
+  struct process_info *proc = current_process ();
   struct breakpoint *bp;
 
   if (breakpoint_data == NULL)
@@ -67,24 +66,25 @@ set_breakpoint_at (CORE_ADDR where, int 
   bp->pc = where;
   bp->handler = handler;
 
-  bp->next = breakpoints;
-  breakpoints = bp;
+  bp->next = proc->breakpoints;
+  proc->breakpoints = bp;
 }
 
 static void
 delete_breakpoint (struct breakpoint *bp)
 {
+  struct process_info *proc = current_process ();
   struct breakpoint *cur;
 
-  if (breakpoints == bp)
+  if (proc->breakpoints == bp)
     {
-      breakpoints = bp->next;
+      proc->breakpoints = bp->next;
       (*the_target->write_memory) (bp->pc, bp->old_data,
 				   breakpoint_len);
       free (bp);
       return;
     }
-  cur = breakpoints;
+  cur = proc->breakpoints;
   while (cur->next)
     {
       if (cur->next == bp)
@@ -102,7 +102,8 @@ delete_breakpoint (struct breakpoint *bp
 static struct breakpoint *
 find_breakpoint_at (CORE_ADDR where)
 {
-  struct breakpoint *bp = breakpoints;
+  struct process_info *proc = current_process ();
+  struct breakpoint *bp = proc->breakpoints;
 
   while (bp != NULL)
     {
@@ -225,7 +226,8 @@ set_breakpoint_data (const unsigned char
 void
 check_mem_read (CORE_ADDR mem_addr, unsigned char *buf, int mem_len)
 {
-  struct breakpoint *bp = breakpoints;
+  struct process_info *proc = current_process ();
+  struct breakpoint *bp = proc->breakpoints;
   CORE_ADDR mem_end = mem_addr + mem_len;
 
   for (; bp != NULL; bp = bp->next)
@@ -258,7 +260,8 @@ check_mem_read (CORE_ADDR mem_addr, unsi
 void
 check_mem_write (CORE_ADDR mem_addr, unsigned char *buf, int mem_len)
 {
-  struct breakpoint *bp = breakpoints;
+  struct process_info *proc = current_process ();
+  struct breakpoint *bp = proc->breakpoints;
   CORE_ADDR mem_end = mem_addr + mem_len;
 
   for (; bp != NULL; bp = bp->next)
@@ -290,11 +293,29 @@ check_mem_write (CORE_ADDR mem_addr, uns
     }
 }
 
-/* Delete all breakpoints.  */
+/* Delete all breakpoints, and un-insert them from the inferior.  */
 
 void
 delete_all_breakpoints (void)
 {
-  while (breakpoints)
-    delete_breakpoint (breakpoints);
+  struct process_info *proc = current_process ();
+
+  while (proc->breakpoints)
+    delete_breakpoint (proc->breakpoints);
+}
+
+/* Release all breakpoints, but do not try to un-insert them from the
+   inferior.  */
+
+void
+free_all_breakpoints (struct process_info *proc)
+{
+  struct breakpoint *bp;
+
+  while (proc->breakpoints)
+    {
+      bp = proc->breakpoints;
+      proc->breakpoints = bp->next;
+      free (bp);
+    }
 }
Index: src/gdb/gdbserver/proc-service.c
===================================================================
--- src.orig/gdb/gdbserver/proc-service.c	2009-03-30 01:19:42.000000000 +0100
+++ src/gdb/gdbserver/proc-service.c	2009-03-30 01:20:28.000000000 +0100
@@ -102,8 +102,7 @@ ps_lgetregs (gdb_ps_prochandle_t ph, lwp
   struct lwp_info *lwp;
   struct thread_info *reg_inferior, *save_inferior;
 
-  lwp = (struct lwp_info *) find_inferior_id (&all_lwps,
-					      lwpid);
+  lwp = find_lwp_pid (pid_to_ptid (lwpid));
   if (lwp == NULL)
     return PS_ERR;
 
@@ -157,5 +156,5 @@ ps_lsetfpregs (gdb_ps_prochandle_t ph, l
 pid_t
 ps_getpid (gdb_ps_prochandle_t ph)
 {
-  return ph->pid;
+  return pid_of (get_thread_lwp (current_inferior));
 }
Index: src/gdb/gdbserver/remote-utils.c
===================================================================
--- src.orig/gdb/gdbserver/remote-utils.c	2009-03-30 01:20:27.000000000 +0100
+++ src/gdb/gdbserver/remote-utils.c	2009-03-30 01:20:28.000000000 +0100
@@ -79,18 +79,11 @@ typedef int socklen_t;
 /* A cache entry for a successfully looked-up symbol.  */
 struct sym_cache
 {
-  const char *name;
+  char *name;
   CORE_ADDR addr;
   struct sym_cache *next;
 };
 
-/* The symbol cache.  */
-static struct sym_cache *symbol_cache;
-
-/* If this flag has been set, assume cache misses are
-   failures.  */
-int all_symbols_looked_up;
-
 int remote_debug = 0;
 struct ui_file *gdb_stdlog;
 
@@ -317,6 +310,29 @@ fromhex (int a)
   return 0;
 }
 
+static const char hexchars[] = "0123456789abcdef";
+
+static int
+ishex (int ch, int *val)
+{
+  if ((ch >= 'a') && (ch <= 'f'))
+    {
+      *val = ch - 'a' + 10;
+      return 1;
+    }
+  if ((ch >= 'A') && (ch <= 'F'))
+    {
+      *val = ch - 'A' + 10;
+      return 1;
+    }
+  if ((ch >= '0') && (ch <= '9'))
+    {
+      *val = ch - '0';
+      return 1;
+    }
+  return 0;
+}
+
 int
 unhexify (char *bin, const char *hex, int count)
 {
@@ -523,6 +539,105 @@ try_rle (char *buf, int remaining, unsig
   return n + 1;
 }
 
+char *
+unpack_varlen_hex (char *buff,	/* packet to parse */
+		   ULONGEST *result)
+{
+  int nibble;
+  ULONGEST retval = 0;
+
+  while (ishex (*buff, &nibble))
+    {
+      buff++;
+      retval = retval << 4;
+      retval |= nibble & 0x0f;
+    }
+  *result = retval;
+  return buff;
+}
+
+/* Write a PTID to BUF.  Returns BUF+CHARACTERS_WRITTEN.  */
+
+char *
+write_ptid (char *buf, ptid_t ptid)
+{
+  int pid, tid;
+
+  if (multi_process)
+    {
+      pid = ptid_get_pid (ptid);
+      if (pid < 0)
+	buf += sprintf (buf, "p-%x.", -pid);
+      else
+	buf += sprintf (buf, "p%x.", pid);
+    }
+  tid = ptid_get_lwp (ptid);
+  if (tid < 0)
+    buf += sprintf (buf, "-%x", -tid);
+  else
+    buf += sprintf (buf, "%x", tid);
+
+  return buf;
+}
+
+ULONGEST
+hex_or_minus_one (char *buf, char **obuf)
+{
+  ULONGEST ret;
+
+  if (strncmp (buf, "-1", 2) == 0)
+    {
+      ret = (ULONGEST) -1;
+      buf += 2;
+    }
+  else
+    buf = unpack_varlen_hex (buf, &ret);
+
+  if (obuf)
+    *obuf = buf;
+
+  return ret;
+}
+
+/* Extract a PTID from BUF.  If non-null, OBUF is set to the to one
+   passed the last parsed char.  Returns null_ptid on error.  */
+ptid_t
+read_ptid (char *buf, char **obuf)
+{
+  char *p = buf;
+  char *pp;
+  ULONGEST pid = 0, tid = 0;
+
+  if (*p == 'p')
+    {
+      /* Multi-process ptid.  */
+      pp = unpack_varlen_hex (p + 1, &pid);
+      if (*pp != '.')
+	error ("invalid remote ptid: %s\n", p);
+
+      p = pp + 1;
+
+      tid = hex_or_minus_one (p, &pp);
+
+      if (obuf)
+	*obuf = pp;
+      /* TODO, we really need to gdbid vs target thread id after
+	 all.  */
+      return ptid_build (pid, tid, 0);
+    }
+
+  /* No multi-process.  Just a tid.  */
+  tid = hex_or_minus_one (p, &pp);
+
+  /* Since the stub is not sending a process id, then default to
+     what's in the current inferior.  */
+  pid = ptid_get_pid (((struct inferior_list_entry *) current_inferior)->id);
+
+  if (obuf)
+    *obuf = pp;
+  return ptid_build (pid, tid, 0);
+}
+
 /* Send a packet to the remote machine, with error checking.
    The data of the packet is in BUF, and the length of the
    packet is in CNT.  Returns >= 0 on success, -1 otherwise.  */
@@ -957,12 +1072,12 @@ dead_thread_notify (int id)
 }
 
 void
-prepare_resume_reply (char *buf, unsigned long ptid,
+prepare_resume_reply (char *buf, ptid_t ptid,
 		      struct target_waitstatus *status)
 {
   if (debug_threads)
-    fprintf (stderr, "Writing resume reply for %lu:%d\n\n",
-	     ptid, status->kind);
+    fprintf (stderr, "Writing resume reply for %s:%d\n\n",
+	     target_pid_to_str (ptid), status->kind);
 
   switch (status->kind)
     {
@@ -978,7 +1093,7 @@ prepare_resume_reply (char *buf, unsigne
 
 	saved_inferior = current_inferior;
 
-	current_inferior = gdb_id_to_thread (ptid);
+	current_inferior = find_thread_pid (ptid);
 
 	if (the_target->stopped_by_watchpoint != NULL
 	    && (*the_target->stopped_by_watchpoint) ())
@@ -1021,13 +1136,16 @@ prepare_resume_reply (char *buf, unsigne
 	       in GDB will claim this event belongs to inferior_ptid
 	       if we do not specify a thread, and there's no way for
 	       gdbserver to know what inferior_ptid is.  */
-	    if (1 || general_thread != ptid)
+	    if (1 || !ptid_equal (general_thread, ptid))
 	      {
 		/* In non-stop, don't change the general thread behind
 		   GDB's back.  */
 		if (!non_stop)
 		  general_thread = ptid;
-		sprintf (buf, "thread:%lx;", ptid);
+		sprintf (buf, "thread:");
+		buf += strlen (buf);
+		buf = write_ptid (buf, ptid);
+		strcat (buf, ";");
 		buf += strlen (buf);
 	      }
 	  }
@@ -1043,10 +1161,18 @@ prepare_resume_reply (char *buf, unsigne
       }
       break;
     case TARGET_WAITKIND_EXITED:
-      sprintf (buf, "W%02x", status->value.integer);
+      if (multi_process)
+	sprintf (buf, "W%x;process:%x",
+		 status->value.integer, ptid_get_pid (ptid));
+      else
+	sprintf (buf, "W%02x", status->value.integer);
       break;
     case TARGET_WAITKIND_SIGNALLED:
-      sprintf (buf, "X%02x", status->value.sig);
+      if (multi_process)
+	sprintf (buf, "X%x;process:%x",
+		 status->value.sig, ptid_get_pid (ptid));
+      else
+	sprintf (buf, "X%02x", status->value.sig);
       break;
     default:
       error ("unhandled waitkind");
@@ -1174,6 +1300,31 @@ decode_search_memory_packet (const char 
   return 0;
 }
 
+static void
+free_sym_cache (struct sym_cache *sym)
+{
+  if (sym != NULL)
+    {
+      free (sym->name);
+      free (sym);
+    }
+}
+
+void
+clear_symbol_cache (struct sym_cache **symcache_p)
+{
+  struct sym_cache *sym, *next;
+
+  /* Check the cache first.  */
+  for (sym = *symcache_p; sym; sym = next)
+    {
+      next = sym->next;
+      free_sym_cache (sym);
+    }
+
+  *symcache_p = NULL;
+}
+
 /* Ask GDB for the address of NAME, and return it in ADDRP if found.
    Returns 1 if the symbol is found, 0 if it is not, -1 on error.  */
 
@@ -1183,9 +1334,12 @@ look_up_one_symbol (const char *name, CO
   char own_buf[266], *p, *q;
   int len;
   struct sym_cache *sym;
+  struct process_info *proc;
+
+  proc = current_process ();
 
   /* Check the cache first.  */
-  for (sym = symbol_cache; sym; sym = sym->next)
+  for (sym = proc->symbol_cache; sym; sym = sym->next)
     if (strcmp (name, sym->name) == 0)
       {
 	*addrp = sym->addr;
@@ -1197,7 +1351,7 @@ look_up_one_symbol (const char *name, CO
      in any libraries loaded after that point, only in symbols in
      libpthread.so.  It might not be an appropriate time to look
      up a symbol, e.g. while we're trying to fetch registers.  */
-  if (all_symbols_looked_up)
+  if (proc->all_symbols_looked_up)
     return 0;
 
   /* Send the request.  */
@@ -1257,8 +1411,8 @@ look_up_one_symbol (const char *name, CO
   sym = xmalloc (sizeof (*sym));
   sym->name = xstrdup (name);
   sym->addr = *addrp;
-  sym->next = symbol_cache;
-  symbol_cache = sym;
+  sym->next = proc->symbol_cache;
+  proc->symbol_cache = sym;
 
   return 1;
 }
Index: src/gdb/gdbserver/server.c
===================================================================
--- src.orig/gdb/gdbserver/server.c	2009-03-30 01:20:27.000000000 +0100
+++ src/gdb/gdbserver/server.c	2009-03-30 01:20:28.000000000 +0100
@@ -32,17 +32,17 @@
 #include <malloc.h>
 #endif
 
-unsigned long cont_thread;
-unsigned long general_thread;
-unsigned long step_thread;
+ptid_t cont_thread;
+ptid_t general_thread;
+ptid_t step_thread;
 
 int server_waiting;
 
 static int extended_protocol;
-static int attached;
 static int response_needed;
 static int exit_requested;
 
+int multi_process;
 int non_stop;
 
 static char **program_argv, **wrapper_argv;
@@ -90,7 +90,7 @@ int disable_packet_qfThreadInfo;
 
 /* Last status reported to GDB.  */
 static struct target_waitstatus last_status;
-static unsigned long last_ptid;
+static ptid_t last_ptid;
 
 static char *own_buf;
 static unsigned char *mem_buf;
@@ -104,7 +104,7 @@ struct vstop_notif
   struct vstop_notif *next;
 
   /* Thread or process that got the event.  */
-  unsigned long ptid;
+  ptid_t ptid;
 
   /* Event info.  */
   struct target_waitstatus status;
@@ -116,7 +116,7 @@ static struct vstop_notif *notif_queue =
 /* Put a stop reply to the stop reply queue.  */
 
 static void
-queue_stop_reply (unsigned long ptid, struct target_waitstatus *status)
+queue_stop_reply (ptid_t ptid, struct target_waitstatus *status)
 {
   struct vstop_notif *new_notif;
 
@@ -153,7 +153,7 @@ queue_stop_reply (unsigned long ptid, st
    we aren't sending one yet.  */
 
 void
-push_event (unsigned long ptid, struct target_waitstatus *status)
+push_event (ptid_t ptid, struct target_waitstatus *status)
 {
   queue_stop_reply (ptid, status);
 
@@ -170,19 +170,30 @@ push_event (unsigned long ptid, struct t
     }
 }
 
-/* Get rid of the currently pending stop replies.  */
+/* Get rid of the currently pending stop replies for PID.  If PID is
+   -1, then apply to all processes.  */
 
 static void
-discard_queued_stop_replies (void)
+discard_queued_stop_replies (int pid)
 {
-  struct vstop_notif *next;
+  struct vstop_notif *prev = NULL, *reply, *next;
 
-  while (notif_queue)
+  for (reply = notif_queue; reply; reply = next)
     {
-      next = notif_queue->next;
-      notif_queue = next;
+      next = reply->next;
+
+      if (pid == -1
+	  || ptid_get_pid (reply->ptid) == pid)
+	{
+	  if (reply == notif_queue)
+	    notif_queue = next;
+	  else
+	    prev->next = reply->next;
 
-      free (next);
+	  free (reply);
+	}
+      else
+	prev = reply;
     }
 }
 
@@ -209,7 +220,6 @@ static int
 start_inferior (char **argv)
 {
   char **new_argv = argv;
-  attached = 0;
 
   if (wrapper_argv != NULL)
     {
@@ -253,13 +263,13 @@ start_inferior (char **argv)
   if (wrapper_argv != NULL)
     {
       struct thread_resume resume_info;
-      unsigned long ptid;
+      ptid_t ptid;
 
-      resume_info.thread = -1;
+      resume_info.thread = pid_to_ptid (signal_pid);
       resume_info.kind = resume_continue;
       resume_info.sig = 0;
 
-      ptid = mywait (&last_status, 0, 0);
+      ptid = mywait (pid_to_ptid (signal_pid), &last_status, 0, 0);
 
       if (last_status.kind != TARGET_WAITKIND_STOPPED)
 	return signal_pid;
@@ -268,7 +278,7 @@ start_inferior (char **argv)
 	{
 	  (*the_target->resume) (&resume_info, 1);
 
- 	  mywait (&last_status, 0, 0);
+ 	  mywait (pid_to_ptid (signal_pid), &last_status, 0, 0);
 	  if (last_status.kind != TARGET_WAITKIND_STOPPED)
 	    return signal_pid;
 	}
@@ -279,7 +289,7 @@ start_inferior (char **argv)
 
   /* Wait till we are at 1st instruction in program, return new pid
      (assuming success).  */
-  last_ptid = mywait (&last_status, 0, 0);
+  last_ptid = mywait (pid_to_ptid (signal_pid), &last_status, 0, 0);
 
   return signal_pid;
 }
@@ -293,8 +303,6 @@ attach_inferior (int pid)
   if (myattach (pid) != 0)
     return -1;
 
-  attached = 1;
-
   fprintf (stderr, "Attached; pid = %d\n", pid);
   fflush (stderr);
 
@@ -305,7 +313,7 @@ attach_inferior (int pid)
 
   if (!non_stop)
     {
-      last_ptid = mywait (&last_status, 0, 0);
+      last_ptid = mywait (pid_to_ptid (pid), &last_status, 0, 0);
 
       /* GDB knows to ignore the first SIGSTOP after attaching to a running
 	 process using the "attach" command, but this is different; it's
@@ -656,10 +664,11 @@ handle_query (char *own_buf, int packet_
   /* Reply the current thread id.  */
   if (strcmp ("qC", own_buf) == 0 && !disable_packet_qC)
     {
-      unsigned long gdb_id;
+      ptid_t gdb_id;
       require_running (own_buf);
 
-      if (general_thread != 0 && general_thread != -1)
+      if (!ptid_equal (general_thread, null_ptid)
+	  && !ptid_equal (general_thread, minus_one_ptid))
 	gdb_id = general_thread;
       else
 	{
@@ -667,7 +676,9 @@ handle_query (char *own_buf, int packet_
 	  gdb_id = thread_to_gdb_id ((struct thread_info *)thread_ptr);
 	}
 
-      sprintf (own_buf, "QC%lx", gdb_id);
+      sprintf (own_buf, "QC");
+      own_buf += 2;
+      own_buf = write_ptid (own_buf, gdb_id);
       return;
     }
 
@@ -684,21 +695,28 @@ handle_query (char *own_buf, int packet_
     {
       if (strcmp ("qfThreadInfo", own_buf) == 0)
 	{
+	  ptid_t gdb_id;
+
 	  require_running (own_buf);
 	  thread_ptr = all_threads.head;
-	  sprintf (own_buf, "m%x",
-		   thread_to_gdb_id ((struct thread_info *)thread_ptr));
+
+	  *own_buf++ = 'm';
+	  gdb_id = thread_to_gdb_id ((struct thread_info *)thread_ptr);
+	  write_ptid (own_buf, gdb_id);
 	  thread_ptr = thread_ptr->next;
 	  return;
 	}
 
       if (strcmp ("qsThreadInfo", own_buf) == 0)
 	{
+	  ptid_t gdb_id;
+
 	  require_running (own_buf);
 	  if (thread_ptr != NULL)
 	    {
-	      sprintf (own_buf, "m%x",
-		       thread_to_gdb_id ((struct thread_info *)thread_ptr));
+	      *own_buf++ = 'm';
+	      gdb_id = thread_to_gdb_id ((struct thread_info *)thread_ptr);
+	      write_ptid (own_buf, gdb_id);
 	      thread_ptr = thread_ptr->next;
 	      return;
 	    }
@@ -1046,6 +1064,21 @@ handle_query (char *own_buf, int packet_
   if (strncmp ("qSupported", own_buf, 10) == 0
       && (own_buf[10] == ':' || own_buf[10] == '\0'))
     {
+      char *p = &own_buf[10];
+
+      /* Process each feature being provided by GDB.  The first
+	 feature will follow a ':', and latter features will follow
+	 ';'.  */
+      if (*p == ':')
+	for (p = strtok (p + 1, ";");
+	     p != NULL;
+	     p = strtok (NULL, ";"))
+	  {
+	    /* Record if GDB knows about multiprocess support.  */
+	    if (strcmp (p, "multiprocess+") == 0)
+	      multi_process = 1;
+	  }
+
       sprintf (own_buf, "PacketSize=%x;QPassSignals+", PBUFSIZ - 1);
 
       /* We do not have any hook to indicate whether the target backend
@@ -1073,6 +1106,8 @@ handle_query (char *own_buf, int packet_
       if (the_target->qxfer_osdata != NULL)
 	strcat (own_buf, ";qXfer:osdata:read+");
 
+      strcat (own_buf, ";multiprocess+");
+
       if (target_supports_non_stop ())
 	strcat (own_buf, ";QNonStop+");
 
@@ -1086,7 +1121,7 @@ handle_query (char *own_buf, int packet_
       char *p = own_buf + 12;
       CORE_ADDR parts[2], address = 0;
       int i, err;
-      unsigned long ptid;
+      ptid_t ptid;
 
       require_running (own_buf);
 
@@ -1111,7 +1146,7 @@ handle_query (char *own_buf, int packet_
 	    }
 
 	  if (i == 0)
-	    ptid = strtoul (p, NULL, 16);
+	    ptid = read_ptid (p, NULL);
 	  else
 	    decode_address (&parts[i - 1], p, len);
 	  p = p2;
@@ -1121,7 +1156,7 @@ handle_query (char *own_buf, int packet_
 	err = 1;
       else
 	{
-	  struct thread_info *thread = gdb_id_to_thread (ptid);
+	  struct thread_info *thread = find_thread_pid (ptid);
 
 	  if (thread == NULL)
 	    err = 2;
@@ -1208,10 +1243,30 @@ handle_query (char *own_buf, int packet_
       return;
     }
 
-  if (strcmp (own_buf, "qAttached") == 0)
+  if (strcmp (own_buf, "qAttached") == 0
+      || strncmp (own_buf, "qAttached:", sizeof ("qAttached:") - 1) == 0)
     {
-      require_running (own_buf);
-      strcpy (own_buf, attached ? "1" : "0");
+      struct process_info *process;
+
+      if (own_buf[sizeof ("qAttached") - 1])
+	{
+	  int pid = strtoul (own_buf + sizeof ("qAttached:") - 1, NULL, 16);
+	  process = (struct process_info *)
+	    find_inferior_id (&all_processes, pid_to_ptid (pid));
+	}
+      else
+	{
+	  require_running (own_buf);
+	  process = current_process ();
+	}
+
+      if (process == NULL)
+	{
+	  write_enn (own_buf);
+	  return;
+	}
+
+      strcpy (own_buf, process->attached ? "1" : "0");
       return;
     }
 
@@ -1227,7 +1282,7 @@ handle_v_cont (char *own_buf)
   char *p, *q;
   int n = 0, i = 0;
   struct thread_resume *resume_info;
-  struct thread_resume default_action = {0};
+  struct thread_resume default_action = {{0}};
 
   /* Count the number of semicolons in the packet.  There should be one
      for every action.  */
@@ -1277,7 +1332,7 @@ handle_v_cont (char *own_buf)
 
       if (p[0] == 0)
 	{
-	  resume_info[i].thread = -1;
+	  resume_info[i].thread = minus_one_ptid;
 	  default_action = resume_info[i];
 
 	  /* Note: we don't increment i here, we'll overwrite this entry
@@ -1285,8 +1340,7 @@ handle_v_cont (char *own_buf)
 	}
       else if (p[0] == ':')
 	{
-	  unsigned int gdb_id = strtoul (p + 1, &q, 16);
-	  unsigned long thread_id;
+	  ptid_t ptid = read_ptid (p + 1, &q);
 
 	  if (p == q)
 	    goto err;
@@ -1294,11 +1348,7 @@ handle_v_cont (char *own_buf)
 	  if (p[0] != ';' && p[0] != 0)
 	    goto err;
 
-	  thread_id = gdb_id_to_thread_id (gdb_id);
-	  if (thread_id)
-	    resume_info[i].thread = thread_id;
-	  else
-	    goto err;
+	  resume_info[i].thread = ptid;
 
 	  i++;
 	}
@@ -1309,11 +1359,11 @@ handle_v_cont (char *own_buf)
 
   /* Still used in occasional places in the backend.  */
   if (n == 1
-      && resume_info[0].thread != -1
+      && !ptid_equal (resume_info[0].thread, minus_one_ptid)
       && resume_info[0].kind != resume_stop)
     cont_thread = resume_info[0].thread;
   else
-    cont_thread = -1;
+    cont_thread = minus_one_ptid;
   set_desired_inferior (0);
 
   if (!non_stop)
@@ -1327,7 +1377,7 @@ handle_v_cont (char *own_buf)
     write_ok (own_buf);
   else
     {
-      last_ptid = mywait (&last_status, 0, 1);
+      last_ptid = mywait (minus_one_ptid, &last_status, 0, 1);
       prepare_resume_reply (own_buf, last_ptid, &last_status);
       disable_async_io ();
     }
@@ -1462,6 +1512,30 @@ handle_v_run (char *own_buf)
     }
 }
 
+/* Attach to a new program.  Return 1 if successful, 0 if failure.  */
+int
+handle_v_kill (char *own_buf)
+{
+  int pid;
+  char *p = &own_buf[6];
+
+  pid = strtol (p, NULL, 16);
+  if (pid != 0 && kill_inferior (pid) == 0)
+    {
+      last_status.kind = TARGET_WAITKIND_SIGNALLED;
+      last_status.value.sig = TARGET_SIGNAL_KILL;
+      last_ptid = pid_to_ptid (pid);
+      discard_queued_stop_replies (pid);
+      write_ok (own_buf);
+      return 1;
+    }
+  else
+    {
+      write_enn (own_buf);
+      return 0;
+    }
+}
+
 /* Handle a 'vStopped' packet.  */
 static void
 handle_v_stopped (char *own_buf)
@@ -1473,7 +1547,8 @@ handle_v_stopped (char *own_buf)
       struct vstop_notif *head;
 
       if (remote_debug)
-	fprintf (stderr, "vStopped: acking %ld\n", notif_queue->ptid);
+	fprintf (stderr, "vStopped: acking %s\n",
+		 target_pid_to_str (notif_queue->ptid));
 
       head = notif_queue;
       notif_queue = notif_queue->next;
@@ -1510,7 +1585,7 @@ handle_v_requests (char *own_buf, int pa
 
   if (strncmp (own_buf, "vAttach;", 8) == 0)
     {
-      if (target_running ())
+      if (!multi_process && target_running ())
 	{
 	  fprintf (stderr, "Already debugging a process\n");
 	  write_enn (own_buf);
@@ -1522,7 +1597,7 @@ handle_v_requests (char *own_buf, int pa
 
   if (strncmp (own_buf, "vRun;", 5) == 0)
     {
-      if (target_running ())
+      if (!multi_process && target_running ())
 	{
 	  fprintf (stderr, "Already debugging a process\n");
 	  write_enn (own_buf);
@@ -1532,6 +1607,18 @@ handle_v_requests (char *own_buf, int pa
       return;
     }
 
+  if (strncmp (own_buf, "vKill;", 6) == 0)
+    {
+      if (!target_running ())
+	{
+	  fprintf (stderr, "No process to kill\n");
+	  write_enn (own_buf);
+	  return;
+	}
+      handle_v_kill (own_buf);
+      return;
+    }
+
   if (strncmp (own_buf, "vStopped", 8) == 0)
     {
       handle_v_stopped (own_buf);
@@ -1556,7 +1643,8 @@ myresume (char *own_buf, int step, int s
 
   set_desired_inferior (0);
 
-  valid_cont_thread = (cont_thread != 0 && cont_thread != -1);
+  valid_cont_thread = (!ptid_equal (cont_thread, null_ptid)
+			 && !ptid_equal (cont_thread, minus_one_ptid));
 
   if (step || sig || valid_cont_thread)
     {
@@ -1572,7 +1660,7 @@ myresume (char *own_buf, int step, int s
 
   if (!valid_cont_thread)
     {
-      resume_info[n].thread = -1;
+      resume_info[n].thread = minus_one_ptid;
       resume_info[n].kind = resume_continue;
       resume_info[n].sig = 0;
       n++;
@@ -1587,7 +1675,7 @@ myresume (char *own_buf, int step, int s
     write_ok (own_buf);
   else
     {
-      last_ptid = mywait (&last_status, 0, 1);
+      last_ptid = mywait (minus_one_ptid, &last_status, 0, 1);
       prepare_resume_reply (own_buf, last_ptid, &last_status);
       disable_async_io ();
     }
@@ -1596,16 +1684,24 @@ myresume (char *own_buf, int step, int s
 /* Callback for for_each_inferior.  Make a new stop reply for each
    stopped thread.  */
 
-static void
-queue_stop_reply_callback (struct inferior_list_entry *entry)
+static int
+queue_stop_reply_callback (struct inferior_list_entry *entry, void *arg)
 {
-  struct target_waitstatus status;
+  int pid = * (int *) arg;
 
-  status.kind = TARGET_WAITKIND_STOPPED;
-  status.value.sig = TARGET_SIGNAL_TRAP;
+  if (pid == -1
+      || ptid_get_pid (entry->id) == pid)
+    {
+      struct target_waitstatus status;
+
+      status.kind = TARGET_WAITKIND_STOPPED;
+      status.value.sig = TARGET_SIGNAL_TRAP;
+
+      /* Pass the last stop reply back to GDB, but don't notify.  */
+      queue_stop_reply (entry->id, &status);
+    }
 
-  /* Pass the last stop reply back to GDB, but don't notify.  */
-  queue_stop_reply (entry->id, &status);
+  return 0;
 }
 
 /* Status handler for the '?' packet.  */
@@ -1623,8 +1719,9 @@ handle_status (char *own_buf)
 
   if (non_stop)
     {
-      discard_queued_stop_replies ();
-      for_each_inferior (&all_threads, queue_stop_reply_callback);
+      int pid = -1;
+      discard_queued_stop_replies (pid);
+      find_inferior (&all_threads, queue_stop_reply_callback, &pid);
 
       /* The first is sent immediatly.  OK is sent if there is no
 	 stopped thread, which is the same handling of the vStopped
@@ -1690,6 +1787,52 @@ gdbserver_show_disableable (FILE *stream
       break;					\
     }
 
+static int
+first_thread_of (struct inferior_list_entry *entry, void *args)
+{
+  int pid = * (int *) args;
+
+  if (ptid_get_pid (entry->id) == pid)
+    return 1;
+
+  return 0;
+}
+
+static void
+kill_inferior_callback (struct inferior_list_entry *entry)
+{
+  struct process_info *process = (struct process_info *) entry;
+  int pid = ptid_get_pid (process->head.id);
+
+  kill_inferior (pid);
+  discard_queued_stop_replies (pid);
+}
+
+static void
+detach_or_kill_inferior_callback (struct inferior_list_entry *entry)
+{
+  struct process_info *process = (struct process_info *) entry;
+  int pid = ptid_get_pid (process->head.id);
+
+  if (process->attached)
+    detach_inferior (pid);
+  else
+    kill_inferior (pid);
+
+  discard_queued_stop_replies (pid);
+}
+
+static void
+join_inferiors_callback (struct inferior_list_entry *entry)
+{
+  struct process_info *process = (struct process_info *) entry;
+
+  /* If we are attached, then we can exit.  Otherwise, we need to hang
+     around doing nothing, until the child is gone.  */
+  if (!process->attached)
+    join_inferior (ptid_get_pid (process->head.id));
+}
+
 int
 main (int argc, char *argv[])
 {
@@ -1827,6 +1970,7 @@ main (int argc, char *argv[])
       exit (1);
     }
 
+  initialize_inferiors ();
   initialize_async_io ();
   initialize_low ();
 
@@ -1861,7 +2005,7 @@ main (int argc, char *argv[])
     {
       last_status.kind = TARGET_WAITKIND_EXITED;
       last_status.value.integer = 0;
-      last_ptid = -1;
+      last_ptid = minus_one_ptid;
     }
 
   /* Don't report shared library events on the initial connection,
@@ -1871,8 +2015,9 @@ main (int argc, char *argv[])
 
   if (setjmp (toplevel))
     {
-      fprintf (stderr, "Killing inferior\n");
-      kill_inferior ();
+      fprintf (stderr, "Killing all inferiors\n");
+      for_each_inferior (&all_processes,
+			 kill_inferior_callback);
       exit (1);
     }
 
@@ -1891,6 +2036,7 @@ main (int argc, char *argv[])
   while (1)
     {
       noack_mode = 0;
+      multi_process = 0;
       non_stop = 0;
 
       remote_open (port);
@@ -1916,10 +2062,8 @@ main (int argc, char *argv[])
 
       if (exit_requested)
 	{
-	  if (attached)
-	    detach_inferior ();
-	  else
-	    kill_inferior ();
+	  for_each_inferior (&all_processes,
+			     detach_or_kill_inferior_callback);
 	  exit (0);
 	}
       else
@@ -1941,6 +2085,7 @@ process_serial_event (void)
   int signal;
   unsigned int len;
   CORE_ADDR mem_addr;
+  int pid;
 
   /* Used to decide when gdbserver should exit in
      multi-mode/remote.  */
@@ -1977,12 +2122,21 @@ process_serial_event (void)
 	      break;
 	    case 'D':
 	      require_running (own_buf);
-	      fprintf (stderr, "Detaching from inferior\n");
-	      if (detach_inferior () != 0)
+
+	      if (multi_process)
+		{
+		  i++; /* skip ';' */
+		  pid = strtol (&own_buf[i], NULL, 16);
+		}
+	      else
+		pid = ptid_get_pid (((struct inferior_list_entry *)current_inferior)->id);
+
+	      fprintf (stderr, "Detaching from process %d\n", pid);
+	      if (detach_inferior (pid) != 0)
 		write_enn (own_buf);
 	      else
 		{
-		  discard_queued_stop_replies ();
+		  discard_queued_stop_replies (pid);
 		  write_ok (own_buf);
 
 		  if (extended_protocol)
@@ -1990,7 +2144,7 @@ process_serial_event (void)
 		      /* Treat this like a normal program exit.  */
 		      last_status.kind = TARGET_WAITKIND_EXITED;
 		      last_status.value.integer = 0;
-		      last_ptid = signal_pid;
+		      last_ptid = pid_to_ptid (pid);
 
 		      current_inferior = NULL;
 		    }
@@ -2002,9 +2156,8 @@ process_serial_event (void)
 		      /* If we are attached, then we can exit.  Otherwise, we
 			 need to hang around doing nothing, until the child
 			 is gone.  */
-		      if (!attached)
-			join_inferior ();
-
+		      for_each_inferior (&all_processes,
+					 join_inferiors_callback);
 		      exit (0);
 		    }
 		}
@@ -2019,16 +2172,38 @@ process_serial_event (void)
 	    case 'H':
 	      if (own_buf[1] == 'c' || own_buf[1] == 'g' || own_buf[1] == 's')
 		{
-		  unsigned long gdb_id, thread_id;
+		  ptid_t gdb_id, thread_id;
+		  int pid;
 
 		  require_running (own_buf);
-		  gdb_id = strtoul (&own_buf[2], NULL, 16);
-		  if (gdb_id == 0 || gdb_id == -1)
-		    thread_id = gdb_id;
+
+		  gdb_id = read_ptid (&own_buf[2], NULL);
+
+		  pid = ptid_get_pid (gdb_id);
+
+		  if (ptid_equal (gdb_id, null_ptid)
+		      || ptid_equal (gdb_id, minus_one_ptid))
+		    thread_id = null_ptid;
+		  else if (pid != 0
+			   && ptid_equal (pid_to_ptid (pid),
+					  gdb_id))
+		    {
+		      struct thread_info *thread =
+			(struct thread_info *) find_inferior (&all_threads,
+							      first_thread_of,
+							      &pid);
+		      if (!thread)
+			{
+			  write_enn (own_buf);
+			  break;
+			}
+
+		      thread_id = ((struct inferior_list_entry *)thread)->id;
+		    }
 		  else
 		    {
 		      thread_id = gdb_id_to_thread_id (gdb_id);
-		      if (thread_id == 0)
+		      if (ptid_equal (thread_id, null_ptid))
 			{
 			  write_enn (own_buf);
 			  break;
@@ -2037,7 +2212,7 @@ process_serial_event (void)
 
 		  if (own_buf[1] == 'g')
 		    {
-		      if (thread_id == 0)
+		      if (ptid_equal (thread_id, null_ptid))
 			{
 			  /* GDB is telling us to choose any thread.
 			     Check if the currently selected thread is
@@ -2200,9 +2375,8 @@ process_serial_event (void)
 		   can't reply to it, either.  */
 		return;
 
-	      fprintf (stderr, "Killing inferior\n");
-	      kill_inferior ();
-	      discard_queued_stop_replies ();
+	      fprintf (stderr, "Killing all inferiors\n");
+	      for_each_inferior (&all_processes, kill_inferior_callback);
 
 	      /* When using the extended protocol, we wait with no
 		 program running.  The traditional protocol will exit
@@ -2220,12 +2394,13 @@ process_serial_event (void)
 		}
 	    case 'T':
 	      {
-		unsigned long gdb_id, thread_id;
+		ptid_t gdb_id, thread_id;
 
 		require_running (own_buf);
-		gdb_id = strtoul (&own_buf[1], NULL, 16);
+
+		gdb_id = read_ptid (&own_buf[1], NULL);
 		thread_id = gdb_id_to_thread_id (gdb_id);
-		if (thread_id == 0)
+		if (ptid_equal (thread_id, null_ptid))
 		  {
 		    write_enn (own_buf);
 		    break;
@@ -2245,10 +2420,8 @@ process_serial_event (void)
 	      if (extended_protocol)
 		{
 		  if (target_running ())
-		    {
-		      kill_inferior ();
-		      discard_queued_stop_replies ();
-		    }
+		    for_each_inferior (&all_processes,
+				       kill_inferior_callback);
 		  fprintf (stderr, "GDBserver restarting\n");
 
 		  /* Wait till we are at 1st instruction in prog.  */
@@ -2327,7 +2500,8 @@ handle_target_event (int err, gdb_client
   if (debug_threads)
     fprintf (stderr, "handling possible target event\n");
 
-  last_ptid = mywait (&last_status, TARGET_WNOHANG, 1);
+  last_ptid = mywait (minus_one_ptid, &last_status,
+		      TARGET_WNOHANG, 1);
 
   if (last_status.kind != TARGET_WAITKIND_IGNORE)
     {
Index: src/gdb/gdbserver/server.h
===================================================================
--- src.orig/gdb/gdbserver/server.h	2009-03-30 01:20:27.000000000 +0100
+++ src/gdb/gdbserver/server.h	2009-03-30 01:20:28.000000000 +0100
@@ -85,6 +85,70 @@ typedef unsigned char gdb_byte;
    least the size of a (void *).  */
 typedef long long CORE_ADDR;
 
+typedef unsigned long long ULONGEST;
+
+/* The ptid struct is a collection of the various "ids" necessary
+   for identifying the inferior.  This consists of the process id
+   (pid), thread id (tid), and other fields necessary for uniquely
+   identifying the inferior process/thread being debugged.  When
+   manipulating ptids, the constructors, accessors, and predicate
+   declared in server.h should be used.  These are as follows:
+
+      ptid_build	- Make a new ptid from a pid, lwp, and tid.
+      pid_to_ptid	- Make a new ptid from just a pid.
+      ptid_get_pid	- Fetch the pid component of a ptid.
+      ptid_get_lwp	- Fetch the lwp component of a ptid.
+      ptid_get_tid	- Fetch the tid component of a ptid.
+      ptid_equal	- Test to see if two ptids are equal.
+
+   Please do NOT access the struct ptid members directly (except, of
+   course, in the implementation of the above ptid manipulation
+   functions).  */
+
+struct ptid
+  {
+    /* Process id */
+    int pid;
+
+    /* Lightweight process id */
+    long lwp;
+
+    /* Thread id */
+    long tid;
+  };
+
+typedef struct ptid ptid_t;
+
+/* The -1 ptid, often used to indicate either an error condition or a
+   "don't care" condition, i.e, "run all threads".  */
+extern ptid_t minus_one_ptid;
+
+/* The null or zero ptid, often used to indicate no process.  */
+extern ptid_t null_ptid;
+
+/* Attempt to find and return an existing ptid with the given PID,
+   LWP, and TID components.  If none exists, create a new one and
+   return that.  */
+ptid_t ptid_build (int pid, long lwp, long tid);
+
+/* Create a ptid from just a pid.  */
+ptid_t pid_to_ptid (int pid);
+
+/* Fetch the pid (process id) component from a ptid.  */
+int ptid_get_pid (ptid_t ptid);
+
+/* Fetch the lwp (lightweight process) component from a ptid.  */
+long ptid_get_lwp (ptid_t ptid);
+
+/* Fetch the tid (thread id) component from a ptid.  */
+long ptid_get_tid (ptid_t ptid);
+
+/* Compare two ptids to see if they are equal.  */
+extern int ptid_equal (ptid_t p1, ptid_t p2);
+
+/* Return true if this ptid represents a process id.  */
+extern int ptid_is_pid (ptid_t ptid);
+
 /* Generic information for tracking a list of ``inferiors'' - threads,
    processes, etc.  */
 struct inferior_list
@@ -94,7 +158,7 @@ struct inferior_list
 };
 struct inferior_list_entry
 {
-  unsigned long id;
+  ptid_t id;
   struct inferior_list_entry *next;
 };
 
@@ -108,6 +172,36 @@ struct dll_info
   CORE_ADDR base_addr;
 };
 
+struct sym_cache;
+struct breakpoint;
+struct process_info_private;
+
+struct process_info
+{
+  struct inferior_list_entry head;
+
+  int attached;
+
+  /* The symbol cache.  */
+  struct sym_cache *symbol_cache;
+
+  /* If this flag has been set, assume symbol cache misses are
+     failures.  */
+  int all_symbols_looked_up;
+
+  /* The list of memory breakpoints.  */
+  struct breakpoint *breakpoints;
+
+  /* Private target data.  */
+  struct process_info_private *private;
+};
+
+/* Return a pointer to the process that corresponds to the current
+   thread (current_inferior).  It is an error to call this if there is
+   no current thread selected.  */
+
+struct process_info *current_process (void);
+
 #include "regcache.h"
 #include "gdb/signals.h"
 #include "gdb_signals.h"
@@ -120,22 +214,33 @@ void initialize_low ();
 
 /* From inferiors.c.  */
 
+extern struct inferior_list all_processes;
 extern struct inferior_list all_threads;
 extern struct inferior_list all_dlls;
 extern int dlls_changed;
 
+void initialize_inferiors (void);
+
 void add_inferior_to_list (struct inferior_list *list,
 			   struct inferior_list_entry *new_inferior);
 void for_each_inferior (struct inferior_list *list,
 			void (*action) (struct inferior_list_entry *));
+
 extern struct thread_info *current_inferior;
 void remove_inferior (struct inferior_list *list,
 		      struct inferior_list_entry *entry);
 void remove_thread (struct thread_info *thread);
-void add_thread (unsigned long thread_id, void *target_data, unsigned int);
-unsigned int thread_id_to_gdb_id (unsigned long);
-unsigned int thread_to_gdb_id (struct thread_info *);
-unsigned long gdb_id_to_thread_id (unsigned int);
+void add_thread (ptid_t ptid, void *target_data);
+
+struct process_info *add_process (int pid, int attached);
+void remove_process (struct process_info *process);
+struct process_info *find_process_pid (int pid);
+
+struct thread_info *find_thread_pid (ptid_t ptid);
+
+ptid_t thread_id_to_gdb_id (ptid_t);
+ptid_t thread_to_gdb_id (struct thread_info *);
+ptid_t gdb_id_to_thread_id (ptid_t);
 struct thread_info *gdb_id_to_thread (unsigned int);
 void clear_inferiors (void);
 struct inferior_list_entry *find_inferior
@@ -144,7 +249,7 @@ struct inferior_list_entry *find_inferio
 		   void *),
       void *arg);
 struct inferior_list_entry *find_inferior_id (struct inferior_list *list,
-					      unsigned long id);
+					      ptid_t id);
 void *inferior_target_data (struct thread_info *);
 void set_inferior_target_data (struct thread_info *, void *);
 void *inferior_regcache_data (struct thread_info *);
@@ -157,9 +262,9 @@ void unloaded_dll (const char *name, COR
 
 /* Public variables in server.c */
 
-extern unsigned long cont_thread;
-extern unsigned long general_thread;
-extern unsigned long step_thread;
+extern ptid_t cont_thread;
+extern ptid_t general_thread;
+extern ptid_t step_thread;
 
 extern int server_waiting;
 extern int debug_threads;
@@ -172,6 +277,7 @@ extern int disable_packet_Tthread;
 extern int disable_packet_qC;
 extern int disable_packet_qfThreadInfo;
 
+extern int multi_process;
 extern int non_stop;
 
 /* Functions from event-loop.c.  */
@@ -189,7 +295,7 @@ extern void start_event_loop (void);
 extern void handle_serial_event (int err, gdb_client_data client_data);
 extern void handle_target_event (int err, gdb_client_data client_data);
 
-extern void push_event (unsigned long ptid, struct target_waitstatus *status);
+extern void push_event (ptid_t ptid, struct target_waitstatus *status);
 
 /* Functions from hostio.c.  */
 extern int handle_vFile (char *, int, int *);
@@ -204,6 +310,9 @@ extern int all_symbols_looked_up;
 extern int noack_mode;
 extern int transport_is_reliable;
 
+ptid_t read_ptid (char *buf, char **obuf);
+char *write_ptid (char *buf, ptid_t ptid);
+
 int putpkt (char *buf);
 int putpkt_binary (char *buf, int len);
 int putpkt_notif (char *buf);
@@ -220,7 +329,7 @@ void convert_ascii_to_int (char *from, u
 void convert_int_to_ascii (unsigned char *from, char *to, int n);
 void new_thread_notify (int id);
 void dead_thread_notify (int id);
-void prepare_resume_reply (char *buf, unsigned long thread_id,
+void prepare_resume_reply (char *buf, ptid_t ptid,
 			   struct target_waitstatus *status);
 
 const char *decode_address_to_semicolon (CORE_ADDR *addrp, const char *start);
@@ -245,6 +354,7 @@ int remote_escape_output (const gdb_byte
 			  gdb_byte *out_buf, int *out_len,
 			  int out_maxlen);
 
+void clear_symbol_cache (struct sym_cache **symcache_p);
 int look_up_one_symbol (const char *name, CORE_ADDR *addrp);
 
 void monitor_output (const char *msg);
Index: src/gdb/gdbserver/target.c
===================================================================
--- src.orig/gdb/gdbserver/target.c	2009-03-30 01:20:27.000000000 +0100
+++ src/gdb/gdbserver/target.c	2009-03-30 01:20:28.000000000 +0100
@@ -29,10 +29,7 @@ set_desired_inferior (int use_general)
   struct thread_info *found;
 
   if (use_general == 1)
-    {
-      found = (struct thread_info *) find_inferior_id (&all_threads,
-						       general_thread);
-    }
+    found = find_thread_pid (general_thread);
   else
     {
       found = NULL;
@@ -40,14 +37,14 @@ set_desired_inferior (int use_general)
       /* If we are continuing any (all) thread(s), use step_thread
 	 to decide which thread to step and/or send the specified
 	 signal to.  */
-      if ((step_thread != 0 && step_thread != -1)
-	  && (cont_thread == 0 || cont_thread == -1))
-	found = (struct thread_info *) find_inferior_id (&all_threads,
-							 step_thread);
+      if ((!ptid_equal (step_thread, null_ptid)
+	   && !ptid_equal (step_thread, minus_one_ptid))
+	  && (ptid_equal (cont_thread, null_ptid)
+	      || ptid_equal (cont_thread, minus_one_ptid)))
+	found = find_thread_pid (step_thread);
 
       if (found == NULL)
-	found = (struct thread_info *) find_inferior_id (&all_threads,
-							 cont_thread);
+	found = find_thread_pid (cont_thread);
     }
 
   if (found == NULL)
@@ -88,16 +85,16 @@ write_inferior_memory (CORE_ADDR memaddr
   return res;
 }
 
-unsigned long
-mywait (struct target_waitstatus *ourstatus, int options,
+ptid_t
+mywait (ptid_t ptid, struct target_waitstatus *ourstatus, int options,
 	int connected_wait)
 {
-  unsigned long ret;
+  ptid_t ret;
 
   if (connected_wait)
     server_waiting = 1;
 
-  ret = (*the_target->wait) (ourstatus, options);
+  ret = (*the_target->wait) (ptid, ourstatus, options);
 
   if (ourstatus->kind == TARGET_WAITKIND_EXITED
       || ourstatus->kind == TARGET_WAITKIND_SIGNALLED)
@@ -137,3 +134,27 @@ set_target_ops (struct target_ops *targe
   the_target = (struct target_ops *) xmalloc (sizeof (*the_target));
   memcpy (the_target, target, sizeof (*the_target));
 }
+
+/* Convert pid to printable format.  */
+
+const char *
+target_pid_to_str (ptid_t ptid)
+{
+  static char buf[80];
+
+  if (ptid_equal (ptid, minus_one_ptid))
+    snprintf (buf, sizeof (buf), "<all threads>");
+  else if (ptid_equal (ptid, null_ptid))
+    snprintf (buf, sizeof (buf), "<null thread>");
+  else if (ptid_get_tid (ptid) != 0)
+    snprintf (buf, sizeof (buf), "Thread %d.0x%lx",
+	      ptid_get_pid (ptid), ptid_get_tid (ptid));
+  else if (ptid_get_lwp (ptid) != 0)
+    snprintf (buf, sizeof (buf), "LWP %d.%ld",
+	      ptid_get_pid (ptid), ptid_get_lwp (ptid));
+  else
+    snprintf (buf, sizeof (buf), "Process %d",
+	      ptid_get_pid (ptid));
+
+  return buf;
+}
Index: src/gdb/gdbserver/target.h
===================================================================
--- src.orig/gdb/gdbserver/target.h	2009-03-30 01:20:27.000000000 +0100
+++ src/gdb/gdbserver/target.h	2009-03-30 01:20:28.000000000 +0100
@@ -43,7 +43,7 @@ enum resume_kind
 
 struct thread_resume
 {
-  unsigned long thread;
+  ptid_t thread;
 
   /* How to "resume".  */
   enum resume_kind kind;
@@ -96,7 +96,7 @@ struct target_waitstatus
       {
 	int integer;
 	enum target_signal sig;
-	unsigned long related_pid;
+	ptid_t related_pid;
 	char *execd_pathname;
       }
     value;
@@ -129,31 +129,38 @@ struct target_ops
 
   int (*attach) (unsigned long pid);
 
-  /* Kill all inferiors.  */
+  /* Kill inferior PID.  Return -1 on failure, and 0 on success.  */
 
-  void (*kill) (void);
+  int (*kill) (int pid);
 
-  /* Detach from all inferiors.
-     Return -1 on failure, and 0 on success.  */
+  /* Detach from inferior PID. Return -1 on failure, and 0 on
+     success.  */
 
-  int (*detach) (void);
+  int (*detach) (int pid);
 
-  /* Wait for inferiors to end.  */
-
-  void (*join) (void);
+  /* Wait for inferior PID to exit.  */
+  void (*join) (int pid);
 
   /* Return 1 iff the thread with process ID PID is alive.  */
 
-  int (*thread_alive) (unsigned long pid);
+  int (*thread_alive) (ptid_t pid);
 
   /* Resume the inferior process.  */
 
   void (*resume) (struct thread_resume *resume_info, size_t n);
 
   /* Wait for the inferior process or thread to change state.  Store
-     status through argument pointer STATUS.  */
+     status through argument pointer STATUS.
+
+     PTID = -1 to wait for any pid to do something, PTID(pid,0,0) to
+     wait for any thread of process pid to do something.  Return ptid
+     of child, or -1 in case of error; store status through argument
+     pointer STATUS.  OPTIONS is a bit set of options defined as
+     TARGET_W* above.  If options contains TARGET_WNOHANG and there's
+     no child stop to report, return is
+     null_ptid/TARGET_WAITKIND_IGNORE.  */
 
-  unsigned long (*wait) (struct target_waitstatus *status, int options);
+  ptid_t (*wait) (ptid_t ptid, struct target_waitstatus *status, int options);
 
   /* Fetch registers from the inferior process.
 
@@ -280,11 +287,11 @@ void set_target_ops (struct target_ops *
 #define myattach(pid) \
   (*the_target->attach) (pid)
 
-#define kill_inferior() \
-  (*the_target->kill) ()
+#define kill_inferior(pid) \
+  (*the_target->kill) (pid)
 
-#define detach_inferior() \
-  (*the_target->detach) ()
+#define detach_inferior(pid) \
+  (*the_target->detach) (pid)
 
 #define mythread_alive(pid) \
   (*the_target->thread_alive) (pid)
@@ -295,8 +302,8 @@ void set_target_ops (struct target_ops *
 #define store_inferior_registers(regno) \
   (*the_target->store_registers) (regno)
 
-#define join_inferior() \
-  (*the_target->join) ()
+#define join_inferior(pid) \
+  (*the_target->join) (pid)
 
 #define target_supports_non_stop() \
   (the_target->supports_non_stop ? (*the_target->supports_non_stop ) () : 0)
@@ -308,8 +315,8 @@ void set_target_ops (struct target_ops *
 
 int start_non_stop (int nonstop);
 
-unsigned long mywait (struct target_waitstatus *ourstatus, int options,
-		      int connected_wait);
+ptid_t mywait (ptid_t ptid, struct target_waitstatus *ourstatus, int options,
+	       int connected_wait);
 
 int read_inferior_memory (CORE_ADDR memaddr, unsigned char *myaddr, int len);
 
@@ -318,4 +325,6 @@ int write_inferior_memory (CORE_ADDR mem
 
 void set_desired_inferior (int id);
 
+const char *target_pid_to_str (ptid_t);
+
 #endif /* TARGET_H */
Index: src/gdb/gdbserver/thread-db.c
===================================================================
--- src.orig/gdb/gdbserver/thread-db.c	2009-03-30 01:20:27.000000000 +0100
+++ src/gdb/gdbserver/thread-db.c	2009-03-30 01:20:28.000000000 +0100
@@ -35,14 +35,7 @@ static int thread_db_use_events;
 
 #include <stdint.h>
 
-/* Structure that identifies the child process for the
-   <proc_service.h> interface.  */
-static struct ps_prochandle proc_handle;
-
-/* Connection to the libthread_db library.  */
-static td_thragent_t *thread_agent;
-
-static int find_one_thread (int);
+static int find_one_thread (ptid_t);
 static int find_new_threads_callback (const td_thrhandle_t *th_p, void *data);
 
 static const char *
@@ -137,6 +130,7 @@ thread_db_create_event (CORE_ADDR where)
   td_event_msg_t msg;
   td_err_e err;
   struct lwp_info *lwp;
+  struct process_info_private *proc = current_process()->private;
 
   if (debug_threads)
     fprintf (stderr, "Thread creation event.\n");
@@ -145,7 +139,7 @@ thread_db_create_event (CORE_ADDR where)
      In the LinuxThreads implementation, this is safe,
      because all events come from the manager thread
      (except for its own creation, of course).  */
-  err = td_ta_event_getmsg (thread_agent, &msg);
+  err = td_ta_event_getmsg (proc->thread_agent, &msg);
   if (err != TD_OK)
     fprintf (stderr, "thread getmsg err: %s\n",
 	     thread_db_err_str (err));
@@ -155,7 +149,7 @@ thread_db_create_event (CORE_ADDR where)
      created threads.  */
   lwp = get_thread_lwp (current_inferior);
   if (lwp->thread_known == 0)
-    find_one_thread (lwpid_of (lwp));
+    find_one_thread (lwp->head.id);
 
   /* msg.event == TD_EVENT_CREATE */
 
@@ -181,6 +175,7 @@ thread_db_enable_reporting ()
   td_thr_events_t events;
   td_notify_t notify;
   td_err_e err;
+  struct process_info_private *proc = current_process()->private;
 
   /* Set the process wide mask saying which events we're interested in.  */
   td_event_emptyset (&events);
@@ -192,7 +187,7 @@ thread_db_enable_reporting ()
   td_event_addset (&events, TD_DEATH);
 #endif
 
-  err = td_ta_set_event (thread_agent, &events);
+  err = td_ta_set_event (proc->thread_agent, &events);
   if (err != TD_OK)
     {
       warning ("Unable to set global thread event mask: %s",
@@ -201,7 +196,7 @@ thread_db_enable_reporting ()
     }
 
   /* Get address for thread creation breakpoint.  */
-  err = td_ta_event_addr (thread_agent, TD_CREATE, &notify);
+  err = td_ta_event_addr (proc->thread_agent, TD_CREATE, &notify);
   if (err != TD_OK)
     {
       warning ("Unable to get location for thread creation breakpoint: %s",
@@ -216,7 +211,7 @@ thread_db_enable_reporting ()
      with actual thread deaths (via wait).  */
 
   /* Get address for thread death breakpoint.  */
-  err = td_ta_event_addr (thread_agent, TD_DEATH, &notify);
+  err = td_ta_event_addr (proc->thread_agent, TD_DEATH, &notify);
   if (err != TD_OK)
     {
       warning ("Unable to get location for thread death breakpoint: %s",
@@ -231,21 +226,23 @@ thread_db_enable_reporting ()
 }
 
 static int
-find_one_thread (int lwpid)
+find_one_thread (ptid_t ptid)
 {
   td_thrhandle_t th;
   td_thrinfo_t ti;
   td_err_e err;
   struct thread_info *inferior;
   struct lwp_info *lwp;
+  struct process_info_private *proc = current_process()->private;
+  int lwpid = ptid_get_lwp (ptid);
 
-  inferior = (struct thread_info *) find_inferior_id (&all_threads, lwpid);
+  inferior = (struct thread_info *) find_inferior_id (&all_threads, ptid);
   lwp = get_thread_lwp (inferior);
   if (lwp->thread_known)
     return 1;
 
   /* Get information about this thread.  */
-  err = td_ta_map_lwp2thr (thread_agent, lwpid_of (lwp), &th);
+  err = td_ta_map_lwp2thr (proc->thread_agent, lwpid, &th);
   if (err != TD_OK)
     error ("Cannot get thread handle for LWP %d: %s",
 	   lwpid, thread_db_err_str (err));
@@ -259,10 +256,10 @@ find_one_thread (int lwpid)
     fprintf (stderr, "Found thread %ld (LWP %d)\n",
 	     ti.ti_tid, ti.ti_lid);
 
-  if (lwpid_of (lwp) != ti.ti_lid)
+  if (lwpid != ti.ti_lid)
     {
       warning ("PID mismatch!  Expected %ld, got %ld",
-	       (long) lwpid_of (lwp), (long) ti.ti_lid);
+	       (long) lwpid, (long) ti.ti_lid);
       return 0;
     }
 
@@ -289,29 +286,24 @@ static void
 maybe_attach_thread (const td_thrhandle_t *th_p, td_thrinfo_t *ti_p)
 {
   td_err_e err;
-  struct thread_info *inferior;
   struct lwp_info *lwp;
 
-  inferior = (struct thread_info *) find_inferior_id (&all_threads,
-						      ti_p->ti_lid);
-  if (inferior != NULL)
+  lwp = find_lwp_pid (pid_to_ptid (ti_p->ti_lid));
+  if (lwp != 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);
-  inferior = (struct thread_info *) find_inferior_id (&all_threads,
-						      ti_p->ti_lid);
-  if (inferior == NULL)
+  lwp = find_lwp_pid (pid_to_ptid (ti_p->ti_lid));
+  if (lwp == NULL)
     {
       warning ("Could not attach to thread %ld (LWP %d)\n",
 	       ti_p->ti_tid, ti_p->ti_lid);
       return;
     }
 
-  lwp = inferior_target_data (inferior);
-
   lwp->thread_known = 1;
   lwp->th = *th_p;
 
@@ -347,15 +339,18 @@ static void
 thread_db_find_new_threads (void)
 {
   td_err_e err;
+  ptid_t ptid = ((struct inferior_list_entry *) current_inferior)->id;
+  struct process_info_private *proc = current_process()->private;
 
   /* 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_one_thread (all_threads.head->id) == 0)
+  if (find_one_thread (ptid) == 0)
     return;
 
   /* Iterate over all user-space threads to discover new threads.  */
-  err = td_ta_thr_iter (thread_agent, find_new_threads_callback, NULL,
+  err = td_ta_thr_iter (proc->thread_agent,
+			find_new_threads_callback, NULL,
 			TD_THR_ANY_STATE, TD_THR_LOWEST_PRIORITY,
 			TD_SIGNO_MASK, TD_THR_ANY_USER_FLAGS);
   if (err != TD_OK)
@@ -385,18 +380,22 @@ thread_db_get_tls_address (struct thread
   psaddr_t addr;
   td_err_e err;
   struct lwp_info *lwp;
+  struct thread_info *saved_inferior;
 
   lwp = get_thread_lwp (thread);
   if (!lwp->thread_known)
-    find_one_thread (lwpid_of (lwp));
+    find_one_thread (lwp->head.id);
   if (!lwp->thread_known)
     return TD_NOTHR;
 
+  saved_inferior = current_inferior;
+  current_inferior = thread;
   /* Note the cast through uintptr_t: this interface only works if
      a target address fits in a psaddr_t, which is a host pointer.
      So a 32-bit debugger can not access 64-bit TLS through this.  */
   err = td_thr_tls_get_addr (&lwp->th, (psaddr_t) (uintptr_t) load_module,
 			     offset, &addr);
+  current_inferior = saved_inferior;
   if (err == TD_OK)
     {
       *address = (CORE_ADDR) (uintptr_t) addr;
@@ -413,6 +412,8 @@ int
 thread_db_init (int use_events)
 {
   int err;
+  struct process_info *proc = current_process ();
+  struct process_info_private *priv = proc->private;
 
   /* FIXME drow/2004-10-16: This is the "overall process ID", which
      GNU/Linux calls tgid, "thread group ID".  When we support
@@ -424,14 +425,10 @@ thread_db_init (int use_events)
 
      This isn't the only place in gdbserver that assumes that the first
      process in the list is the thread group leader.  */
-  proc_handle.pid = ((struct inferior_list_entry *)current_inferior)->id;
-
-  /* Allow new symbol lookups.  */
-  all_symbols_looked_up = 0;
 
   thread_db_use_events = use_events;
 
-  err = td_ta_new (&proc_handle, &thread_agent);
+  err = td_ta_new (&priv->proc_handle, &priv->thread_agent);
   switch (err)
     {
     case TD_NOLIBTHREAD:
@@ -445,7 +442,7 @@ thread_db_init (int use_events)
 	return 0;
       thread_db_find_new_threads ();
       thread_db_look_up_symbols ();
-      all_symbols_looked_up = 1;
+      proc->all_symbols_looked_up = 1;
       return 1;
 
     default:
Index: src/gdb/gdbserver/mem-break.h
===================================================================
--- src.orig/gdb/gdbserver/mem-break.h	2009-03-30 01:19:42.000000000 +0100
+++ src/gdb/gdbserver/mem-break.h	2009-03-30 01:20:28.000000000 +0100
@@ -75,4 +75,9 @@ void set_breakpoint_data (const unsigned
 
 void delete_all_breakpoints (void);
 
+/* Delete all breakpoints, but do not try to un-insert them from the
+   inferior.  */
+
+void free_all_breakpoints (struct process_info *proc);
+
 #endif /* MEM_BREAK_H */
Index: src/gdb/gdbserver/spu-low.c
===================================================================
--- src.orig/gdb/gdbserver/spu-low.c	2009-03-30 01:20:27.000000000 +0100
+++ src/gdb/gdbserver/spu-low.c	2009-03-30 15:09:50.000000000 +0100
@@ -268,6 +268,7 @@ static int
 spu_create_inferior (char *program, char **allargs)
 {
   int pid;
+  ptid_t ptid;
 
   pid = fork ();
   if (pid < 0)
@@ -289,7 +290,10 @@ spu_create_inferior (char *program, char
       _exit (0177);
     }
 
-  add_thread (pid, NULL, pid);
+  add_process (pid, 0);
+
+  ptid = ptid_build (pid, pid, 0);
+  add_thread (ptid, NULL);
   return pid;
 }
 
@@ -297,6 +301,8 @@ spu_create_inferior (char *program, char
 int
 spu_attach (unsigned long  pid)
 {
+  ptid_t ptid;
+
   if (ptrace (PTRACE_ATTACH, pid, 0, 0) != 0)
     {
       fprintf (stderr, "Cannot attach to process %ld: %s (%d)\n", pid,
@@ -305,7 +311,9 @@ spu_attach (unsigned long  pid)
       _exit (0177);
     }
 
-  add_thread (pid, NULL, pid);
+  add_process (pid, 1);
+  ptid = ptid_build (pid, pid, 0);
+  add_thread (ptid, NULL);
   return 0;
 }
 
@@ -314,6 +322,7 @@ static void
 spu_kill (void)
 {
   ptrace (PTRACE_KILL, current_tid, 0, 0);
+  remove_process (current_tid);
 }
 
 /* Detach from inferior process.  */
@@ -321,6 +330,7 @@ static int
 spu_detach (void)
 {
   ptrace (PTRACE_DETACH, current_tid, 0, 0);
+  remove_process (current_tid);
   return 0;
 }
 
@@ -371,8 +381,8 @@ spu_resume (struct thread_resume *resume
 }
 
 /* Wait for process, returns status.  */
-static unsigned long
-spu_wait (struct target_waitstatus *ourstatus, int options)
+static ptid_t
+spu_wait (ptid_t ptid, struct target_waitstatus *ourstatus, int options)
 {
   int tid = current_tid;
   int w;
@@ -415,7 +425,8 @@ spu_wait (struct target_waitstatus *ours
       ourstatus->kind =  TARGET_WAITKIND_EXITED;
       ourstatus->value.integer = WEXITSTATUS (w);
       clear_inferiors ();
-      return ret;
+      remove_process (current_tid);
+      return pid_to_ptid (ret);
     }
   else if (!WIFSTOPPED (w))
     {
@@ -423,7 +434,8 @@ spu_wait (struct target_waitstatus *ours
       ourstatus->kind = TARGET_WAITKIND_SIGNALLED;
       ourstatus->value.sig = target_signal_from_host (WTERMSIG (w));
       clear_inferiors ();
-      return ret;
+      remove_process (current_tid);
+      return pid_to_ptid (ret);
     }
 
   /* After attach, we may have received a SIGSTOP.  Do not return this
@@ -432,12 +444,12 @@ spu_wait (struct target_waitstatus *ours
     {
       ourstatus->kind = TARGET_WAITKIND_STOPPED;
       ourstatus->value.sig = TARGET_SIGNAL_0;
-      return ret;
+      return ptid_build (ret, ret, 0);
     }
 
   ourstatus->kind = TARGET_WAITKIND_STOPPED;
   ourstatus->value.sig = target_signal_from_host (WSTOPSIG (w));
-  return ret;
+  return ptid_build (ret, ret, 0);
 }
 
 /* Fetch inferior registers.  */
Index: src/gdb/gdbserver/win32-low.c
===================================================================
--- src.orig/gdb/gdbserver/win32-low.c	2009-03-30 01:20:27.000000000 +0100
+++ src/gdb/gdbserver/win32-low.c	2009-03-30 01:20:28.000000000 +0100
@@ -94,11 +94,10 @@ static void win32_resume (struct thread_
 
 /* Get the thread ID from the current selected inferior (the current
    thread).  */
-static DWORD
-current_inferior_tid (void)
+static ptid_t
+current_inferior_ptid (void)
 {
-  win32_thread_info *th = inferior_target_data (current_inferior);
-  return th->tid;
+  return current_inferior->head.id;
 }
 
 /* Get the thread context of the thread associated with TH.  */
@@ -137,12 +136,12 @@ win32_set_thread_context (win32_thread_i
 /* Find a thread record given a thread id.  If GET_CONTEXT is set then
    also retrieve the context for this thread.  */
 static win32_thread_info *
-thread_rec (DWORD id, int get_context)
+thread_rec (ptid_t ptid, int get_context)
 {
   struct thread_info *thread;
   win32_thread_info *th;
 
-  thread = (struct thread_info *) find_inferior_id (&all_threads, id);
+  thread = (struct thread_info *) find_inferior_id (&all_threads, ptid);
   if (thread == NULL)
     return NULL;
 
@@ -169,11 +168,12 @@ thread_rec (DWORD id, int get_context)
 
 /* Add a thread to the thread list.  */
 static win32_thread_info *
-child_add_thread (DWORD tid, HANDLE h)
+child_add_thread (DWORD pid, DWORD tid, HANDLE h)
 {
   win32_thread_info *th;
+  ptid_t ptid = ptid_build (pid, tid, 0);
 
-  if ((th = thread_rec (tid, FALSE)))
+  if ((th = thread_rec (ptid, FALSE)))
     return th;
 
   th = xcalloc (1, sizeof (*th));
@@ -204,7 +204,7 @@ delete_thread_info (struct inferior_list
 
 /* Delete a thread from the list of threads.  */
 static void
-child_delete_thread (DWORD id)
+child_delete_thread (ptid_t ptid)
 {
   struct inferior_list_entry *thread;
 
@@ -212,7 +212,7 @@ child_delete_thread (DWORD id)
   if (all_threads.head == all_threads.tail)
     return;
 
-  thread = find_inferior_id (&all_threads, id);
+  thread = find_inferior_id (&all_threads, ptid);
   if (thread == NULL)
     return;
 
@@ -250,7 +250,7 @@ child_init_thread_list (void)
 }
 
 static void
-do_initial_child_stuff (HANDLE proch, DWORD pid)
+do_initial_child_stuff (HANDLE proch, DWORD pid, int attached)
 {
   last_sig = TARGET_SIGNAL_0;
 
@@ -263,6 +263,7 @@ do_initial_child_stuff (HANDLE proch, DW
 
   memset (&current_event, 0, sizeof (current_event));
 
+  add_process (pid, attached);
   child_init_thread_list ();
 
   if (the_low_target.initial_stuff != NULL)
@@ -320,7 +321,7 @@ static void
 child_fetch_inferior_registers (int r)
 {
   int regno;
-  win32_thread_info *th = thread_rec (current_inferior_tid (), TRUE);
+  win32_thread_info *th = thread_rec (current_inferior_ptid (), TRUE);
   if (r == -1 || r == 0 || r > NUM_REGS)
     child_fetch_inferior_registers (NUM_REGS);
   else
@@ -334,7 +335,7 @@ static void
 child_store_inferior_registers (int r)
 {
   int regno;
-  win32_thread_info *th = thread_rec (current_inferior_tid (), TRUE);
+  win32_thread_info *th = thread_rec (current_inferior_ptid (), TRUE);
   if (r == -1 || r == 0 || r > NUM_REGS)
     child_store_inferior_registers (NUM_REGS);
   else
@@ -540,7 +541,7 @@ win32_create_inferior (char *program, ch
   CloseHandle (pi.hThread);
 #endif
 
-  do_initial_child_stuff (pi.hProcess, pi.dwProcessId);
+  do_initial_child_stuff (pi.hProcess, pi.dwProcessId, 0);
 
   return current_process_id;
 }
@@ -571,7 +572,7 @@ win32_attach (unsigned long pid)
 
 	  /* win32_wait needs to know we're attaching.  */
 	  attaching = 1;
-	  do_initial_child_stuff (h, pid);
+	  do_initial_child_stuff (h, pid, 1);
 	  return 0;
 	}
 
@@ -662,6 +663,7 @@ win32_kill (void)
     }
 
   win32_clear_inferiors ();
+  remove_process (current_process_id);
 }
 
 /* Detach from all inferiors.  */
@@ -694,6 +696,7 @@ win32_detach (void)
     return -1;
 
   DebugSetProcessKillOnExit (FALSE);
+  remove_process (current_process_id);
 
   win32_clear_inferiors ();
   return 0;
@@ -777,7 +780,9 @@ win32_resume (struct thread_resume *resu
   last_sig = TARGET_SIGNAL_0;
 
   /* Get context for the currently selected thread.  */
-  th = thread_rec (current_event.dwThreadId, FALSE);
+  ptid = ptid_build (current_event.dwProcessId,
+		     current_event.dwThreadId, 0);
+  th = thread_rec (ptid, FALSE);
   if (th)
     {
       if (th->context.ContextFlags)
@@ -1362,8 +1367,9 @@ get_child_debug_event (struct target_wai
 		(unsigned) current_event.dwThreadId));
 
       /* Record the existence of this thread.  */
-      child_add_thread (current_event.dwThreadId,
-			     current_event.u.CreateThread.hThread);
+      child_add_thread (current_event.dwProcessId,
+			current_event.dwThreadId,
+			current_event.u.CreateThread.hThread);
       break;
 
     case EXIT_THREAD_DEBUG_EVENT:
@@ -1371,7 +1377,8 @@ get_child_debug_event (struct target_wai
 		"for pid=%d tid=%x\n",
 		(unsigned) current_event.dwProcessId,
 		(unsigned) current_event.dwThreadId));
-      child_delete_thread (current_event.dwThreadId);
+      child_delete_thread (current_event.dwProcessId,
+			   current_event.dwThreadId);
       break;
 
     case CREATE_PROCESS_DEBUG_EVENT:
@@ -1388,7 +1395,8 @@ get_child_debug_event (struct target_wai
       ourstatus->value.execd_pathname = "Main executable";
 
       /* Add the main thread.  */
-      child_add_thread (main_thread_id,
+      child_add_thread (current_event.dwProcessId,
+			main_thread_id,
 			current_event.u.CreateProcessInfo.hThread);
 
       ourstatus->value.related_pid = current_event.dwThreadId;
@@ -1490,6 +1498,7 @@ win32_wait (struct target_waitstatus *ou
 		    ourstatus->value.integer));
 
 	  win32_clear_inferiors ();
+	  remove_process (current_process_id);
 	  return current_event.dwProcessId;
 	case TARGET_WAITKIND_STOPPED:
 	case TARGET_WAITKIND_LOADED:
Index: src/gdb/gdbserver/gdb_proc_service.h
===================================================================
--- src.orig/gdb/gdbserver/gdb_proc_service.h	2009-03-30 01:19:42.000000000 +0100
+++ src/gdb/gdbserver/gdb_proc_service.h	2009-03-30 01:20:28.000000000 +0100
@@ -66,8 +66,8 @@ typedef elf_gregset_t prgregset_t;
 /* Structure that identifies the target process.  */
 struct ps_prochandle
 {
-  /* The process id is all we need.  */
-  pid_t pid;
+  /* We don't need to track anything.  All context is served from the
+     current inferior.  */
 };
 
 #endif /* gdb_proc_service.h */


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