/* Main code for remote server for GDB.
- Copyright (C) 1989-2015 Free Software Foundation, Inc.
+ Copyright (C) 1989-2016 Free Software Foundation, Inc.
This file is part of GDB.
int server_waiting;
-int extended_protocol;
+static int extended_protocol;
static int response_needed;
static int exit_requested;
int report_fork_events;
int report_vfork_events;
int report_exec_events;
+int report_thread_events;
+
+/* Whether to report TARGET_WAITKING_NO_RESUMED events. */
+static int report_no_resumed;
+
int non_stop;
int swbreak_feature;
int hwbreak_feature;
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
}
while (last_status.value.sig != GDB_SIGNAL_TRAP);
}
- target_arch_setup ();
+ target_post_create_inferior ();
return signal_pid;
}
(assuming success). */
last_ptid = mywait (pid_to_ptid (signal_pid), &last_status, 0, 0);
- target_arch_setup ();
+ target_post_create_inferior ();
if (last_status.kind != TARGET_WAITKIND_EXITED
&& last_status.kind != TARGET_WAITKIND_SIGNALLED)
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)
if (handle_btrace_conf_general_set (own_buf))
return;
+ if (startswith (own_buf, "QThreadEvents:"))
+ {
+ char *mode = own_buf + strlen ("QThreadEvents:");
+ enum tribool req = TRIBOOL_UNKNOWN;
+
+ if (strcmp (mode, "0") == 0)
+ req = TRIBOOL_FALSE;
+ else if (strcmp (mode, "1") == 0)
+ req = TRIBOOL_TRUE;
+ else
+ {
+ char *mode_copy = xstrdup (mode);
+
+ /* We don't know what this mode is, so complain to GDB. */
+ sprintf (own_buf, "E.Unknown thread-events mode requested: %s\n",
+ mode_copy);
+ xfree (mode_copy);
+ return;
+ }
+
+ report_thread_events = (req == TRIBOOL_TRUE);
+
+ if (remote_debug)
+ {
+ const char *req_str = report_thread_events ? "enabled" : "disabled";
+
+ fprintf (stderr, "[thread events are now %s]\n", req_str);
+ }
+
+ write_ok (own_buf);
+ return;
+ }
+
/* Otherwise we didn't know what packet it was. Say we didn't
understand it. */
own_buf[0] = 0;
return NULL;
}
-void
+static void
monitor_show_help (void)
{
monitor_output ("The following monitor commands are supported:\n");
return 0;
}
-/* Table used by the crc32 function to calcuate the checksum. */
-
-static unsigned int crc32_table[256] =
-{0, 0};
-
/* Compute 32 bit CRC from inferior memory.
On success, return 32 bit CRC.
static unsigned long long
crc32 (CORE_ADDR base, int len, unsigned int crc)
{
- if (!crc32_table[1])
- {
- /* Initialize the CRC table and the decoding table. */
- int i, j;
- unsigned int c;
-
- for (i = 0; i < 256; i++)
- {
- for (c = i << 24, j = 8; j > 0; --j)
- c = c & 0x80000000 ? (c << 1) ^ 0x04c11db7 : (c << 1);
- crc32_table[i] = c;
- }
- }
-
while (len--)
{
unsigned char byte = 0;
if (read_inferior_memory (base, &byte, 1) != 0)
return (unsigned long long) -1;
- crc = (crc << 8) ^ crc32_table[((crc >> 24) ^ byte) & 255];
+ crc = xcrc32 (&byte, 1, crc);
base++;
}
return (unsigned long long) crc;
/* 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;
}
else if (strcmp (p, "vContSupported+") == 0)
vCont_supported = 1;
+ else if (strcmp (p, "QThreadEvents+") == 0)
+ ;
+ else if (strcmp (p, "no-resumed+") == 0)
+ {
+ /* GDB supports and wants TARGET_WAITKIND_NO_RESUMED
+ events. */
+ report_no_resumed = 1;
+ }
else
{
/* Move the unknown features all together. */
"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+");
strcat (own_buf, ";tracenz+");
}
- if (target_supports_hardware_single_step ())
+ if (target_supports_hardware_single_step ()
+ || target_supports_software_single_step () )
{
- /* Support target-side breakpoint conditions and commands.
- GDBserver needs to step over the breakpoint if the condition
- is false. GDBserver software single step is too simple, so
- disable conditional breakpoints if the target doesn't have
- hardware single step. */
strcat (own_buf, ";ConditionalBreakpoints+");
}
strcat (own_buf, ";BreakpointCommands+");
strcat (own_buf, ";vContSupported+");
+ strcat (own_buf, ";QThreadEvents+");
+
+ strcat (own_buf, ";no-resumed+");
+
/* Reinitialize components as needed for the new connection. */
hostio_handle_new_gdb_connection ();
target_handle_new_gdb_connection ();
}
/* Parse vCont packets. */
-void
+static void
handle_v_cont (char *own_buf)
{
char *p, *q;
{
last_ptid = mywait (minus_one_ptid, &last_status, 0, 1);
- if (last_status.kind == TARGET_WAITKIND_NO_RESUMED)
+ if (last_status.kind == TARGET_WAITKIND_NO_RESUMED
+ && !report_no_resumed)
{
- /* No proper RSP support for this yet. At least return
- error. */
+ /* The client does not support this stop reply. At least
+ return error. */
sprintf (own_buf, "E.No unwaited-for children left.");
disable_async_io ();
return;
}
/* 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 (!disable_packet_vCont)
{
+ if (strcmp (own_buf, "vCtrlC") == 0)
+ {
+ (*the_target->request_interrupt) ();
+ write_ok (own_buf);
+ return;
+ }
+
if (startswith (own_buf, "vCont;"))
{
require_running (own_buf);
gdbserver_version (void)
{
printf ("GNU gdbserver %s%s\n"
- "Copyright (C) 2015 Free Software Foundation, Inc.\n"
+ "Copyright (C) 2016 Free Software Foundation, Inc.\n"
"gdbserver is free software, covered by the "
"GNU General Public License.\n"
"This gdbserver was configured as \"%s\"\n",
start_event_loop ();
/* If an exit was requested (using the "monitor exit"
- command), terminate now. The only other way to get
- here is for getpkt to fail; close the connection
- and reopen it at the top of the loop. */
+ command), terminate now. */
+ if (exit_requested)
+ throw_quit ("Quit");
+
+ /* The only other way to get here is for getpkt to fail:
+
+ - If --once was specified, we're done.
- if (exit_requested || run_once)
+ - If not in extended-remote mode, and we're no longer
+ debugging anything, simply exit: GDB has disconnected
+ after processing the last process exit.
+
+ - Otherwise, close the connection and reopen it at the
+ top of the loop. */
+ if (run_once || (!extended_protocol && !target_running ()))
throw_quit ("Quit");
fprintf (stderr,
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. */
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;
int packet_len;
int new_packet_len = -1;
- /* Used to decide when gdbserver should exit in
- multi-mode/remote. */
- static int have_ran = 0;
-
- if (!have_ran)
- have_ran = target_running ();
-
disable_async_io ();
response_needed = 0;
discard_queued_stop_replies (pid_to_ptid (pid));
write_ok (own_buf);
- if (extended_protocol)
+ if (extended_protocol || target_running ())
{
- /* Treat this like a normal program exit. */
+ /* There is still at least one inferior remaining or
+ we are in extended mode, so don't terminate gdbserver,
+ and instead treat this like a normal program exit. */
last_status.kind = TARGET_WAITKIND_EXITED;
last_status.value.integer = 0;
last_ptid = pid_to_ptid (pid);
response_needed = 0;
- if (!extended_protocol && have_ran && !target_running ())
- {
- /* In non-stop, defer exiting until GDB had a chance to query
- the whole vStopped list (until it gets an OK). */
- if (QUEUE_is_empty (notif_event_p, notif_stop.queue))
- {
- /* Be transparent when GDB is connected through stdio -- no
- need to spam GDB's console. */
- if (!remote_connection_is_stdio ())
- fprintf (stderr, "GDBserver exiting\n");
- remote_close ();
- exit (0);
- }
- }
-
if (exit_requested)
return -1;
return 0;
}
+/* Push a stop notification on the notification queue. */
+
+static void
+push_stop_notification (ptid_t ptid, struct target_waitstatus *status)
+{
+ struct vstop_notif *vstop_notif = XNEW (struct vstop_notif);
+
+ vstop_notif->status = *status;
+ vstop_notif->ptid = ptid;
+ /* Push Stop notification. */
+ notif_push (¬if_stop, (struct notif_event *) vstop_notif);
+}
+
/* Event-loop callback for target events. */
int
if (last_status.kind == TARGET_WAITKIND_NO_RESUMED)
{
- /* No RSP support for this yet. */
+ if (gdb_connected () && report_no_resumed)
+ push_stop_notification (null_ptid, &last_status);
}
else if (last_status.kind != TARGET_WAITKIND_IGNORE)
{
mark_breakpoints_out (process);
mourn_inferior (process);
}
+ else if (last_status.kind == TARGET_WAITKIND_THREAD_EXITED)
+ ;
else
{
/* We're reporting this thread as stopped. Update its
exit (0);
}
- if (last_status.kind == TARGET_WAITKIND_STOPPED)
+ if (last_status.kind == TARGET_WAITKIND_EXITED
+ || last_status.kind == TARGET_WAITKIND_SIGNALLED
+ || last_status.kind == TARGET_WAITKIND_THREAD_EXITED)
+ ;
+ else
{
/* A thread stopped with a signal, but gdb isn't
connected to handle it. Pass it down to the
resume_info.thread = last_ptid;
resume_info.kind = resume_continue;
- resume_info.sig = gdb_signal_to_host (last_status.value.sig);
+ if (last_status.kind == TARGET_WAITKIND_STOPPED)
+ resume_info.sig = gdb_signal_to_host (last_status.value.sig);
+ else
+ resume_info.sig = 0;
(*the_target->resume) (&resume_info, 1);
}
- else if (debug_threads)
- debug_printf ("GDB not connected; ignoring event %d for [%s]\n",
- (int) last_status.kind,
- target_pid_to_str (last_ptid));
}
else
- {
- struct vstop_notif *vstop_notif = XNEW (struct vstop_notif);
-
- vstop_notif->status = last_status;
- vstop_notif->ptid = last_ptid;
- /* Push Stop notification. */
- notif_push (¬if_stop,
- (struct notif_event *) vstop_notif);
- }
+ push_stop_notification (last_ptid, &last_status);
}
/* Be sure to not change the selected thread behind GDB's back.