aboutsummaryrefslogtreecommitdiff
path: root/gdb/gdbserver/server.c
diff options
context:
space:
mode:
authorPedro Alves <palves@redhat.com>2009-04-01 22:50:24 +0000
committerPedro Alves <palves@redhat.com>2009-04-01 22:50:24 +0000
commit95954743cb49efcc384c378173606fd309b6e6ac (patch)
tree77498746f38b65a313aa42bcbf5db4c6c491c7e5 /gdb/gdbserver/server.c
parentbd99dc858385792aad304d42f4a47791fd8d3272 (diff)
downloadgdb-95954743cb49efcc384c378173606fd309b6e6ac.zip
gdb-95954743cb49efcc384c378173606fd309b6e6ac.tar.gz
gdb-95954743cb49efcc384c378173606fd309b6e6ac.tar.bz2
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.
Diffstat (limited to 'gdb/gdbserver/server.c')
-rw-r--r--gdb/gdbserver/server.c369
1 files changed, 272 insertions, 97 deletions
diff --git a/gdb/gdbserver/server.c b/gdb/gdbserver/server.c
index 81efecc..998fd0c 100644
--- a/gdb/gdbserver/server.c
+++ b/gdb/gdbserver/server.c
@@ -32,17 +32,17 @@
#include <malloc.h>
#endif
-unsigned long cont_thread;
-unsigned long general_thread;
-unsigned long step_thread;
+ptid_t cont_thread;
+ptid_t general_thread;
+ptid_t step_thread;
int server_waiting;
static int extended_protocol;
-static int attached;
static int response_needed;
static int exit_requested;
+int multi_process;
int non_stop;
static char **program_argv, **wrapper_argv;
@@ -90,7 +90,7 @@ int disable_packet_qfThreadInfo;
/* Last status reported to GDB. */
static struct target_waitstatus last_status;
-static unsigned long last_ptid;
+static ptid_t last_ptid;
static char *own_buf;
static unsigned char *mem_buf;
@@ -104,7 +104,7 @@ struct vstop_notif
struct vstop_notif *next;
/* Thread or process that got the event. */
- unsigned long ptid;
+ ptid_t ptid;
/* Event info. */
struct target_waitstatus status;
@@ -116,7 +116,7 @@ static struct vstop_notif *notif_queue = NULL;
/* Put a stop reply to the stop reply queue. */
static void
-queue_stop_reply (unsigned long ptid, struct target_waitstatus *status)
+queue_stop_reply (ptid_t ptid, struct target_waitstatus *status)
{
struct vstop_notif *new_notif;
@@ -153,7 +153,7 @@ queue_stop_reply (unsigned long ptid, struct target_waitstatus *status)
we aren't sending one yet. */
void
-push_event (unsigned long ptid, struct target_waitstatus *status)
+push_event (ptid_t ptid, struct target_waitstatus *status)
{
queue_stop_reply (ptid, status);
@@ -170,19 +170,30 @@ push_event (unsigned long ptid, struct target_waitstatus *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;
}
}
@@ -209,7 +220,6 @@ static int
start_inferior (char **argv)
{
char **new_argv = argv;
- attached = 0;
if (wrapper_argv != NULL)
{
@@ -253,13 +263,13 @@ start_inferior (char **argv)
if (wrapper_argv != NULL)
{
struct thread_resume resume_info;
- unsigned long ptid;
+ ptid_t ptid;
- resume_info.thread = -1;
+ resume_info.thread = pid_to_ptid (signal_pid);
resume_info.kind = resume_continue;
resume_info.sig = 0;
- ptid = mywait (&last_status, 0, 0);
+ ptid = mywait (pid_to_ptid (signal_pid), &last_status, 0, 0);
if (last_status.kind != TARGET_WAITKIND_STOPPED)
return signal_pid;
@@ -268,7 +278,7 @@ start_inferior (char **argv)
{
(*the_target->resume) (&resume_info, 1);
- mywait (&last_status, 0, 0);
+ mywait (pid_to_ptid (signal_pid), &last_status, 0, 0);
if (last_status.kind != TARGET_WAITKIND_STOPPED)
return signal_pid;
}
@@ -279,7 +289,7 @@ start_inferior (char **argv)
/* Wait till we are at 1st instruction in program, return new pid
(assuming success). */
- last_ptid = mywait (&last_status, 0, 0);
+ last_ptid = mywait (pid_to_ptid (signal_pid), &last_status, 0, 0);
return signal_pid;
}
@@ -293,8 +303,6 @@ attach_inferior (int pid)
if (myattach (pid) != 0)
return -1;
- attached = 1;
-
fprintf (stderr, "Attached; pid = %d\n", pid);
fflush (stderr);
@@ -305,7 +313,7 @@ attach_inferior (int pid)
if (!non_stop)
{
- last_ptid = mywait (&last_status, 0, 0);
+ last_ptid = mywait (pid_to_ptid (pid), &last_status, 0, 0);
/* GDB knows to ignore the first SIGSTOP after attaching to a running
process using the "attach" command, but this is different; it's
@@ -656,10 +664,11 @@ handle_query (char *own_buf, int packet_len, int *new_packet_len_p)
/* Reply the current thread id. */
if (strcmp ("qC", own_buf) == 0 && !disable_packet_qC)
{
- unsigned long gdb_id;
+ ptid_t gdb_id;
require_running (own_buf);
- if (general_thread != 0 && general_thread != -1)
+ if (!ptid_equal (general_thread, null_ptid)
+ && !ptid_equal (general_thread, minus_one_ptid))
gdb_id = general_thread;
else
{
@@ -667,7 +676,9 @@ handle_query (char *own_buf, int packet_len, int *new_packet_len_p)
gdb_id = thread_to_gdb_id ((struct thread_info *)thread_ptr);
}
- sprintf (own_buf, "QC%lx", gdb_id);
+ sprintf (own_buf, "QC");
+ own_buf += 2;
+ own_buf = write_ptid (own_buf, gdb_id);
return;
}
@@ -684,21 +695,28 @@ handle_query (char *own_buf, int packet_len, int *new_packet_len_p)
{
if (strcmp ("qfThreadInfo", own_buf) == 0)
{
+ ptid_t gdb_id;
+
require_running (own_buf);
thread_ptr = all_threads.head;
- sprintf (own_buf, "m%x",
- thread_to_gdb_id ((struct thread_info *)thread_ptr));
+
+ *own_buf++ = 'm';
+ gdb_id = thread_to_gdb_id ((struct thread_info *)thread_ptr);
+ write_ptid (own_buf, gdb_id);
thread_ptr = thread_ptr->next;
return;
}
if (strcmp ("qsThreadInfo", own_buf) == 0)
{
+ ptid_t gdb_id;
+
require_running (own_buf);
if (thread_ptr != NULL)
{
- sprintf (own_buf, "m%x",
- thread_to_gdb_id ((struct thread_info *)thread_ptr));
+ *own_buf++ = 'm';
+ gdb_id = thread_to_gdb_id ((struct thread_info *)thread_ptr);
+ write_ptid (own_buf, gdb_id);
thread_ptr = thread_ptr->next;
return;
}
@@ -1046,6 +1064,21 @@ handle_query (char *own_buf, int packet_len, int *new_packet_len_p)
if (strncmp ("qSupported", own_buf, 10) == 0
&& (own_buf[10] == ':' || own_buf[10] == '\0'))
{
+ char *p = &own_buf[10];
+
+ /* Process each feature being provided by GDB. The first
+ feature will follow a ':', and latter features will follow
+ ';'. */
+ if (*p == ':')
+ for (p = strtok (p + 1, ";");
+ p != NULL;
+ p = strtok (NULL, ";"))
+ {
+ /* Record if GDB knows about multiprocess support. */
+ if (strcmp (p, "multiprocess+") == 0)
+ multi_process = 1;
+ }
+
sprintf (own_buf, "PacketSize=%x;QPassSignals+", PBUFSIZ - 1);
/* We do not have any hook to indicate whether the target backend
@@ -1073,6 +1106,8 @@ handle_query (char *own_buf, int packet_len, int *new_packet_len_p)
if (the_target->qxfer_osdata != NULL)
strcat (own_buf, ";qXfer:osdata:read+");
+ strcat (own_buf, ";multiprocess+");
+
if (target_supports_non_stop ())
strcat (own_buf, ";QNonStop+");
@@ -1086,7 +1121,7 @@ handle_query (char *own_buf, int packet_len, int *new_packet_len_p)
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);
@@ -1111,7 +1146,7 @@ handle_query (char *own_buf, int packet_len, int *new_packet_len_p)
}
if (i == 0)
- ptid = strtoul (p, NULL, 16);
+ ptid = read_ptid (p, NULL);
else
decode_address (&parts[i - 1], p, len);
p = p2;
@@ -1121,7 +1156,7 @@ handle_query (char *own_buf, int packet_len, int *new_packet_len_p)
err = 1;
else
{
- struct thread_info *thread = gdb_id_to_thread (ptid);
+ struct thread_info *thread = find_thread_pid (ptid);
if (thread == NULL)
err = 2;
@@ -1208,10 +1243,30 @@ handle_query (char *own_buf, int packet_len, int *new_packet_len_p)
return;
}
- if (strcmp (own_buf, "qAttached") == 0)
+ if (strcmp (own_buf, "qAttached") == 0
+ || strncmp (own_buf, "qAttached:", sizeof ("qAttached:") - 1) == 0)
{
- require_running (own_buf);
- strcpy (own_buf, attached ? "1" : "0");
+ struct process_info *process;
+
+ if (own_buf[sizeof ("qAttached") - 1])
+ {
+ int pid = strtoul (own_buf + sizeof ("qAttached:") - 1, NULL, 16);
+ process = (struct process_info *)
+ find_inferior_id (&all_processes, pid_to_ptid (pid));
+ }
+ else
+ {
+ require_running (own_buf);
+ process = current_process ();
+ }
+
+ if (process == NULL)
+ {
+ write_enn (own_buf);
+ return;
+ }
+
+ strcpy (own_buf, process->attached ? "1" : "0");
return;
}
@@ -1227,7 +1282,7 @@ handle_v_cont (char *own_buf)
char *p, *q;
int n = 0, i = 0;
struct thread_resume *resume_info;
- struct thread_resume default_action = {0};
+ struct thread_resume default_action = {{0}};
/* Count the number of semicolons in the packet. There should be one
for every action. */
@@ -1277,7 +1332,7 @@ handle_v_cont (char *own_buf)
if (p[0] == 0)
{
- resume_info[i].thread = -1;
+ resume_info[i].thread = minus_one_ptid;
default_action = resume_info[i];
/* Note: we don't increment i here, we'll overwrite this entry
@@ -1285,8 +1340,7 @@ handle_v_cont (char *own_buf)
}
else if (p[0] == ':')
{
- unsigned int gdb_id = strtoul (p + 1, &q, 16);
- unsigned long thread_id;
+ ptid_t ptid = read_ptid (p + 1, &q);
if (p == q)
goto err;
@@ -1294,11 +1348,7 @@ handle_v_cont (char *own_buf)
if (p[0] != ';' && p[0] != 0)
goto err;
- thread_id = gdb_id_to_thread_id (gdb_id);
- if (thread_id)
- resume_info[i].thread = thread_id;
- else
- goto err;
+ resume_info[i].thread = ptid;
i++;
}
@@ -1309,11 +1359,11 @@ handle_v_cont (char *own_buf)
/* Still used in occasional places in the backend. */
if (n == 1
- && resume_info[0].thread != -1
+ && !ptid_equal (resume_info[0].thread, minus_one_ptid)
&& resume_info[0].kind != resume_stop)
cont_thread = resume_info[0].thread;
else
- cont_thread = -1;
+ cont_thread = minus_one_ptid;
set_desired_inferior (0);
if (!non_stop)
@@ -1327,7 +1377,7 @@ handle_v_cont (char *own_buf)
write_ok (own_buf);
else
{
- last_ptid = mywait (&last_status, 0, 1);
+ last_ptid = mywait (minus_one_ptid, &last_status, 0, 1);
prepare_resume_reply (own_buf, last_ptid, &last_status);
disable_async_io ();
}
@@ -1462,6 +1512,30 @@ handle_v_run (char *own_buf)
}
}
+/* 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)
@@ -1473,7 +1547,8 @@ handle_v_stopped (char *own_buf)
struct vstop_notif *head;
if (remote_debug)
- fprintf (stderr, "vStopped: acking %ld\n", notif_queue->ptid);
+ fprintf (stderr, "vStopped: acking %s\n",
+ target_pid_to_str (notif_queue->ptid));
head = notif_queue;
notif_queue = notif_queue->next;
@@ -1510,7 +1585,7 @@ handle_v_requests (char *own_buf, int packet_len, int *new_packet_len)
if (strncmp (own_buf, "vAttach;", 8) == 0)
{
- if (target_running ())
+ if (!multi_process && target_running ())
{
fprintf (stderr, "Already debugging a process\n");
write_enn (own_buf);
@@ -1522,7 +1597,7 @@ handle_v_requests (char *own_buf, int packet_len, int *new_packet_len)
if (strncmp (own_buf, "vRun;", 5) == 0)
{
- if (target_running ())
+ if (!multi_process && target_running ())
{
fprintf (stderr, "Already debugging a process\n");
write_enn (own_buf);
@@ -1532,6 +1607,18 @@ handle_v_requests (char *own_buf, int packet_len, int *new_packet_len)
return;
}
+ if (strncmp (own_buf, "vKill;", 6) == 0)
+ {
+ if (!target_running ())
+ {
+ fprintf (stderr, "No process to kill\n");
+ write_enn (own_buf);
+ return;
+ }
+ handle_v_kill (own_buf);
+ return;
+ }
+
if (strncmp (own_buf, "vStopped", 8) == 0)
{
handle_v_stopped (own_buf);
@@ -1556,7 +1643,8 @@ myresume (char *own_buf, int step, int sig)
set_desired_inferior (0);
- valid_cont_thread = (cont_thread != 0 && cont_thread != -1);
+ valid_cont_thread = (!ptid_equal (cont_thread, null_ptid)
+ && !ptid_equal (cont_thread, minus_one_ptid));
if (step || sig || valid_cont_thread)
{
@@ -1572,7 +1660,7 @@ myresume (char *own_buf, int step, int sig)
if (!valid_cont_thread)
{
- resume_info[n].thread = -1;
+ resume_info[n].thread = minus_one_ptid;
resume_info[n].kind = resume_continue;
resume_info[n].sig = 0;
n++;
@@ -1587,7 +1675,7 @@ myresume (char *own_buf, int step, int sig)
write_ok (own_buf);
else
{
- last_ptid = mywait (&last_status, 0, 1);
+ last_ptid = mywait (minus_one_ptid, &last_status, 0, 1);
prepare_resume_reply (own_buf, last_ptid, &last_status);
disable_async_io ();
}
@@ -1596,16 +1684,24 @@ myresume (char *own_buf, int step, int sig)
/* Callback for for_each_inferior. Make a new stop reply for each
stopped thread. */
-static void
-queue_stop_reply_callback (struct inferior_list_entry *entry)
+static int
+queue_stop_reply_callback (struct inferior_list_entry *entry, void *arg)
{
- struct target_waitstatus status;
+ int pid = * (int *) arg;
- status.kind = TARGET_WAITKIND_STOPPED;
- status.value.sig = TARGET_SIGNAL_TRAP;
+ if (pid == -1
+ || ptid_get_pid (entry->id) == pid)
+ {
+ struct target_waitstatus status;
+
+ status.kind = TARGET_WAITKIND_STOPPED;
+ status.value.sig = TARGET_SIGNAL_TRAP;
- /* Pass the last stop reply back to GDB, but don't notify. */
- queue_stop_reply (entry->id, &status);
+ /* Pass the last stop reply back to GDB, but don't notify. */
+ queue_stop_reply (entry->id, &status);
+ }
+
+ return 0;
}
/* Status handler for the '?' packet. */
@@ -1623,8 +1719,9 @@ handle_status (char *own_buf)
if (non_stop)
{
- discard_queued_stop_replies ();
- for_each_inferior (&all_threads, queue_stop_reply_callback);
+ int pid = -1;
+ discard_queued_stop_replies (pid);
+ find_inferior (&all_threads, queue_stop_reply_callback, &pid);
/* The first is sent immediatly. OK is sent if there is no
stopped thread, which is the same handling of the vStopped
@@ -1690,6 +1787,52 @@ gdbserver_show_disableable (FILE *stream)
break; \
}
+static int
+first_thread_of (struct inferior_list_entry *entry, void *args)
+{
+ int pid = * (int *) args;
+
+ if (ptid_get_pid (entry->id) == pid)
+ return 1;
+
+ return 0;
+}
+
+static void
+kill_inferior_callback (struct inferior_list_entry *entry)
+{
+ struct process_info *process = (struct process_info *) entry;
+ int pid = ptid_get_pid (process->head.id);
+
+ kill_inferior (pid);
+ discard_queued_stop_replies (pid);
+}
+
+static void
+detach_or_kill_inferior_callback (struct inferior_list_entry *entry)
+{
+ struct process_info *process = (struct process_info *) entry;
+ int pid = ptid_get_pid (process->head.id);
+
+ if (process->attached)
+ detach_inferior (pid);
+ else
+ kill_inferior (pid);
+
+ discard_queued_stop_replies (pid);
+}
+
+static void
+join_inferiors_callback (struct inferior_list_entry *entry)
+{
+ struct process_info *process = (struct process_info *) entry;
+
+ /* If we are attached, then we can exit. Otherwise, we need to hang
+ around doing nothing, until the child is gone. */
+ if (!process->attached)
+ join_inferior (ptid_get_pid (process->head.id));
+}
+
int
main (int argc, char *argv[])
{
@@ -1827,6 +1970,7 @@ main (int argc, char *argv[])
exit (1);
}
+ initialize_inferiors ();
initialize_async_io ();
initialize_low ();
@@ -1861,7 +2005,7 @@ main (int argc, char *argv[])
{
last_status.kind = TARGET_WAITKIND_EXITED;
last_status.value.integer = 0;
- last_ptid = -1;
+ last_ptid = minus_one_ptid;
}
/* Don't report shared library events on the initial connection,
@@ -1871,8 +2015,9 @@ main (int argc, char *argv[])
if (setjmp (toplevel))
{
- fprintf (stderr, "Killing inferior\n");
- kill_inferior ();
+ fprintf (stderr, "Killing all inferiors\n");
+ for_each_inferior (&all_processes,
+ kill_inferior_callback);
exit (1);
}
@@ -1891,6 +2036,7 @@ main (int argc, char *argv[])
while (1)
{
noack_mode = 0;
+ multi_process = 0;
non_stop = 0;
remote_open (port);
@@ -1916,10 +2062,8 @@ main (int argc, char *argv[])
if (exit_requested)
{
- if (attached)
- detach_inferior ();
- else
- kill_inferior ();
+ for_each_inferior (&all_processes,
+ detach_or_kill_inferior_callback);
exit (0);
}
else
@@ -1941,6 +2085,7 @@ process_serial_event (void)
int signal;
unsigned int len;
CORE_ADDR mem_addr;
+ int pid;
unsigned char sig;
int packet_len;
int new_packet_len = -1;
@@ -1976,12 +2121,22 @@ process_serial_event (void)
break;
case 'D':
require_running (own_buf);
- fprintf (stderr, "Detaching from inferior\n");
- if (detach_inferior () != 0)
+
+ if (multi_process)
+ {
+ i++; /* skip ';' */
+ pid = strtol (&own_buf[i], NULL, 16);
+ }
+ else
+ pid =
+ ptid_get_pid (((struct inferior_list_entry *) current_inferior)->id);
+
+ fprintf (stderr, "Detaching from process %d\n", pid);
+ if (detach_inferior (pid) != 0)
write_enn (own_buf);
else
{
- discard_queued_stop_replies ();
+ discard_queued_stop_replies (pid);
write_ok (own_buf);
if (extended_protocol)
@@ -1989,7 +2144,7 @@ process_serial_event (void)
/* Treat this like a normal program exit. */
last_status.kind = TARGET_WAITKIND_EXITED;
last_status.value.integer = 0;
- last_ptid = signal_pid;
+ last_ptid = pid_to_ptid (pid);
current_inferior = NULL;
}
@@ -2001,9 +2156,8 @@ process_serial_event (void)
/* If we are attached, then we can exit. Otherwise, we
need to hang around doing nothing, until the child is
gone. */
- if (!attached)
- join_inferior ();
-
+ for_each_inferior (&all_processes,
+ join_inferiors_callback);
exit (0);
}
}
@@ -2018,16 +2172,38 @@ process_serial_event (void)
case 'H':
if (own_buf[1] == 'c' || own_buf[1] == 'g' || own_buf[1] == 's')
{
- unsigned long gdb_id, thread_id;
+ ptid_t gdb_id, thread_id;
+ int pid;
require_running (own_buf);
- gdb_id = strtoul (&own_buf[2], NULL, 16);
- if (gdb_id == 0 || gdb_id == -1)
- thread_id = gdb_id;
+
+ gdb_id = read_ptid (&own_buf[2], NULL);
+
+ pid = ptid_get_pid (gdb_id);
+
+ if (ptid_equal (gdb_id, null_ptid)
+ || ptid_equal (gdb_id, minus_one_ptid))
+ thread_id = null_ptid;
+ else if (pid != 0
+ && ptid_equal (pid_to_ptid (pid),
+ gdb_id))
+ {
+ struct thread_info *thread =
+ (struct thread_info *) find_inferior (&all_threads,
+ first_thread_of,
+ &pid);
+ if (!thread)
+ {
+ write_enn (own_buf);
+ break;
+ }
+
+ thread_id = ((struct inferior_list_entry *)thread)->id;
+ }
else
{
thread_id = gdb_id_to_thread_id (gdb_id);
- if (thread_id == 0)
+ if (ptid_equal (thread_id, null_ptid))
{
write_enn (own_buf);
break;
@@ -2036,7 +2212,7 @@ process_serial_event (void)
if (own_buf[1] == 'g')
{
- if (thread_id == 0)
+ if (ptid_equal (thread_id, null_ptid))
{
/* GDB is telling us to choose any thread. Check if
the currently selected thread is still valid. If
@@ -2194,13 +2370,12 @@ process_serial_event (void)
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. */
@@ -2217,12 +2392,13 @@ process_serial_event (void)
}
case 'T':
{
- unsigned long gdb_id, thread_id;
+ ptid_t gdb_id, thread_id;
require_running (own_buf);
- gdb_id = strtoul (&own_buf[1], NULL, 16);
+
+ gdb_id = read_ptid (&own_buf[1], NULL);
thread_id = gdb_id_to_thread_id (gdb_id);
- if (thread_id == 0)
+ if (ptid_equal (thread_id, null_ptid))
{
write_enn (own_buf);
break;
@@ -2242,10 +2418,8 @@ process_serial_event (void)
if (extended_protocol)
{
if (target_running ())
- {
- kill_inferior ();
- discard_queued_stop_replies ();
- }
+ for_each_inferior (&all_processes,
+ kill_inferior_callback);
fprintf (stderr, "GDBserver restarting\n");
/* Wait till we are at 1st instruction in prog. */
@@ -2323,7 +2497,8 @@ handle_target_event (int err, gdb_client_data client_data)
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)
{