+2009-04-01 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.
+ * 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.
+ * proc-service.c (ps_lgetregs): Use find_lwp_pid.
+ (ps_getpid): Return the pid of the current inferior.
+ * 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): Adjust interface. Remove process from
+ processes table.
+ (spu_join, spu_thread_alive): Adjust interface.
+ (spu_wait): Adjust interface. Remove process from processes
+ table. Adjust to use ptids.
+ * win32-low.c (current_inferior_tid): Delete.
+ (current_inferior_ptid): New.
+ (debug_event_ptid): New.
+ (thread_rec): Take a ptid. Adjust.
+ (child_add_thread): Add `pid' argument. Adjust to use ptids.
+ (child_delete_thread): Ditto.
+ (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): Adjust interface. Remove process from processes
+ table.
+ (win32_detach): Ditto.
+ (win32_join): Adjust interface.
+ (win32_thread_alive): Take a ptid.
+ (win32_resume): Adjust to use ptids.
+ (get_child_debug_event): Ditto.
+ (win32_wait): Adjust interface. Remove exiting process from
+ processes table.
+
2009-04-01 Pedro Alves <pedro@codesourcery.com>
Non-stop mode support.
/* 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 */
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))
}
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));
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;
}
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
}
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;
}
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;
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);
}
{
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
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);
+}
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;
/* 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
{
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 };
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). */
if (event == PTRACE_EVENT_CLONE)
{
+ ptid_t ptid;
unsigned long new_pid;
int ret, status = W_STOPCODE (SIGSTOP);
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.
}
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);
{
void *new_lwp;
int pid;
+ ptid_t ptid;
#if defined(__UCLIBC__) && defined(HAS_NOMMU)
pid = vfork ();
_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.
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. */
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. */
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);
/* 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
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. */
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);
/* 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;
}
/* 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))
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;
&& 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.
{
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 ();
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;
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;
/* 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)
/* 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;
&& !event_child->stepping
&& (
#ifdef USE_THREAD_DB
- (thread_db_active
+ (current_process ()->private->thread_db_active
&& (WSTOPSIG (*wstat) == __SIGRTMIN
|| WSTOPSIG (*wstat) == __SIGRTMIN + 1))
||
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. */
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);
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);
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;
}
- return pid;
+ return pid_to_ptid (pid);
}
}
else
}
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. */
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;
kill_lwp (pid, SIGSTOP);
}
+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;
if (saved_inferior != NULL)
saved_tid = ((struct inferior_list_entry *) saved_inferior)->id;
else
- saved_tid = 0; /* avoid bogus unused warning */
+ saved_tid = null_ptid; /* avoid bogus unused warning */
- ptid = lwpid_of (lwp);
+ ptid = lwp->head.id;
linux_wait_for_event (ptid, &wstat, __WALL);
}
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;
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;
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);
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;
CORE_ADDR regaddr;
int i, size;
char *buf;
+ int pid;
if (regno >= the_low_target.num_regs)
return;
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);
{
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)
{
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)
{
{
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;
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)
{
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);
}
}
{
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;
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)
/* 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
}
= (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;
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;
}
= (((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)
{
/* 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);
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;
}
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
}
{
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;
{
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)
{
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);
#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 *);
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. */
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
{
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;
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);
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)
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)
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)
{
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)
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)
}
}
-/* 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);
+ }
}
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 */
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;
pid_t
ps_getpid (gdb_ps_prochandle_t ph)
{
- return ph->pid;
+ return pid_of (get_thread_lwp (current_inferior));
}
/* 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;
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)
{
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;
+ 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. */
}
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)
{
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) ())
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);
}
}
}
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");
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. */
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;
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. */
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;
}
#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;
/* 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;
struct vstop_notif *next;
/* Thread or process that got the event. */
- unsigned long ptid;
+ ptid_t ptid;
/* Event info. */
struct target_waitstatus status;
/* 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;
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);
}
}
-/* 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;
}
}
start_inferior (char **argv)
{
char **new_argv = argv;
- attached = 0;
if (wrapper_argv != NULL)
{
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;
{
(*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;
}
/* 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;
}
if (myattach (pid) != 0)
return -1;
- attached = 1;
-
fprintf (stderr, "Attached; pid = %d\n", pid);
fflush (stderr);
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
/* 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
{
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;
}
{
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;
}
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
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+");
char *p = own_buf + 12;
CORE_ADDR parts[2], address = 0;
int i, err;
- unsigned long ptid = 0;
+ ptid_t ptid = null_ptid;
require_running (own_buf);
}
if (i == 0)
- ptid = strtoul (p, NULL, 16);
+ ptid = read_ptid (p, NULL);
else
decode_address (&parts[i - 1], p, len);
p = p2;
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;
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;
}
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. */
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
}
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;
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++;
}
/* 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)
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 ();
}
}
}
+/* Kill process. 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)
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;
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);
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);
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);
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)
{
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++;
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 ();
}
/* 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. */
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
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[])
{
exit (1);
}
+ initialize_inferiors ();
initialize_async_io ();
initialize_low ();
{
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,
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);
}
while (1)
{
noack_mode = 0;
+ multi_process = 0;
non_stop = 0;
remote_open (port);
if (exit_requested)
{
- if (attached)
- detach_inferior ();
- else
- kill_inferior ();
+ for_each_inferior (&all_processes,
+ detach_or_kill_inferior_callback);
exit (0);
}
else
int signal;
unsigned int len;
CORE_ADDR mem_addr;
+ int pid;
unsigned char sig;
int packet_len;
int new_packet_len = -1;
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)
/* 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;
}
/* 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);
}
}
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;
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 still valid. If
case 'k':
response_needed = 0;
if (!target_running ())
- /* The packet we received doesn't make sense - but we
- can't reply to it, either. */
+ /* The packet we received doesn't make sense - but we 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 instead. */
}
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;
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. */
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)
{
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
};
struct inferior_list_entry
{
- unsigned long id;
+ ptid_t id;
struct inferior_list_entry *next;
};
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"
/* 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
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 *);
/* 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;
extern int disable_packet_qC;
extern int disable_packet_qfThreadInfo;
+extern int multi_process;
extern int non_stop;
/* Functions from event-loop.c. */
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 *);
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);
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);
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);
spu_create_inferior (char *program, char **allargs)
{
int pid;
+ ptid_t ptid;
pid = fork ();
if (pid < 0)
_exit (0177);
}
- add_thread (pid, NULL, pid);
+ add_process (pid, 0);
+
+ ptid = ptid_build (pid, pid, 0);
+ add_thread (ptid, NULL);
return pid;
}
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,
_exit (0177);
}
- add_thread (pid, NULL, pid);
+ add_process (pid, 1);
+ ptid = ptid_build (pid, pid, 0);
+ add_thread (ptid, NULL);
return 0;
}
/* Kill the inferior process. */
-static void
-spu_kill (void)
+static int
+spu_kill (int)
{
ptrace (PTRACE_KILL, current_tid, 0, 0);
+ remove_process (pid);
+ return 0;
}
/* Detach from inferior process. */
static int
-spu_detach (void)
+spu_detach (int pid)
{
ptrace (PTRACE_DETACH, current_tid, 0, 0);
+ remove_process (pid);
return 0;
}
static void
-spu_join (void)
+spu_join (int pid)
{
int status, ret;
/* Return nonzero if the given thread is still alive. */
static int
-spu_thread_alive (unsigned long tid)
+spu_thread_alive (ptid_t ptid)
{
- return tid == current_tid;
+ return ptid_get_lwp (ptid) == current_tid;
}
/* Resume process. */
size_t i;
for (i = 0; i < n; i++)
- if (resume_info[i].thread == -1
- || resume_info[i].thread == current_tid)
+ if (ptid_equal (resume_info[i].thread, minus_one_ptid)
+ || ptid_get_lwp (resume_info[i].thread) == current_tid)
break;
if (i == n)
}
/* 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;
ourstatus->kind = TARGET_WAITKIND_EXITED;
ourstatus->value.integer = WEXITSTATUS (w);
clear_inferiors ();
- return ret;
+ remove_process (ret);
+ return pid_to_ptid (ret);
}
else if (!WIFSTOPPED (w))
{
ourstatus->kind = TARGET_WAITKIND_SIGNALLED;
ourstatus->value.sig = target_signal_from_host (WTERMSIG (w));
clear_inferiors ();
- return ret;
+ remove_process (ret);
+ return pid_to_ptid (ret);
}
/* After attach, we may have received a SIGSTOP. Do not return this
{
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. */
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;
/* 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)
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)
- {
- if (ourstatus->kind == TARGET_WAITKIND_EXITED)
- fprintf (stderr,
- "\nChild exited with status %d\n", ourstatus->value.sig);
- if (ourstatus->kind == TARGET_WAITKIND_SIGNALLED)
- fprintf (stderr, "\nChild terminated with signal = 0x%x (%s)\n",
- target_signal_to_host (ourstatus->value.sig),
- target_signal_to_name (ourstatus->value.sig));
- }
+ if (ourstatus->kind == TARGET_WAITKIND_EXITED)
+ fprintf (stderr,
+ "\nChild exited with status %d\n", ourstatus->value.sig);
+ else if (ourstatus->kind == TARGET_WAITKIND_SIGNALLED)
+ fprintf (stderr, "\nChild terminated with signal = 0x%x (%s)\n",
+ target_signal_to_host (ourstatus->value.sig),
+ target_signal_to_name (ourstatus->value.sig));
if (connected_wait)
server_waiting = 0;
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;
+}
struct thread_resume
{
- unsigned long thread;
+ ptid_t thread;
/* How to "resume". */
enum resume_kind kind;
{
int integer;
enum target_signal sig;
- unsigned long related_pid;
+ ptid_t related_pid;
char *execd_pathname;
}
value;
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.
#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)
#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)
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);
void set_desired_inferior (int id);
+const char *target_pid_to_str (ptid_t);
+
#endif /* TARGET_H */
#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 *
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");
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));
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 */
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);
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",
}
/* Get address for thread creation breakpoint. */
- err = td_ta_event_addr (thread_agent, TD_CREATE, ¬ify);
+ err = td_ta_event_addr (proc->thread_agent, TD_CREATE, ¬ify);
if (err != TD_OK)
{
warning ("Unable to get location for thread creation breakpoint: %s",
with actual thread deaths (via wait). */
/* Get address for thread death breakpoint. */
- err = td_ta_event_addr (thread_agent, TD_DEATH, ¬ify);
+ err = td_ta_event_addr (proc->thread_agent, TD_DEATH, ¬ify);
if (err != TD_OK)
{
warning ("Unable to get location for thread death breakpoint: %s",
}
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));
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;
}
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;
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)
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;
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
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:
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:
/* 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 ((struct inferior_list_entry*) current_inferior)->id;
+}
+
+/* The current debug event from WaitForDebugEvent. */
+static ptid_t
+debug_event_ptid (DEBUG_EVENT *event)
+{
+ return ptid_build (event->dwProcessId, event->dwThreadId, 0);
}
/* Get the thread context of the thread associated with TH. */
/* 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;
/* 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));
th->tid = tid;
th->h = h;
- add_thread (tid, th, (unsigned int) tid);
+ add_thread (ptid, th);
set_inferior_regcache_data ((struct thread_info *)
- find_inferior_id (&all_threads, tid),
+ find_inferior_id (&all_threads, ptid),
new_register_cache ());
if (the_low_target.thread_added != NULL)
/* Delete a thread from the list of threads. */
static void
-child_delete_thread (DWORD id)
+child_delete_thread (DWORD pid, DWORD tid)
{
struct inferior_list_entry *thread;
+ ptid_t ptid;
/* If the last thread is exiting, just return. */
if (all_threads.head == all_threads.tail)
return;
- thread = find_inferior_id (&all_threads, id);
+ ptid = ptid_build (pid, tid, 0);
+ thread = find_inferior_id (&all_threads, ptid);
if (thread == NULL)
return;
}
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;
memset (¤t_event, 0, sizeof (current_event));
+ add_process (pid, attached);
child_init_thread_list ();
if (the_low_target.initial_stuff != NULL)
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
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
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;
}
/* 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;
}
}
/* Kill all inferiors. */
-static void
-win32_kill (void)
+static int
+win32_kill (int pid)
{
+ struct process_info *process;
+
if (current_process_handle == NULL)
- return;
+ return -1;
TerminateProcess (current_process_handle, 0);
for (;;)
}
win32_clear_inferiors ();
+
+ process = find_process_pid (pid);
+ remove_process (process);
+ return 0;
}
-/* Detach from all inferiors. */
+/* Detach from inferior PID. */
static int
-win32_detach (void)
+win32_detach (int pid)
{
+ struct process_info *process;
winapi_DebugActiveProcessStop DebugActiveProcessStop = NULL;
winapi_DebugSetProcessKillOnExit DebugSetProcessKillOnExit = NULL;
#ifdef _WIN32_WCE
{
struct thread_resume resume;
- resume.thread = -1;
+ resume.thread = minus_one_ptid;
resume.kind = resume_continue;
resume.sig = 0;
win32_resume (&resume, 1);
return -1;
DebugSetProcessKillOnExit (FALSE);
+ process = find_process_pid (pid);
+ remove_process (process);
win32_clear_inferiors ();
return 0;
/* Wait for inferiors to end. */
static void
-win32_join (void)
+win32_join (int pid)
{
- extern unsigned long signal_pid;
-
- HANDLE h = OpenProcess (PROCESS_ALL_ACCESS, FALSE, signal_pid);
+ HANDLE h = OpenProcess (PROCESS_ALL_ACCESS, FALSE, pid);
if (h != NULL)
{
WaitForSingleObject (h, INFINITE);
/* Return 1 iff the thread with thread ID TID is alive. */
static int
-win32_thread_alive (unsigned long tid)
+win32_thread_alive (ptid_t ptid)
{
int res;
/* Our thread list is reliable; don't bother to poll target
threads. */
- if (find_inferior_id (&all_threads, tid) != NULL)
+ if (find_inferior_id (&all_threads, ptid) != NULL)
res = 1;
else
res = 0;
int step;
win32_thread_info *th;
DWORD continue_status = DBG_CONTINUE;
+ ptid_t ptid;
/* This handles the very limited set of resume packets that GDB can
currently produce. */
- if (n == 1 && resume_info[0].thread == -1)
+ if (n == 1 && ptid_equal (resume_info[0].thread, minus_one_ptid))
tid = -1;
else if (n > 1)
tid = -1;
the Windows resume code do the right thing for thread switching. */
tid = current_event.dwThreadId;
- if (resume_info[0].thread != -1)
+ if (!ptid_equal (resume_info[0].thread, minus_one_ptid))
{
sig = resume_info[0].sig;
step = resume_info[0].kind == resume_step;
last_sig = TARGET_SIGNAL_0;
/* Get context for the currently selected thread. */
- th = thread_rec (current_event.dwThreadId, FALSE);
+ ptid = debug_event_ptid (¤t_event);
+ th = thread_rec (ptid, FALSE);
if (th)
{
if (th->context.ContextFlags)
static int
get_child_debug_event (struct target_waitstatus *ourstatus)
{
+ ptid_t ptid;
+
last_sig = TARGET_SIGNAL_0;
ourstatus->kind = TARGET_WAITKIND_SPURIOUS;
gotevent:
+ ptid = debug_event_ptid (¤t_event);
current_inferior =
- (struct thread_info *) find_inferior_id (&all_threads,
- current_event.dwThreadId);
+ (struct thread_info *) find_inferior_id (&all_threads, ptid);
switch (current_event.dwDebugEventCode)
{
(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:
"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:
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;
+ ourstatus->value.related_pid = debug_event_ptid (¤t_event);
#ifdef _WIN32_WCE
if (!attaching)
{
}
current_inferior =
- (struct thread_info *) find_inferior_id (&all_threads,
- current_event.dwThreadId);
+ (struct thread_info *) find_inferior_id (&all_threads, ptid);
return 1;
}
/* Wait for the inferior process to change state.
STATUS will be filled in with a response code to send to GDB.
Returns the signal which caused the process to stop. */
-static unsigned long
-win32_wait (struct target_waitstatus *ourstatus, int options)
+static ptid_t
+win32_wait (ptid_t ptid, struct target_waitstatus *ourstatus, int options)
{
+ struct process_info *process;
+
while (1)
{
if (!get_child_debug_event (ourstatus))
OUTMSG2 (("Child exited with retcode = %x\n",
ourstatus->value.integer));
+ process = find_process_pid (current_process_id);
+ remove_process (process);
win32_clear_inferiors ();
- return current_event.dwProcessId;
+ return pid_to_ptid (current_event.dwProcessId);
case TARGET_WAITKIND_STOPPED:
case TARGET_WAITKIND_LOADED:
OUTMSG2 (("Child Stopped with signal = %d \n",
if (ourstatus->kind == TARGET_WAITKIND_LOADED)
ourstatus->kind = TARGET_WAITKIND_STOPPED;
- return current_event.dwThreadId;
+ return debug_event_ptid (¤t_event);
default:
OUTMSG (("Ignoring unknown internal event, %d\n", ourstatus->kind));
/* fall-through */