#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)
{