From 95954743cb49efcc384c378173606fd309b6e6ac Mon Sep 17 00:00:00 2001 From: Pedro Alves Date: Wed, 1 Apr 2009 22:50:24 +0000 Subject: 2009-04-01 Pedro Alves 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) : Change type to ptid_t. (struct target_waitstatus) : Ditto. (struct target_ops) : Add `pid' argument. Change return type to int. (struct target_ops) : Add `pid' argument. (struct target_ops) : Change pid's type to ptid_t. (struct target_ops) : 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) : 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) : 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) : Use ptid_get_pid. : 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) : 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. --- gdb/gdbserver/server.c | 369 ++++++++++++++++++++++++++++++++++++------------- 1 file changed, 272 insertions(+), 97 deletions(-) (limited to 'gdb/gdbserver/server.c') 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 #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) { -- cgit v1.1