/* Main code for remote server for GDB.
- Copyright (C) 1989-2015 Free Software Foundation, Inc.
+ Copyright (C) 1989-2017 Free Software Foundation, Inc.
This file is part of GDB.
#include "notif.h"
#include "tdesc.h"
#include "rsp-low.h"
-
+#include "signals-state-save-restore.h"
#include <ctype.h>
#include <unistd.h>
#if HAVE_SIGNAL_H
static struct target_waitstatus last_status;
static ptid_t last_ptid;
-static char *own_buf;
+char *own_buf;
static unsigned char *mem_buf;
/* A sub-class of 'struct notif_event' for stop, holding information
prepare_resume_reply (own_buf, vstop->ptid, &vstop->status);
}
+/* QUEUE_iterate callback helper for in_queued_stop_replies. */
+
+static int
+in_queued_stop_replies_ptid (QUEUE (notif_event_p) *q,
+ QUEUE_ITER (notif_event_p) *iter,
+ struct notif_event *event,
+ void *data)
+{
+ ptid_t filter_ptid = *(ptid_t *) data;
+ struct vstop_notif *vstop_event = (struct vstop_notif *) event;
+
+ if (ptid_match (vstop_event->ptid, filter_ptid))
+ return 0;
+
+ /* Don't resume fork children that GDB does not know about yet. */
+ if ((vstop_event->status.kind == TARGET_WAITKIND_FORKED
+ || vstop_event->status.kind == TARGET_WAITKIND_VFORKED)
+ && ptid_match (vstop_event->status.value.related_pid, filter_ptid))
+ return 0;
+
+ return 1;
+}
+
+/* See server.h. */
+
+int
+in_queued_stop_replies (ptid_t ptid)
+{
+ return !QUEUE_iterate (notif_event_p, notif_stop.queue,
+ in_queued_stop_replies_ptid, &ptid);
+}
+
struct notif_server notif_stop =
{
"vStopped", "Stop", NULL, vstop_notif_reply,
if (wrapper_argv != NULL)
{
- struct thread_resume resume_info;
-
- memset (&resume_info, 0, sizeof (resume_info));
- resume_info.thread = pid_to_ptid (signal_pid);
- resume_info.kind = resume_continue;
- resume_info.sig = 0;
+ ptid_t ptid = pid_to_ptid (signal_pid);
last_ptid = mywait (pid_to_ptid (signal_pid), &last_status, 0, 0);
{
do
{
- (*the_target->resume) (&resume_info, 1);
+ target_continue_no_signal (ptid);
last_ptid = mywait (pid_to_ptid (signal_pid), &last_status, 0, 0);
if (last_status.kind != TARGET_WAITKIND_STOPPED)
(assuming success). */
last_ptid = mywait (pid_to_ptid (signal_pid), &last_status, 0, 0);
- target_post_create_inferior ();
-
+ /* At this point, the target process, if it exits, is stopped. Do not call
+ the function target_post_create_inferior if the process has already
+ exited, as the target implementation of the routine may rely on the
+ process being live. */
if (last_status.kind != TARGET_WAITKIND_EXITED
&& last_status.kind != TARGET_WAITKIND_SIGNALLED)
{
+ target_post_create_inferior ();
current_thread->last_resume_kind = resume_stop;
current_thread->last_status = last_status;
}
else
- mourn_inferior (find_process_pid (ptid_get_pid (last_ptid)));
+ target_mourn_inferior (last_ptid);
return signal_pid;
}
return NULL;
}
-/* Handle btrace enabling in Intel(R) Processor Trace format. */
+/* Handle btrace enabling in Intel Processor Trace format. */
static const char *
handle_btrace_enable_pt (struct thread_info *thread)
return;
}
+ if (startswith (own_buf, "QCatchSyscalls:"))
+ {
+ const char *p = own_buf + sizeof ("QCatchSyscalls:") - 1;
+ int enabled = -1;
+ CORE_ADDR sysno;
+ struct process_info *process;
+
+ if (!target_running () || !target_supports_catch_syscall ())
+ {
+ write_enn (own_buf);
+ return;
+ }
+
+ if (strcmp (p, "0") == 0)
+ enabled = 0;
+ else if (p[0] == '1' && (p[1] == ';' || p[1] == '\0'))
+ enabled = 1;
+ else
+ {
+ fprintf (stderr, "Unknown catch-syscalls mode requested: %s\n",
+ own_buf);
+ write_enn (own_buf);
+ return;
+ }
+
+ process = current_process ();
+ VEC_truncate (int, process->syscalls_to_catch, 0);
+
+ if (enabled)
+ {
+ p += 1;
+ if (*p == ';')
+ {
+ p += 1;
+ while (*p != '\0')
+ {
+ p = decode_address_to_semicolon (&sysno, p);
+ VEC_safe_push (int, process->syscalls_to_catch, (int) sysno);
+ }
+ }
+ else
+ VEC_safe_push (int, process->syscalls_to_catch, ANY_SYSCALL);
+ }
+
+ write_ok (own_buf);
+ return;
+ }
+
if (strcmp (own_buf, "QStartNoAckMode") == 0)
{
if (remote_debug)
{
- fprintf (stderr, "[noack mode enabled]\n");
- fflush (stderr);
+ debug_printf ("[noack mode enabled]\n");
+ debug_flush ();
}
noack_mode = 1;
non_stop = req;
if (remote_debug)
- fprintf (stderr, "[%s mode enabled]\n", req_str);
+ debug_printf ("[%s mode enabled]\n", req_str);
write_ok (own_buf);
return;
if (remote_debug)
{
- if (disable_randomization)
- fprintf (stderr, "[address space randomization disabled]\n");
- else
- fprintf (stderr, "[address space randomization enabled]\n");
+ debug_printf (disable_randomization
+ ? "[address space randomization disabled]\n"
+ : "[address space randomization enabled]\n");
}
write_ok (own_buf);
/* Update the flag. */
use_agent = req;
if (remote_debug)
- fprintf (stderr, "[%s agent]\n", req ? "Enable" : "Disable");
+ debug_printf ("[%s agent]\n", req ? "Enable" : "Disable");
write_ok (own_buf);
return;
}
{
const char *req_str = report_thread_events ? "enabled" : "disabled";
- fprintf (stderr, "[thread events are now %s]\n", req_str);
+ debug_printf ("[thread events are now %s]\n", req_str);
}
write_ok (own_buf);
return NULL;
}
-void
+static void
monitor_show_help (void)
{
monitor_output ("The following monitor commands are supported:\n");
/* Handle all of the extended 'q' packets. */
-void
+static void
handle_query (char *own_buf, int packet_len, int *new_packet_len_p)
{
static struct inferior_list_entry *thread_ptr;
"PacketSize=%x;QPassSignals+;QProgramSignals+",
PBUFSIZ - 1);
+ if (target_supports_catch_syscall ())
+ strcat (own_buf, ";QCatchSyscalls+");
+
if (the_target->qxfer_libraries_svr4 != NULL)
strcat (own_buf, ";qXfer:libraries-svr4:read+"
";augmented-libraries-svr4-read+");
}
/* Parse vCont packets. */
-void
+static void
handle_v_cont (char *own_buf)
{
char *p, *q;
if (last_status.kind == TARGET_WAITKIND_EXITED
|| last_status.kind == TARGET_WAITKIND_SIGNALLED)
- mourn_inferior (find_process_pid (ptid_get_pid (last_ptid)));
+ target_mourn_inferior (last_ptid);
}
}
/* Attach to a new program. Return 1 if successful, 0 if failure. */
-int
+static int
handle_v_attach (char *own_buf)
{
int pid;
}
/* Kill process. Return 1 if successful, 0 if failure. */
-int
+static int
handle_v_kill (char *own_buf)
{
int pid;
if (startswith (own_buf, "vCont;"))
{
- require_running (own_buf);
handle_v_cont (own_buf);
return;
}
{
strcpy (own_buf, "vCont;c;C;t");
- if (target_supports_hardware_single_step () || !vCont_supported)
+ if (target_supports_hardware_single_step ()
+ || target_supports_software_single_step ()
+ || !vCont_supported)
{
- /* If target supports hardware single step, add actions s
- and S to the list of supported actions. On the other
- hand, if GDB doesn't request the supported vCont actions
- in qSupported packet, add s and S to the list too. */
+ /* If target supports single step either by hardware or by
+ software, add actions s and S to the list of supported
+ actions. On the other hand, if GDB doesn't request the
+ supported vCont actions in qSupported packet, add s and
+ S to the list too. */
own_buf = own_buf + strlen (own_buf);
strcpy (own_buf, ";s;S");
}
gdbserver_version (void)
{
printf ("GNU gdbserver %s%s\n"
- "Copyright (C) 2016 Free Software Foundation, Inc.\n"
+ "Copyright (C) 2017 Free Software Foundation, Inc.\n"
"gdbserver is free software, covered by the "
"GNU General Public License.\n"
"This gdbserver was configured as \"%s\"\n",
opened by remote_prepare. */
notice_open_fds ();
+ save_original_signals_state ();
+
/* We need to know whether the remote connection is stdio before
starting the inferior. Inferiors created in this scenario have
stdin,stdout redirected. So do this here before we call
gdb_assert_not_reached ("captured_main should never return");
}
-/* Skip PACKET until the next semi-colon (or end of string). */
-
-static void
-skip_to_semicolon (char **packet)
-{
- while (**packet != '\0' && **packet != ';')
- (*packet)++;
-}
-
/* Process options coming from Z packets for a breakpoint. PACKET is
the packet buffer. *PACKET is updated to point to the first char
after the last processed option. */
static void
-process_point_options (struct breakpoint *bp, char **packet)
+process_point_options (struct gdb_breakpoint *bp, char **packet)
{
char *dataptr = *packet;
int persist;
if (debug_threads)
debug_printf ("Found breakpoint condition.\n");
if (!add_breakpoint_condition (bp, &dataptr))
- skip_to_semicolon (&dataptr);
+ dataptr = strchrnul (dataptr, ';');
}
else if (startswith (dataptr, "cmds:"))
{
persist = (*dataptr == '1');
dataptr += 2;
if (add_breakpoint_commands (bp, &dataptr, persist))
- skip_to_semicolon (&dataptr);
+ dataptr = strchrnul (dataptr, ';');
}
else
{
fprintf (stderr, "Unknown token %c, ignoring.\n",
*dataptr);
/* Skip tokens until we find one that we recognize. */
- skip_to_semicolon (&dataptr);
+ dataptr = strchrnul (dataptr, ';');
}
}
*packet = dataptr;
if ((tracing && disconnected_tracing) || any_persistent_commands ())
{
- struct thread_resume resume_info;
struct process_info *process = find_process_pid (pid);
if (process == NULL)
process->gdb_detached = 1;
/* Detaching implicitly resumes all threads. */
- resume_info.thread = minus_one_ptid;
- resume_info.kind = resume_continue;
- resume_info.sig = 0;
- (*the_target->resume) (&resume_info, 1);
+ target_continue_no_signal (minus_one_ptid);
write_ok (own_buf);
break; /* from switch/case */
if (insert)
{
- struct breakpoint *bp;
+ struct gdb_breakpoint *bp;
bp = set_gdb_breakpoint (type, addr, kind, &res);
if (bp != NULL)
|| last_status.kind == TARGET_WAITKIND_SIGNALLED)
{
mark_breakpoints_out (process);
- mourn_inferior (process);
+ target_mourn_inferior (last_ptid);
}
else if (last_status.kind == TARGET_WAITKIND_THREAD_EXITED)
;
/* A thread stopped with a signal, but gdb isn't
connected to handle it. Pass it down to the
inferior, as if it wasn't being traced. */
- struct thread_resume resume_info;
+ enum gdb_signal signal;
if (debug_threads)
debug_printf ("GDB not connected; forwarding event %d for"
(int) last_status.kind,
target_pid_to_str (last_ptid));
- resume_info.thread = last_ptid;
- resume_info.kind = resume_continue;
if (last_status.kind == TARGET_WAITKIND_STOPPED)
- resume_info.sig = gdb_signal_to_host (last_status.value.sig);
+ signal = last_status.value.sig;
else
- resume_info.sig = 0;
- (*the_target->resume) (&resume_info, 1);
+ signal = GDB_SIGNAL_0;
+ target_continue (last_ptid, signal);
}
}
else