/* Remote target communications for serial-line targets in custom GDB protocol
- Copyright (C) 1988-2015 Free Software Foundation, Inc.
+ Copyright (C) 1988-2016 Free Software Foundation, Inc.
This file is part of GDB.
enum { REMOTE_ALIGN_WRITES = 16 };
/* Prototypes for local functions. */
-static void async_cleanup_sigint_signal_handler (void *dummy);
static int getpkt_sane (char **buf, long *sizeof_buf, int forever);
static int getpkt_or_notif_sane (char **buf, long *sizeof_buf,
int forever, int *is_notif);
-static void async_handle_remote_sigint (int);
-static void async_handle_remote_sigint_twice (int);
-
static void remote_files_info (struct target_ops *ignore);
static void remote_prepare_to_store (struct target_ops *self,
static int remote_vkill (int pid, struct remote_state *rs);
+static void remote_kill_k (void);
+
static void remote_mourn (struct target_ops *ops);
static void extended_remote_restart (void);
-static void extended_remote_mourn (struct target_ops *);
-
static void remote_send (char **buf, long *sizeof_buf_p);
static int readchar (int timeout);
static void remote_async (struct target_ops *ops, int enable);
-static void sync_remote_interrupt_twice (int signo);
+static void remote_thread_events (struct target_ops *ops, int enable);
static void interrupt_query (void);
static void readahead_cache_invalidate (void);
+static void remote_unpush_and_throw (void);
+
/* For "remote". */
static struct cmd_list_element *remote_cmdlist;
responded to that. */
int ctrlc_pending_p;
+ /* True if we saw a Ctrl-C while reading or writing from/to the
+ remote descriptor. At that point it is not safe to send a remote
+ interrupt packet, so we instead remember we saw the Ctrl-C and
+ process it once we're done with sending/receiving the current
+ packet, which should be shortly. If however that takes too long,
+ and the user presses Ctrl-C again, we offer to disconnect. */
+ int got_ctrlc_during_io;
+
/* Descriptor for I/O to remote machine. Initialize it to NULL so that
remote_open knows that we don't have a file open when the program
starts. */
int last_sent_step;
+ /* The execution direction of the last resume we got. */
+ enum exec_direction_kind last_resume_exec_dir;
+
char *finished_object;
char *finished_annex;
ULONGEST finished_offset;
int use_threadinfo_query;
int use_threadextra_query;
- /* This is set to the data address of the access causing the target
- to stop for a watchpoint. */
- CORE_ADDR remote_watch_data_address;
-
- /* Whether the target stopped for a breakpoint/watchpoint. */
- enum target_stop_reason stop_reason;
-
threadref echo_nextthread;
threadref nextthread;
threadref resultthreadlist[MAXTHREADLISTRESULTS];
struct private_thread_info
{
char *extra;
+ char *name;
int core;
+
+ /* Whether the target stopped for a breakpoint/watchpoint. */
+ enum target_stop_reason stop_reason;
+
+ /* This is set to the data address of the access causing the target
+ to stop for a watchpoint. */
+ CORE_ADDR watch_data_address;
};
static void
free_private_thread_info (struct private_thread_info *info)
{
xfree (info->extra);
+ xfree (info->name);
xfree (info);
}
result->buf = (char *) xmalloc (result->buf_size);
result->remote_traceframe_number = -1;
result->last_sent_signal = GDB_SIGNAL_0;
+ result->last_resume_exec_dir = EXEC_FORWARD;
result->fs_pid = -1;
return result;
remote_register_number_and_offset (struct gdbarch *gdbarch, int regnum,
int *pnum, int *poffset)
{
- int sizeof_g_packet;
struct packet_reg *regs;
struct cleanup *old_chain;
regs = XCNEWVEC (struct packet_reg, gdbarch_num_regs (gdbarch));
old_chain = make_cleanup (xfree, regs);
- sizeof_g_packet = map_regcache_remote_table (gdbarch, regs);
+ map_regcache_remote_table (gdbarch, regs);
*pnum = regs[regnum].pnum;
*poffset = regs[regnum].offset;
PACKET_qSupported,
PACKET_qTStatus,
PACKET_QPassSignals,
+ PACKET_QCatchSyscalls,
PACKET_QProgramSignals,
PACKET_qCRC,
PACKET_qSearch_memory,
/* Support for the QNonStop packet. */
PACKET_QNonStop,
+ /* Support for the QThreadEvents packet. */
+ PACKET_QThreadEvents,
+
/* Support for multi-process extensions. */
PACKET_multiprocess_feature,
/* Support for query supported vCont actions. */
PACKET_vContSupported,
+ /* Support remote CTRL-C. */
+ PACKET_vCtrlC,
+
+ /* Support TARGET_WAITKIND_NO_RESUMED. */
+ PACKET_no_resumed,
+
PACKET_MAX
};
return 0;
}
-/* Tokens for use by the asynchronous signal handlers for SIGINT. */
-static struct async_signal_handler *async_sigint_remote_twice_token;
-static struct async_signal_handler *async_sigint_remote_token;
-
\f
/* Asynchronous signal handle registered as event loop source for
when we have pending events ready to be passed to the core. */
according to RUNNING. */
static void
-remote_add_thread (ptid_t ptid, int running)
+remote_add_thread (ptid_t ptid, int running, int executing)
{
struct remote_state *rs = get_remote_state ();
else
add_thread (ptid);
- set_executing (ptid, running);
+ set_executing (ptid, executing);
set_running (ptid, running);
}
It may be the first time we hear about such thread, so take the
opportunity to add it to GDB's thread list. In case this is the
first time we're noticing its corresponding inferior, add it to
- GDB's inferior list as well. */
+ GDB's inferior list as well. EXECUTING indicates whether the
+ thread is (internally) executing or stopped. */
static void
-remote_notice_new_inferior (ptid_t currthread, int running)
+remote_notice_new_inferior (ptid_t currthread, int executing)
{
+ /* In non-stop mode, we assume new found threads are (externally)
+ running until proven otherwise with a stop reply. In all-stop,
+ we can only get here if all threads are stopped. */
+ int running = target_is_non_stop_p () ? 1 : 0;
+
/* If this is a new thread, add it to GDB's thread list.
If we leave it up to WFI to do this, bad things will happen. */
{
/* We're seeing an event on a thread id we knew had exited.
This has to be a new thread reusing the old id. Add it. */
- remote_add_thread (currthread, running);
+ remote_add_thread (currthread, running, executing);
return;
}
thread_change_ptid (inferior_ptid, currthread);
else
{
- remote_add_thread (currthread, running);
+ remote_add_thread (currthread, running, executing);
inferior_ptid = currthread;
}
return;
}
/* This is really a new thread. Add it. */
- remote_add_thread (currthread, running);
+ remote_add_thread (currthread, running, executing);
/* If we found a new inferior, let the common code do whatever
it needs to with it (e.g., read shared libraries, insert
{
struct remote_state *rs = get_remote_state ();
- if (non_stop || !rs->starting_up)
- notice_new_inferior (currthread, running, 0);
+ if (!rs->starting_up)
+ notice_new_inferior (currthread, executing, 0);
}
}
}
info->priv = XNEW (struct private_thread_info);
info->private_dtor = free_private_thread_info;
info->priv->core = -1;
- info->priv->extra = 0;
+ info->priv->extra = NULL;
+ info->priv->name = NULL;
}
return info->priv;
}
}
+/* If 'QCatchSyscalls' is supported, tell the remote stub
+ to report syscalls to GDB. */
+
+static int
+remote_set_syscall_catchpoint (struct target_ops *self,
+ int pid, int needed, int any_count,
+ int table_size, int *table)
+{
+ char *catch_packet;
+ enum packet_result result;
+ int n_sysno = 0;
+
+ if (packet_support (PACKET_QCatchSyscalls) == PACKET_DISABLE)
+ {
+ /* Not supported. */
+ return 1;
+ }
+
+ if (needed && !any_count)
+ {
+ int i;
+
+ /* Count how many syscalls are to be caught (table[sysno] != 0). */
+ for (i = 0; i < table_size; i++)
+ {
+ if (table[i] != 0)
+ n_sysno++;
+ }
+ }
+
+ if (remote_debug)
+ {
+ fprintf_unfiltered (gdb_stdlog,
+ "remote_set_syscall_catchpoint "
+ "pid %d needed %d any_count %d n_sysno %d\n",
+ pid, needed, any_count, n_sysno);
+ }
+
+ if (needed)
+ {
+ /* Prepare a packet with the sysno list, assuming max 8+1
+ characters for a sysno. If the resulting packet size is too
+ big, fallback on the non-selective packet. */
+ const int maxpktsz = strlen ("QCatchSyscalls:1") + n_sysno * 9 + 1;
+
+ catch_packet = (char *) xmalloc (maxpktsz);
+ strcpy (catch_packet, "QCatchSyscalls:1");
+ if (!any_count)
+ {
+ int i;
+ char *p;
+
+ p = catch_packet;
+ p += strlen (p);
+
+ /* Add in catch_packet each syscall to be caught (table[i] != 0). */
+ for (i = 0; i < table_size; i++)
+ {
+ if (table[i] != 0)
+ p += xsnprintf (p, catch_packet + maxpktsz - p, ";%x", i);
+ }
+ }
+ if (strlen (catch_packet) > get_remote_packet_size ())
+ {
+ /* catch_packet too big. Fallback to less efficient
+ non selective mode, with GDB doing the filtering. */
+ catch_packet[sizeof ("QCatchSyscalls:1") - 1] = 0;
+ }
+ }
+ else
+ catch_packet = xstrdup ("QCatchSyscalls:0");
+
+ {
+ struct cleanup *old_chain = make_cleanup (xfree, catch_packet);
+ struct remote_state *rs = get_remote_state ();
+
+ putpkt (catch_packet);
+ getpkt (&rs->buf, &rs->buf_size, 0);
+ result = packet_ok (rs->buf, &remote_protocol_packets[PACKET_QCatchSyscalls]);
+ do_cleanups (old_chain);
+ if (result == PACKET_OK)
+ return 0;
+ else
+ return -1;
+ }
+}
+
/* If 'QProgramSignals' is supported, tell the remote stub what
signals it should pass through to the inferior when detaching. */
struct remote_state *rs = get_remote_state ();
/* If the remote can't handle multiple processes, don't bother. */
- if (!rs->extended || !remote_multi_process_p (rs))
+ if (!remote_multi_process_p (rs))
return;
/* We only need to change the remote current thread if it's pointing
static int
remote_thread_always_alive (struct target_ops *ops, ptid_t ptid)
{
- struct remote_state *rs = get_remote_state ();
- char *p, *endp;
-
if (ptid_equal (ptid, magic_null_ptid))
/* The main thread is always alive. */
return 1;
return (rs->buf[0] == 'O' && rs->buf[1] == 'K');
}
+/* Return a pointer to a thread name if we know it and NULL otherwise.
+ The thread_info object owns the memory for the name. */
+
+static const char *
+remote_thread_name (struct target_ops *ops, struct thread_info *info)
+{
+ if (info->priv != NULL)
+ return info->priv->name;
+
+ return NULL;
+}
+
/* About these extended threadlist and threadinfo packets. They are
variable length packets but, the fields within them are often fixed
length. They are redundent enough to send over UDP as is the
/* The thread's extra info. May be NULL. */
char *extra;
+ /* The thread's name. May be NULL. */
+ char *name;
+
/* The core the thread was running on. -1 if not known. */
int core;
} thread_item_t;
struct thread_item *item;
for (i = 0; VEC_iterate (thread_item_t, context->items, i, item); ++i)
- xfree (item->extra);
+ {
+ xfree (item->extra);
+ xfree (item->name);
+ }
VEC_free (thread_item_t, context->items);
}
item.ptid = ptid_build (pid, threadref_to_int (ref), 0);
item.core = -1;
+ item.name = NULL;
item.extra = NULL;
VEC_safe_push (thread_item_t, context->items, &item);
else
item.core = -1;
+ attr = xml_find_attribute (attributes, "name");
+ item.name = attr != NULL ? xstrdup ((const char *) attr->value) : NULL;
+
item.extra = 0;
VEC_safe_push (thread_item_t, data->items, &item);
const struct gdb_xml_attribute thread_attributes[] = {
{ "id", GDB_XML_AF_NONE, NULL, NULL },
{ "core", GDB_XML_AF_OPTIONAL, gdb_xml_parse_attr_ulongest, NULL },
+ { "name", GDB_XML_AF_OPTIONAL, NULL, NULL },
{ NULL, GDB_XML_AF_NONE, NULL, NULL }
};
item.ptid = read_ptid (bufp, &bufp);
item.core = -1;
+ item.name = NULL;
item.extra = NULL;
VEC_safe_push (thread_item_t, context->items, &item);
static void
remote_update_thread_list (struct target_ops *ops)
{
- struct remote_state *rs = get_remote_state ();
struct threads_listing_context context;
struct cleanup *old_chain;
int got_list = 0;
{
struct private_thread_info *info;
/* In non-stop mode, we assume new found threads are
- running until proven otherwise with a stop reply. In
- all-stop, we can only get here if all threads are
+ executing until proven otherwise with a stop reply.
+ In all-stop, we can only get here if all threads are
stopped. */
- int running = non_stop ? 1 : 0;
+ int executing = target_is_non_stop_p () ? 1 : 0;
- remote_notice_new_inferior (item->ptid, running);
+ remote_notice_new_inferior (item->ptid, executing);
info = demand_private_info (item->ptid);
info->core = item->core;
info->extra = item->extra;
item->extra = NULL;
+ info->name = item->name;
+ item->name = NULL;
}
}
}
if (rs->remote_desc == NULL)
return; /* already closed */
- /* Make sure we leave stdin registered in the event loop, and we
- don't leave the async SIGINT signal handler installed. */
+ /* Make sure we leave stdin registered in the event loop. */
remote_terminal_ours (self);
serial_close (rs->remote_desc);
add_thread_silent (inferior_ptid);
}
+/* Print info about a thread that was found already stopped on
+ connection. */
+
+static void
+print_one_stopped_thread (struct thread_info *thread)
+{
+ struct target_waitstatus *ws = &thread->suspend.waitstatus;
+
+ switch_to_thread (thread->ptid);
+ stop_pc = get_frame_pc (get_current_frame ());
+ set_current_sal_from_frame (get_current_frame ());
+
+ thread->suspend.waitstatus_pending_p = 0;
+
+ if (ws->kind == TARGET_WAITKIND_STOPPED)
+ {
+ enum gdb_signal sig = ws->value.sig;
+
+ if (signal_print_state (sig))
+ observer_notify_signal_received (sig);
+ }
+ observer_notify_normal_stop (NULL, 1);
+}
+
/* Process all initial stop replies the remote side sent in response
to the ? packet. These indicate threads that were already stopped
on initial connection. We mark these threads as stopped and print
their current frame before giving the user the prompt. */
static void
-process_initial_stop_replies (void)
+process_initial_stop_replies (int from_tty)
{
int pending_stop_replies = stop_reply_queue_length ();
+ struct inferior *inf;
+ struct thread_info *thread;
+ struct thread_info *selected = NULL;
+ struct thread_info *lowest_stopped = NULL;
+ struct thread_info *first = NULL;
/* Consume the initial pending events. */
while (pending_stop_replies-- > 0)
ptid_t event_ptid;
struct target_waitstatus ws;
int ignore_event = 0;
+ struct thread_info *thread;
memset (&ws, 0, sizeof (ws));
event_ptid = target_wait (waiton_ptid, &ws, TARGET_WNOHANG);
if (ignore_event)
continue;
- switch_to_thread (event_ptid);
- set_executing (event_ptid, 0);
- set_running (event_ptid, 0);
-
- stop_pc = get_frame_pc (get_current_frame ());
- set_current_sal_from_frame (get_current_frame ());
+ thread = find_thread_ptid (event_ptid);
if (ws.kind == TARGET_WAITKIND_STOPPED)
{
instead of signal 0. Suppress it. */
if (sig == GDB_SIGNAL_TRAP)
sig = GDB_SIGNAL_0;
- inferior_thread ()->suspend.stop_signal = sig;
+ thread->suspend.stop_signal = sig;
+ ws.value.sig = sig;
+ }
- if (signal_print_state (sig))
- observer_notify_signal_received (sig);
- }
+ thread->suspend.waitstatus = ws;
+
+ if (ws.kind != TARGET_WAITKIND_STOPPED
+ || ws.value.sig != GDB_SIGNAL_0)
+ thread->suspend.waitstatus_pending_p = 1;
+
+ set_executing (event_ptid, 0);
+ set_running (event_ptid, 0);
+ }
+
+ /* "Notice" the new inferiors before anything related to
+ registers/memory. */
+ ALL_INFERIORS (inf)
+ {
+ if (inf->pid == 0)
+ continue;
+
+ inf->needs_setup = 1;
+
+ if (non_stop)
+ {
+ thread = any_live_thread_of_process (inf->pid);
+ notice_new_inferior (thread->ptid,
+ thread->state == THREAD_RUNNING,
+ from_tty);
+ }
+ }
+
+ /* If all-stop on top of non-stop, pause all threads. Note this
+ records the threads' stop pc, so must be done after "noticing"
+ the inferiors. */
+ if (!non_stop)
+ {
+ stop_all_threads ();
+
+ /* If all threads of an inferior were already stopped, we
+ haven't setup the inferior yet. */
+ ALL_INFERIORS (inf)
+ {
+ if (inf->pid == 0)
+ continue;
+
+ if (inf->needs_setup)
+ {
+ thread = any_live_thread_of_process (inf->pid);
+ switch_to_thread_no_regs (thread);
+ setup_inferior (0);
+ }
+ }
+ }
+
+ /* Now go over all threads that are stopped, and print their current
+ frame. If all-stop, then if there's a signalled thread, pick
+ that as current. */
+ ALL_NON_EXITED_THREADS (thread)
+ {
+ if (first == NULL)
+ first = thread;
+
+ if (!non_stop)
+ set_running (thread->ptid, 0);
+ else if (thread->state != THREAD_STOPPED)
+ continue;
+
+ if (selected == NULL
+ && thread->suspend.waitstatus_pending_p)
+ selected = thread;
+
+ if (lowest_stopped == NULL
+ || thread->inf->num < lowest_stopped->inf->num
+ || thread->per_inf_num < lowest_stopped->per_inf_num)
+ lowest_stopped = thread;
+
+ if (non_stop)
+ print_one_stopped_thread (thread);
+ }
+
+ /* In all-stop, we only print the status of one thread, and leave
+ others with their status pending. */
+ if (!non_stop)
+ {
+ thread = selected;
+ if (thread == NULL)
+ thread = lowest_stopped;
+ if (thread == NULL)
+ thread = first;
- print_stack_frame (get_selected_frame (NULL), 1, SRC_AND_LOC, 1);
- observer_notify_normal_stop (NULL, 1);
+ print_one_stopped_thread (thread);
}
+
+ /* For "info program". */
+ thread = inferior_thread ();
+ if (thread->state == THREAD_STOPPED)
+ set_last_target_status (inferior_ptid, thread->suspend.waitstatus);
}
+/* Start the remote connection and sync state. */
+
static void
remote_start_remote (int from_tty, struct target_ops *target, int extended_p)
{
struct packet_config *noack_config;
char *wait_status = NULL;
- immediate_quit++; /* Allow user to interrupt it. */
+ /* Signal other parts that we're going through the initial setup,
+ and so things may not be stable yet. E.g., we don't try to
+ install tracepoints until we've relocated symbols. Also, a
+ Ctrl-C before we're connected and synced up can't interrupt the
+ target. Instead, it offers to drop the (potentially wedged)
+ connection. */
+ rs->starting_up = 1;
+
QUIT;
if (interrupt_on_connect)
send_interrupt_sequence ();
/* Ack any packet which the remote side has already sent. */
- serial_write (rs->remote_desc, "+", 1);
-
- /* Signal other parts that we're going through the initial setup,
- and so things may not be stable yet. */
- rs->starting_up = 1;
+ remote_serial_write ("+", 1);
/* The first packet we send to the target is the optional "supported
packets" request. If the target can answer this, it will tell us
if (packet_support (PACKET_QAllow) != PACKET_DISABLE)
remote_set_permissions (target);
+ /* gdbserver < 7.7 (before its fix from 2013-12-11) did reply to any
+ unknown 'v' packet with string "OK". "OK" gets interpreted by GDB
+ as a reply to known packet. For packet "vFile:setfs:" it is an
+ invalid reply and GDB would return error in
+ remote_hostio_set_filesystem, making remote files access impossible.
+ Disable "vFile:setfs:" in such case. Do not disable other 'v' packets as
+ other "vFile" packets get correctly detected even on gdbserver < 7.7. */
+ {
+ const char v_mustreplyempty[] = "vMustReplyEmpty";
+
+ putpkt (v_mustreplyempty);
+ getpkt (&rs->buf, &rs->buf_size, 0);
+ if (strcmp (rs->buf, "OK") == 0)
+ remote_protocol_packets[PACKET_vFile_setfs].support = PACKET_DISABLE;
+ else if (strcmp (rs->buf, "") != 0)
+ error (_("Remote replied unexpectedly to '%s': %s"), v_mustreplyempty,
+ rs->buf);
+ }
+
/* Next, we possibly activate noack mode.
If the QStartNoAckMode packet configuration is set to AUTO,
if (gdbarch_has_global_solist (target_gdbarch ()))
solib_add (NULL, from_tty, target, auto_solib_add);
- if (non_stop)
+ if (target_is_non_stop_p ())
{
if (packet_support (PACKET_QNonStop) != PACKET_ENABLE)
error (_("Non-stop mode requested, but remote "
putpkt ("?");
getpkt (&rs->buf, &rs->buf_size, 0);
- if (!non_stop)
+ if (!target_is_non_stop_p ())
{
- ptid_t ptid;
- int fake_pid_p = 0;
- struct inferior *inf;
-
if (rs->buf[0] == 'W' || rs->buf[0] == 'X')
{
if (!extended_p)
strcpy (rs->buf, wait_status);
rs->cached_wait_status = 1;
- immediate_quit--;
start_remote (from_tty); /* Initialize gdb process mechanisms. */
}
else
{
- ptid_t current_ptid;
-
/* Clear WFI global state. Do this before finding about new
threads and inferiors, and setting the current inferior.
Otherwise we would clear the proceed status of the current
return;
}
- /* Let the stub know that we want it to return the thread. */
-
- /* Force the stub to choose a thread. */
- set_general_thread (null_ptid);
-
- /* Query it. */
- current_ptid = remote_current_thread (minus_one_ptid);
- if (ptid_equal (inferior_ptid, minus_one_ptid))
- error (_("remote didn't report the current thread in non-stop mode"));
-
- inferior_ptid = current_ptid;
- get_offsets (); /* Get text, data & bss offsets. */
-
/* In non-stop mode, any cached wait status will be stored in
the stop reply queue. */
gdb_assert (wait_status == NULL);
/* If there are already stopped threads, mark them stopped and
report their stops before giving the prompt to the user. */
- process_initial_stop_replies ();
-
- switch_to_thread (current_ptid);
+ process_initial_stop_replies (from_tty);
if (target_can_async_p ())
target_async (1);
{
struct remote_state *rs = get_remote_state ();
char *msg, *reply, *tmp;
- struct bound_minimal_symbol sym;
int end;
+ long reply_size;
struct cleanup *old_chain;
/* The remote side has no concept of inferiors that aren't running
because we need both at the same time. */
msg = (char *) xmalloc (get_remote_packet_size ());
old_chain = make_cleanup (xfree, msg);
+ reply = (char *) xmalloc (get_remote_packet_size ());
+ make_cleanup (free_current_contents, &reply);
+ reply_size = get_remote_packet_size ();
/* Invite target to request symbol lookups. */
putpkt ("qSymbol::");
- getpkt (&rs->buf, &rs->buf_size, 0);
- packet_ok (rs->buf, &remote_protocol_packets[PACKET_qSymbol]);
- reply = rs->buf;
+ getpkt (&reply, &reply_size, 0);
+ packet_ok (reply, &remote_protocol_packets[PACKET_qSymbol]);
while (startswith (reply, "qSymbol:"))
{
}
putpkt (msg);
- getpkt (&rs->buf, &rs->buf_size, 0);
- reply = rs->buf;
+ getpkt (&reply, &reply_size, 0);
}
do_cleanups (old_chain);
PACKET_qXfer_traceframe_info },
{ "QPassSignals", PACKET_DISABLE, remote_supported_packet,
PACKET_QPassSignals },
+ { "QCatchSyscalls", PACKET_DISABLE, remote_supported_packet,
+ PACKET_QCatchSyscalls },
{ "QProgramSignals", PACKET_DISABLE, remote_supported_packet,
PACKET_QProgramSignals },
{ "QStartNoAckMode", PACKET_DISABLE, remote_supported_packet,
PACKET_exec_event_feature },
{ "Qbtrace-conf:pt:size", PACKET_DISABLE, remote_supported_packet,
PACKET_Qbtrace_conf_pt_size },
- { "vContSupported", PACKET_DISABLE, remote_supported_packet, PACKET_vContSupported }
+ { "vContSupported", PACKET_DISABLE, remote_supported_packet, PACKET_vContSupported },
+ { "QThreadEvents", PACKET_DISABLE, remote_supported_packet, PACKET_QThreadEvents },
+ { "no-resumed", PACKET_DISABLE, remote_supported_packet, PACKET_no_resumed },
};
static char *remote_support_xml;
if (packet_set_cmd_state (PACKET_hwbreak_feature) != AUTO_BOOLEAN_FALSE)
q = remote_query_supported_append (q, "hwbreak+");
- if (remote_support_xml)
- q = remote_query_supported_append (q, remote_support_xml);
-
q = remote_query_supported_append (q, "qRelocInsn+");
- if (rs->extended)
- {
- if (packet_set_cmd_state (PACKET_fork_event_feature)
- != AUTO_BOOLEAN_FALSE)
- q = remote_query_supported_append (q, "fork-events+");
- if (packet_set_cmd_state (PACKET_vfork_event_feature)
- != AUTO_BOOLEAN_FALSE)
- q = remote_query_supported_append (q, "vfork-events+");
- if (packet_set_cmd_state (PACKET_exec_event_feature)
- != AUTO_BOOLEAN_FALSE)
- q = remote_query_supported_append (q, "exec-events+");
- }
+ if (packet_set_cmd_state (PACKET_fork_event_feature)
+ != AUTO_BOOLEAN_FALSE)
+ q = remote_query_supported_append (q, "fork-events+");
+ if (packet_set_cmd_state (PACKET_vfork_event_feature)
+ != AUTO_BOOLEAN_FALSE)
+ q = remote_query_supported_append (q, "vfork-events+");
+ if (packet_set_cmd_state (PACKET_exec_event_feature)
+ != AUTO_BOOLEAN_FALSE)
+ q = remote_query_supported_append (q, "exec-events+");
if (packet_set_cmd_state (PACKET_vContSupported) != AUTO_BOOLEAN_FALSE)
q = remote_query_supported_append (q, "vContSupported+");
+ if (packet_set_cmd_state (PACKET_QThreadEvents) != AUTO_BOOLEAN_FALSE)
+ q = remote_query_supported_append (q, "QThreadEvents+");
+
+ if (packet_set_cmd_state (PACKET_no_resumed) != AUTO_BOOLEAN_FALSE)
+ q = remote_query_supported_append (q, "no-resumed+");
+
+ /* Keep this one last to work around a gdbserver <= 7.10 bug in
+ the qSupported:xmlRegisters=i386 handling. */
+ if (remote_support_xml != NULL)
+ q = remote_query_supported_append (q, remote_support_xml);
+
q = reconcat (q, "qSupported:", q, (char *) NULL);
putpkt (q);
}
}
+/* Serial QUIT handler for the remote serial descriptor.
+
+ Defers handling a Ctrl-C until we're done with the current
+ command/response packet sequence, unless:
+
+ - We're setting up the connection. Don't send a remote interrupt
+ request, as we're not fully synced yet. Quit immediately
+ instead.
+
+ - The target has been resumed in the foreground
+ (target_terminal_is_ours is false) with a synchronous resume
+ packet, and we're blocked waiting for the stop reply, thus a
+ Ctrl-C should be immediately sent to the target.
+
+ - We get a second Ctrl-C while still within the same serial read or
+ write. In that case the serial is seemingly wedged --- offer to
+ quit/disconnect.
+
+ - We see a second Ctrl-C without target response, after having
+ previously interrupted the target. In that case the target/stub
+ is probably wedged --- offer to quit/disconnect.
+*/
+
+static void
+remote_serial_quit_handler (void)
+{
+ struct remote_state *rs = get_remote_state ();
+
+ if (check_quit_flag ())
+ {
+ /* If we're starting up, we're not fully synced yet. Quit
+ immediately. */
+ if (rs->starting_up)
+ quit ();
+ else if (rs->got_ctrlc_during_io)
+ {
+ if (query (_("The target is not responding to GDB commands.\n"
+ "Stop debugging it? ")))
+ remote_unpush_and_throw ();
+ }
+ /* If ^C has already been sent once, offer to disconnect. */
+ else if (!target_terminal_is_ours () && rs->ctrlc_pending_p)
+ interrupt_query ();
+ /* All-stop protocol, and blocked waiting for stop reply. Send
+ an interrupt request. */
+ else if (!target_terminal_is_ours () && rs->waiting_for_stop_reply)
+ target_interrupt (inferior_ptid);
+ else
+ rs->got_ctrlc_during_io = 1;
+ }
+}
+
/* Remove any of the remote.c targets from target stack. Upper targets depend
on it so remove them first. */
static void
remote_unpush_target (void)
{
- pop_all_targets_above (process_stratum - 1);
+ pop_all_targets_at_and_above (process_stratum);
+}
+
+static void
+remote_unpush_and_throw (void)
+{
+ remote_unpush_target ();
+ throw_error (TARGET_CLOSE_ERROR, _("Disconnected from target."));
}
static void
rs->extended = extended_p;
rs->waiting_for_stop_reply = 0;
rs->ctrlc_pending_p = 0;
+ rs->got_ctrlc_during_io = 0;
rs->general_thread = not_sent_ptid;
rs->continue_thread = not_sent_ptid;
rs->remote_traceframe_number = -1;
+ rs->last_resume_exec_dir = EXEC_FORWARD;
+
/* Probe for ability to use "ThreadInfo" query, as required. */
rs->use_threadinfo_query = 1;
rs->use_threadextra_query = 1;
readahead_cache_invalidate ();
+ /* Start out by owning the terminal. */
+ remote_async_terminal_ours_p = 1;
+
if (target_async_permitted)
{
- /* With this target we start out by owning the terminal. */
- remote_async_terminal_ours_p = 1;
-
/* FIXME: cagney/1999-09-23: During the initial connection it is
assumed that the target is already ready and able to respond to
requests. Unfortunately remote_start_remote() eventually calls
/* Tell the remote target to detach. */
remote_detach_pid (pid);
- if (from_tty && !rs->extended)
+ /* Exit only if this is the only active inferior. */
+ if (from_tty && !rs->extended && number_of_live_inferiors () == 1)
puts_filtered (_("Ending remote debugging.\n"));
/* Check to see if we are detaching a fork parent. Note that if we
if (args)
error (_("Argument given to \"disconnect\" when remotely debugging."));
- /* Make sure we unpush even the extended remote targets; mourn
- won't do it. So call remote_mourn directly instead of
- target_mourn_inferior. */
- remote_mourn (target);
+ /* Make sure we unpush even the extended remote targets. Calling
+ target_mourn_inferior won't unpush, and remote_mourn won't
+ unpush if there is more than one inferior left. */
+ unpush_target (target);
+ generic_mourn_inferior ();
if (from_tty)
puts_filtered ("Ending remote debugging.\n");
&remote_protocol_packets[PACKET_vAttach]))
{
case PACKET_OK:
- if (!non_stop)
+ if (!target_is_non_stop_p ())
{
/* Save the reply for later. */
wait_status = (char *) alloca (strlen (rs->buf) + 1);
inferior_ptid = pid_to_ptid (pid);
- if (non_stop)
+ if (target_is_non_stop_p ())
{
struct thread_info *thread;
this before anything involving memory or registers. */
target_find_description ();
- if (!non_stop)
+ if (!target_is_non_stop_p ())
{
/* Use the previously fetched status. */
gdb_assert (wait_status != NULL);
static void
extended_remote_post_attach (struct target_ops *ops, int pid)
{
+ /* Get text, data & bss offsets. */
+ get_offsets ();
+
/* In certain cases GDB might not have had the chance to start
symbol lookup up until now. This could happen if the debugged
binary is not using shared libraries, the vsyscall page is not
return p;
}
+/* Clear the thread's private info on resume. */
+
+static void
+resume_clear_thread_private_info (struct thread_info *thread)
+{
+ if (thread->priv != NULL)
+ {
+ thread->priv->stop_reason = TARGET_STOPPED_BY_NO_REASON;
+ thread->priv->watch_data_address = 0;
+ }
+}
+
/* Append a vCont continue-with-signal action for threads that have a
non-zero stop signal. */
p = append_resumption (p, endp, thread->ptid,
0, thread->suspend.stop_signal);
thread->suspend.stop_signal = GDB_SIGNAL_0;
+ resume_clear_thread_private_info (thread);
}
return p;
gdb_assert (strlen (rs->buf) < get_remote_packet_size ());
putpkt (rs->buf);
- if (non_stop)
+ if (target_is_non_stop_p ())
{
/* In non-stop, the stub replies to vCont with "OK". The stop
reply will be reported asynchronously by means of a `%Stop'
{
struct remote_state *rs = get_remote_state ();
char *buf;
+ struct thread_info *thread;
/* In all-stop, we can't mark REMOTE_ASYNC_GET_PENDING_EVENTS_TOKEN
(explained in remote-notif.c:handle_notification) so
it is safe to start a 'vNotif' sequence. It is good to do it
before resuming inferior, because inferior was stopped and no RSP
traffic at that moment. */
- if (!non_stop)
+ if (!target_is_non_stop_p ())
remote_notif_process (rs->notif_state, ¬if_client_stop);
rs->last_sent_signal = siggnal;
rs->last_sent_step = step;
+ rs->last_resume_exec_dir = execution_direction;
+
/* The vCont packet doesn't need to specify threads via Hc. */
/* No reverse support (yet) for vCont. */
if (execution_direction != EXEC_REVERSE)
else
set_continue_thread (ptid);
+ ALL_NON_EXITED_THREADS (thread)
+ resume_clear_thread_private_info (thread);
+
buf = rs->buf;
if (execution_direction == EXEC_REVERSE)
{
only to the base all-stop protocol, however. In non-stop (which
only supports vCont), the stub replies with an "OK", and is
immediate able to process further serial input. */
- if (!non_stop)
+ if (!target_is_non_stop_p ())
rs->waiting_for_stop_reply = 1;
}
\f
-/* Set up the signal handler for SIGINT, while the target is
- executing, ovewriting the 'regular' SIGINT signal handler. */
-static void
-async_initialize_sigint_signal_handler (void)
-{
- signal (SIGINT, async_handle_remote_sigint);
-}
-
-/* Signal handler for SIGINT, while the target is executing. */
-static void
-async_handle_remote_sigint (int sig)
-{
- signal (sig, async_handle_remote_sigint_twice);
- /* Note we need to go through gdb_call_async_signal_handler in order
- to wake up the event loop on Windows. */
- gdb_call_async_signal_handler (async_sigint_remote_token, 0);
-}
-
-/* Signal handler for SIGINT, installed after SIGINT has already been
- sent once. It will take effect the second time that the user sends
- a ^C. */
-static void
-async_handle_remote_sigint_twice (int sig)
-{
- signal (sig, async_handle_remote_sigint);
- /* See note in async_handle_remote_sigint. */
- gdb_call_async_signal_handler (async_sigint_remote_twice_token, 0);
-}
-
-/* Implementation of to_check_pending_interrupt. */
-
-static void
-remote_check_pending_interrupt (struct target_ops *self)
-{
- struct async_signal_handler *token = async_sigint_remote_twice_token;
-
- if (async_signal_handler_is_marked (token))
- {
- clear_async_signal_handler (token);
- call_async_signal_handler (token);
- }
-}
-
-/* Perform the real interruption of the target execution, in response
- to a ^C. */
-static void
-async_remote_interrupt (gdb_client_data arg)
-{
- if (remote_debug)
- fprintf_unfiltered (gdb_stdlog, "async_remote_interrupt called\n");
-
- target_stop (inferior_ptid);
-}
-
-/* Perform interrupt, if the first attempt did not succeed. Just give
- up on the target alltogether. */
-static void
-async_remote_interrupt_twice (gdb_client_data arg)
-{
- if (remote_debug)
- fprintf_unfiltered (gdb_stdlog, "async_remote_interrupt_twice called\n");
-
- interrupt_query ();
-}
-
-/* Reinstall the usual SIGINT handlers, after the target has
- stopped. */
-static void
-async_cleanup_sigint_signal_handler (void *dummy)
-{
- signal (SIGINT, handle_sigint);
-}
-
-/* Send ^C to target to halt it. Target will respond, and send us a
- packet. */
-static void (*ofunc) (int);
-
-/* The command line interface's interrupt routine. This function is installed
- as a signal handler for SIGINT. The first time a user requests an
- interrupt, we call remote_interrupt to send a break or ^C. If there is no
- response from the target (it didn't stop when the user requested it),
- we ask the user if he'd like to detach from the target. */
-
-static void
-sync_remote_interrupt (int signo)
-{
- /* If this doesn't work, try more severe steps. */
- signal (signo, sync_remote_interrupt_twice);
-
- gdb_call_async_signal_handler (async_sigint_remote_token, 1);
-}
-
-/* The user typed ^C twice. */
-
-static void
-sync_remote_interrupt_twice (int signo)
-{
- signal (signo, ofunc);
- gdb_call_async_signal_handler (async_sigint_remote_twice_token, 1);
- signal (signo, sync_remote_interrupt);
-}
-
/* Non-stop version of target_stop. Uses `vCont;t' to stop a remote
thread, all threads of a remote process, or all threads of all
processes. */
process reports the interrupt. */
static void
-remote_interrupt_as (ptid_t ptid)
+remote_interrupt_as (void)
{
struct remote_state *rs = get_remote_state ();
send_interrupt_sequence ();
}
+/* Non-stop version of target_interrupt. Uses `vCtrlC' to interrupt
+ the remote target. It is undefined which thread of which process
+ reports the interrupt. Throws an error if the packet is not
+ supported by the server. */
+
+static void
+remote_interrupt_ns (void)
+{
+ struct remote_state *rs = get_remote_state ();
+ char *p = rs->buf;
+ char *endp = rs->buf + get_remote_packet_size ();
+
+ xsnprintf (p, endp - p, "vCtrlC");
+
+ /* In non-stop, we get an immediate OK reply. The stop reply will
+ come in asynchronously by notification. */
+ putpkt (rs->buf);
+ getpkt (&rs->buf, &rs->buf_size, 0);
+
+ switch (packet_ok (rs->buf, &remote_protocol_packets[PACKET_vCtrlC]))
+ {
+ case PACKET_OK:
+ break;
+ case PACKET_UNKNOWN:
+ error (_("No support for interrupting the remote target."));
+ case PACKET_ERROR:
+ error (_("Interrupting target failed: %s"), rs->buf);
+ }
+}
+
/* Implement the to_stop function for the remote targets. */
static void
if (remote_debug)
fprintf_unfiltered (gdb_stdlog, "remote_stop called\n");
- if (non_stop)
+ if (target_is_non_stop_p ())
remote_stop_ns (ptid);
else
{
/* We don't currently have a way to transparently pause the
remote target in all-stop mode. Interrupt it instead. */
- remote_interrupt_as (ptid);
+ remote_interrupt_as ();
}
}
static void
remote_interrupt (struct target_ops *self, ptid_t ptid)
{
+ struct remote_state *rs = get_remote_state ();
+
if (remote_debug)
fprintf_unfiltered (gdb_stdlog, "remote_interrupt called\n");
- if (non_stop)
- {
- /* We don't currently have a way to ^C the remote target in
- non-stop mode. Stop it (with no signal) instead. */
- remote_stop_ns (ptid);
- }
+ if (target_is_non_stop_p ())
+ remote_interrupt_ns ();
+ else
+ remote_interrupt_as ();
+}
+
+/* Implement the to_pass_ctrlc function for the remote targets. */
+
+static void
+remote_pass_ctrlc (struct target_ops *self)
+{
+ struct remote_state *rs = get_remote_state ();
+
+ if (remote_debug)
+ fprintf_unfiltered (gdb_stdlog, "remote_pass_ctrlc called\n");
+
+ /* If we're starting up, we're not fully synced yet. Quit
+ immediately. */
+ if (rs->starting_up)
+ quit ();
+ /* If ^C has already been sent once, offer to disconnect. */
+ else if (rs->ctrlc_pending_p)
+ interrupt_query ();
else
- remote_interrupt_as (ptid);
+ target_interrupt (inferior_ptid);
}
/* Ask the user what to do when an interrupt is received. */
interrupt_query (void)
{
struct remote_state *rs = get_remote_state ();
- struct cleanup *old_chain;
-
- old_chain = make_cleanup_restore_target_terminal ();
- target_terminal_ours ();
if (rs->waiting_for_stop_reply && rs->ctrlc_pending_p)
{
"Give up waiting? ")))
quit ();
}
-
- do_cleanups (old_chain);
}
/* Enable/disable target terminal ownership. Most targets can use
static void
remote_terminal_inferior (struct target_ops *self)
{
- if (!target_async_permitted)
- /* Nothing to do. */
- return;
-
/* FIXME: cagney/1999-09-27: Make calls to target_terminal_*()
idempotent. The event-loop GDB talking to an asynchronous target
with a synchronous command calls this function from both
can go away. */
if (!remote_async_terminal_ours_p)
return;
- delete_file_handler (input_fd);
remote_async_terminal_ours_p = 0;
- async_initialize_sigint_signal_handler ();
/* NOTE: At this point we could also register our selves as the
recipient of all input. Any characters typed could then be
passed on down to the target. */
static void
remote_terminal_ours (struct target_ops *self)
{
- if (!target_async_permitted)
- /* Nothing to do. */
- return;
-
/* See FIXME in remote_terminal_inferior. */
if (remote_async_terminal_ours_p)
return;
- async_cleanup_sigint_signal_handler (NULL);
- add_file_handler (input_fd, stdin_event_handler, 0);
remote_async_terminal_ours_p = 1;
}
= (struct threads_listing_context *) param->input;
if (event->ws.kind == TARGET_WAITKIND_FORKED
- || event->ws.kind == TARGET_WAITKIND_VFORKED)
- {
- threads_listing_context_remove (&event->ws, context);
- }
+ || event->ws.kind == TARGET_WAITKIND_VFORKED
+ || event->ws.kind == TARGET_WAITKIND_THREAD_EXITED)
+ threads_listing_context_remove (&event->ws, context);
return 1;
}
fork child threads from the CONTEXT list. */
ALL_NON_EXITED_THREADS (thread)
{
- struct target_waitstatus *ws = &thread->pending_follow;
+ struct target_waitstatus *ws;
+
+ if (thread->suspend.waitstatus_pending_p)
+ ws = &thread->suspend.waitstatus;
+ else
+ ws = &thread->pending_follow;
if (is_pending_fork_parent (ws, pid, thread->ptid))
{
static void
discard_pending_stop_replies (struct inferior *inf)
{
- int i;
struct queue_iter_param param;
struct stop_reply *reply;
struct remote_state *rs = get_remote_state ();
stop_reply_match_ptid_and_ws, &ptid);
}
-/* Skip PACKET until the next semi-colon (or end of string). */
-
-static char *
-skip_to_semicolon (char *p)
-{
- while (*p != '\0' && *p != ';')
- p++;
- return p;
-}
-
/* Helper for remote_parse_stop_reply. Return nonzero if the substring
starting with P and ending with PEND matches PREFIX. */
if (strprefix (p, p1, "thread"))
event->ptid = read_ptid (++p1, &p);
+ else if (strprefix (p, p1, "syscall_entry"))
+ {
+ ULONGEST sysno;
+
+ event->ws.kind = TARGET_WAITKIND_SYSCALL_ENTRY;
+ p = unpack_varlen_hex (++p1, &sysno);
+ event->ws.value.syscall_number = (int) sysno;
+ }
+ else if (strprefix (p, p1, "syscall_return"))
+ {
+ ULONGEST sysno;
+
+ event->ws.kind = TARGET_WAITKIND_SYSCALL_RETURN;
+ p = unpack_varlen_hex (++p1, &sysno);
+ event->ws.value.syscall_number = (int) sysno;
+ }
else if (strprefix (p, p1, "watch")
|| strprefix (p, p1, "rwatch")
|| strprefix (p, p1, "awatch"))
/* The value part is documented as "must be empty",
though we ignore it, in case we ever decide to make
use of it in a backward compatible way. */
- p = skip_to_semicolon (p1 + 1);
+ p = strchrnul (p1 + 1, ';');
}
else if (strprefix (p, p1, "hwbreak"))
{
error (_("Unexpected hwbreak stop reason"));
/* See above. */
- p = skip_to_semicolon (p1 + 1);
+ p = strchrnul (p1 + 1, ';');
}
else if (strprefix (p, p1, "library"))
{
event->ws.kind = TARGET_WAITKIND_LOADED;
- p = skip_to_semicolon (p1 + 1);
+ p = strchrnul (p1 + 1, ';');
}
else if (strprefix (p, p1, "replaylog"))
{
event->ws.kind = TARGET_WAITKIND_NO_HISTORY;
/* p1 will indicate "begin" or "end", but it makes
no difference for now, so ignore it. */
- p = skip_to_semicolon (p1 + 1);
+ p = strchrnul (p1 + 1, ';');
}
else if (strprefix (p, p1, "core"))
{
else if (strprefix (p, p1, "vforkdone"))
{
event->ws.kind = TARGET_WAITKIND_VFORK_DONE;
- p = skip_to_semicolon (p1 + 1);
+ p = strchrnul (p1 + 1, ';');
}
else if (strprefix (p, p1, "exec"))
{
one used by the original program. */
skipregs = 1;
}
+ else if (strprefix (p, p1, "create"))
+ {
+ event->ws.kind = TARGET_WAITKIND_THREAD_CREATED;
+ p = strchrnul (p1 + 1, ';');
+ }
else
{
ULONGEST pnum;
if (skipregs)
{
- p = skip_to_semicolon (p1 + 1);
+ p = strchrnul (p1 + 1, ';');
p++;
continue;
}
{
/* Not a number. Silently skip unknown optional
info. */
- p = skip_to_semicolon (p1 + 1);
+ p = strchrnul (p1 + 1, ';');
}
}
event->ws.value.sig = GDB_SIGNAL_UNKNOWN;
}
break;
+ case 'w': /* Thread exited. */
+ {
+ char *p;
+ ULONGEST value;
+
+ event->ws.kind = TARGET_WAITKIND_THREAD_EXITED;
+ p = unpack_varlen_hex (&buf[1], &value);
+ event->ws.value.integer = value;
+ if (*p != ';')
+ error (_("stop reply packet badly formatted: %s"), buf);
+ event->ptid = read_ptid (++p, NULL);
+ break;
+ }
case 'W': /* Target exited. */
case 'X':
{
event->ptid = pid_to_ptid (pid);
}
break;
+ case 'N':
+ event->ws.kind = TARGET_WAITKIND_NO_RESUMED;
+ event->ptid = minus_one_ptid;
+ break;
}
- if (non_stop && ptid_equal (event->ptid, null_ptid))
+ if (target_is_non_stop_p () && ptid_equal (event->ptid, null_ptid))
error (_("No process or thread specified in stop reply: %s"), buf);
}
ptid = inferior_ptid;
if (status->kind != TARGET_WAITKIND_EXITED
- && status->kind != TARGET_WAITKIND_SIGNALLED)
+ && status->kind != TARGET_WAITKIND_SIGNALLED
+ && status->kind != TARGET_WAITKIND_NO_RESUMED)
{
- struct remote_state *rs = get_remote_state ();
+ struct private_thread_info *remote_thr;
/* Expedited registers. */
if (stop_reply->regcache)
VEC_free (cached_reg_t, stop_reply->regcache);
}
- rs->stop_reason = stop_reply->stop_reason;
- rs->remote_watch_data_address = stop_reply->watch_data_address;
-
remote_notice_new_inferior (ptid, 0);
- demand_private_info (ptid)->core = stop_reply->core;
+ remote_thr = demand_private_info (ptid);
+ remote_thr->core = stop_reply->core;
+ remote_thr->stop_reason = stop_reply->stop_reason;
+ remote_thr->watch_data_address = stop_reply->watch_data_address;
}
stop_reply_xfree (stop_reply);
return minus_one_ptid;
}
- if (!target_is_async_p ())
- {
- ofunc = signal (SIGINT, sync_remote_interrupt);
- /* If the user hit C-c before this packet, or between packets,
- pretend that it was hit right here. */
- if (check_quit_flag ())
- {
- clear_quit_flag ();
- sync_remote_interrupt (SIGINT);
- }
- }
-
/* FIXME: cagney/1999-09-27: If we're in async mode we should
_never_ wait for ever -> test on target_is_async_p().
However, before we do that we need to ensure that the caller
ret = getpkt_or_notif_sane (&rs->buf, &rs->buf_size,
forever, &is_notif);
- if (!target_is_async_p ())
- signal (SIGINT, ofunc);
-
/* GDB gets a notification. Return to core as this event is
not interesting. */
if (ret != -1 && is_notif)
buf = rs->buf;
- rs->stop_reason = TARGET_STOPPED_BY_NO_REASON;
-
/* Assume that the target has acknowledged Ctrl-C unless we receive
an 'F' or 'O' packet. */
if (buf[0] != 'F' && buf[0] != 'O')
status->value.sig = GDB_SIGNAL_0;
break;
case 'F': /* File-I/O request. */
+ /* GDB may access the inferior memory while handling the File-I/O
+ request, but we don't want GDB accessing memory while waiting
+ for a stop reply. See the comments in putpkt_binary. Set
+ waiting_for_stop_reply to 0 temporarily. */
+ rs->waiting_for_stop_reply = 0;
remote_fileio_request (buf, rs->ctrlc_pending_p);
rs->ctrlc_pending_p = 0;
+ /* GDB handled the File-I/O request, and the target is running
+ again. Keep waiting for events. */
+ rs->waiting_for_stop_reply = 1;
break;
- case 'T': case 'S': case 'X': case 'W':
+ case 'N': case 'T': case 'S': case 'X': case 'W':
{
struct stop_reply *stop_reply;
break;
}
- if (status->kind == TARGET_WAITKIND_IGNORE)
+ if (status->kind == TARGET_WAITKIND_NO_RESUMED)
+ return minus_one_ptid;
+ else if (status->kind == TARGET_WAITKIND_IGNORE)
{
/* Nothing interesting happened. If we're doing a non-blocking
poll, we're done. Otherwise, go back to waiting. */
{
ptid_t event_ptid;
- if (non_stop)
+ if (target_is_non_stop_p ())
event_ptid = remote_wait_ns (ptid, status, options);
else
event_ptid = remote_wait_as (ptid, status, options);
safe_strerror (saved_errno));
}
-/* Read a single character from the remote end. */
+/* Read a single character from the remote end. The current quit
+ handler is overridden to avoid quitting in the middle of packet
+ sequence, as that would break communication with the remote server.
+ See remote_serial_quit_handler for more detail. */
static int
readchar (int timeout)
{
int ch;
struct remote_state *rs = get_remote_state ();
+ struct cleanup *old_chain;
+
+ old_chain = make_cleanup_override_quit_handler (remote_serial_quit_handler);
+
+ rs->got_ctrlc_during_io = 0;
ch = serial_readchar (rs->remote_desc, timeout);
+ if (rs->got_ctrlc_during_io)
+ set_quit_flag ();
+
+ do_cleanups (old_chain);
+
if (ch >= 0)
return ch;
}
/* Wrapper for serial_write that closes the target and throws if
- writing fails. */
+ writing fails. The current quit handler is overridden to avoid
+ quitting in the middle of packet sequence, as that would break
+ communication with the remote server. See
+ remote_serial_quit_handler for more detail. */
static void
remote_serial_write (const char *str, int len)
{
struct remote_state *rs = get_remote_state ();
+ struct cleanup *old_chain;
+
+ old_chain = make_cleanup_override_quit_handler (remote_serial_quit_handler);
+
+ rs->got_ctrlc_during_io = 0;
if (serial_write (rs->remote_desc, str, len))
{
unpush_and_perror (_("Remote communication error. "
"Target disconnected."));
}
+
+ if (rs->got_ctrlc_during_io)
+ set_quit_flag ();
+
+ do_cleanups (old_chain);
}
/* Send the command in *BUF to the remote machine, and read the reply
int ch;
int tcount = 0;
char *p;
- char *message;
/* Catch cases like trying to read memory or listing threads while
we're waiting for a stop reply. The remote server wouldn't be
case it's not possible to issue a command while the target is
running. This is not a problem in non-stop mode, because in that
case, the stub is always ready to process serial input. */
- if (!non_stop && target_is_async_p () && rs->waiting_for_stop_reply)
+ if (!target_is_non_stop_p ()
+ && target_is_async_p ()
+ && rs->waiting_for_stop_reply)
{
error (_("Cannot execute this command while the target is running.\n"
"Use the \"interrupt\" command to stop the target\n"
long *sizeof_buf,
int forever)
{
- int timed_out;
-
- timed_out = getpkt_sane (buf, sizeof_buf, forever);
+ getpkt_sane (buf, sizeof_buf, forever);
}
if (forever) /* Watchdog went off? Kill the target. */
{
- QUIT;
remote_unpush_target ();
throw_error (TARGET_CLOSE_ERROR,
_("Watchdog timeout has expired. "
}
\f
+/* Target hook to kill the current inferior. */
+
static void
remote_kill (struct target_ops *ops)
{
+ int res = -1;
+ int pid = ptid_get_pid (inferior_ptid);
+ struct remote_state *rs = get_remote_state ();
- /* Catch errors so the user can quit from gdb even when we
- aren't on speaking terms with the remote system. */
- TRY
+ if (packet_support (PACKET_vKill) != PACKET_DISABLE)
{
- putpkt ("k");
- }
- CATCH (ex, RETURN_MASK_ERROR)
- {
- if (ex.error == TARGET_CLOSE_ERROR)
+ /* If we're stopped while forking and we haven't followed yet,
+ kill the child task. We need to do this before killing the
+ parent task because if this is a vfork then the parent will
+ be sleeping. */
+ kill_new_fork_children (pid, rs);
+
+ res = remote_vkill (pid, rs);
+ if (res == 0)
{
- /* If we got an (EOF) error that caused the target
- to go away, then we're done, that's what we wanted.
- "k" is susceptible to cause a premature EOF, given
- that the remote server isn't actually required to
- reply to "k", and it can happen that it doesn't
- even get to reply ACK to the "k". */
+ target_mourn_inferior ();
return;
}
+ }
- /* Otherwise, something went wrong. We didn't actually kill
- the target. Just propagate the exception, and let the
- user or higher layers decide what to do. */
- throw_exception (ex);
+ /* If we are in 'target remote' mode and we are killing the only
+ inferior, then we will tell gdbserver to exit and unpush the
+ target. */
+ if (res == -1 && !remote_multi_process_p (rs)
+ && number_of_live_inferiors () == 1)
+ {
+ remote_kill_k ();
+
+ /* We've killed the remote end, we get to mourn it. If we are
+ not in extended mode, mourning the inferior also unpushes
+ remote_ops from the target stack, which closes the remote
+ connection. */
+ target_mourn_inferior ();
+
+ return;
}
- END_CATCH
- /* We've killed the remote end, we get to mourn it. Since this is
- target remote, single-process, mourning the inferior also
- unpushes remote_ops. */
- target_mourn_inferior ();
+ error (_("Can't kill process"));
}
+/* Send a kill request to the target using the 'vKill' packet. */
+
static int
remote_vkill (int pid, struct remote_state *rs)
{
}
}
+/* Send a kill request to the target using the 'k' packet. */
+
static void
-extended_remote_kill (struct target_ops *ops)
+remote_kill_k (void)
{
- int res;
- int pid = ptid_get_pid (inferior_ptid);
- struct remote_state *rs = get_remote_state ();
-
- /* If we're stopped while forking and we haven't followed yet, kill the
- child task. We need to do this before killing the parent task
- because if this is a vfork then the parent will be sleeping. */
- kill_new_fork_children (pid, rs);
-
- res = remote_vkill (pid, rs);
- if (res == -1 && !(rs->extended && remote_multi_process_p (rs)))
+ /* Catch errors so the user can quit from gdb even when we
+ aren't on speaking terms with the remote system. */
+ TRY
{
- /* Don't try 'k' on a multi-process aware stub -- it has no way
- to specify the pid. */
-
putpkt ("k");
-#if 0
- getpkt (&rs->buf, &rs->buf_size, 0);
- if (rs->buf[0] != 'O' || rs->buf[0] != 'K')
- res = 1;
-#else
- /* Don't wait for it to die. I'm not really sure it matters whether
- we do or not. For the existing stubs, kill is a noop. */
- res = 0;
-#endif
}
+ CATCH (ex, RETURN_MASK_ERROR)
+ {
+ if (ex.error == TARGET_CLOSE_ERROR)
+ {
+ /* If we got an (EOF) error that caused the target
+ to go away, then we're done, that's what we wanted.
+ "k" is susceptible to cause a premature EOF, given
+ that the remote server isn't actually required to
+ reply to "k", and it can happen that it doesn't
+ even get to reply ACK to the "k". */
+ return;
+ }
- if (res != 0)
- error (_("Can't kill process"));
-
- target_mourn_inferior ();
+ /* Otherwise, something went wrong. We didn't actually kill
+ the target. Just propagate the exception, and let the
+ user or higher layers decide what to do. */
+ throw_exception (ex);
+ }
+ END_CATCH
}
static void
remote_mourn (struct target_ops *target)
{
- unpush_target (target);
+ struct remote_state *rs = get_remote_state ();
- /* remote_close takes care of doing most of the clean up. */
- generic_mourn_inferior ();
-}
+ /* In 'target remote' mode with one inferior, we close the connection. */
+ if (!rs->extended && number_of_live_inferiors () <= 1)
+ {
+ unpush_target (target);
-static void
-extended_remote_mourn (struct target_ops *target)
-{
- struct remote_state *rs = get_remote_state ();
+ /* remote_close takes care of doing most of the clean up. */
+ generic_mourn_inferior ();
+ return;
+ }
/* In case we got here due to an error, but we're going to stay
connected. */
current thread. */
record_currthread (rs, minus_one_ptid);
- /* Unlike "target remote", we do not want to unpush the target; then
- the next time the user says "run", we won't be connected. */
-
- /* Call common code to mark the inferior as not running. */
+ /* Call common code to mark the inferior as not running. */
generic_mourn_inferior ();
if (!have_inferiors ())
{
struct agent_expr *aexpr = NULL;
int i, ix;
- char *pkt;
- char *buf_start = buf;
if (VEC_empty (agent_expr_p, bp_tgt->conditions))
return 0;
struct remote_state *rs;
char *p, *endbuf;
int bpsize;
- struct condition_list *cond = NULL;
/* Make sure the remote is pointing at the right process, if
necessary. */
static int
remote_stopped_by_sw_breakpoint (struct target_ops *ops)
{
- struct remote_state *rs = get_remote_state ();
+ struct thread_info *thread = inferior_thread ();
- return rs->stop_reason == TARGET_STOPPED_BY_SW_BREAKPOINT;
+ return (thread->priv != NULL
+ && thread->priv->stop_reason == TARGET_STOPPED_BY_SW_BREAKPOINT);
}
/* The to_supports_stopped_by_sw_breakpoint method of target
static int
remote_supports_stopped_by_sw_breakpoint (struct target_ops *ops)
{
- struct remote_state *rs = get_remote_state ();
-
return (packet_support (PACKET_swbreak_feature) == PACKET_ENABLE);
}
static int
remote_stopped_by_hw_breakpoint (struct target_ops *ops)
{
- struct remote_state *rs = get_remote_state ();
+ struct thread_info *thread = inferior_thread ();
- return rs->stop_reason == TARGET_STOPPED_BY_HW_BREAKPOINT;
+ return (thread->priv != NULL
+ && thread->priv->stop_reason == TARGET_STOPPED_BY_HW_BREAKPOINT);
}
/* The to_supports_stopped_by_hw_breakpoint method of target
static int
remote_supports_stopped_by_hw_breakpoint (struct target_ops *ops)
{
- struct remote_state *rs = get_remote_state ();
-
return (packet_support (PACKET_hwbreak_feature) == PACKET_ENABLE);
}
static int
remote_stopped_by_watchpoint (struct target_ops *ops)
{
- struct remote_state *rs = get_remote_state ();
+ struct thread_info *thread = inferior_thread ();
- return rs->stop_reason == TARGET_STOPPED_BY_WATCHPOINT;
+ return (thread->priv != NULL
+ && thread->priv->stop_reason == TARGET_STOPPED_BY_WATCHPOINT);
}
static int
remote_stopped_data_address (struct target_ops *target, CORE_ADDR *addr_p)
{
- struct remote_state *rs = get_remote_state ();
- int rc = 0;
+ struct thread_info *thread = inferior_thread ();
- if (remote_stopped_by_watchpoint (target))
+ if (thread->priv != NULL
+ && thread->priv->stop_reason == TARGET_STOPPED_BY_WATCHPOINT)
{
- *addr_p = rs->remote_watch_data_address;
- rc = 1;
+ *addr_p = thread->priv->watch_data_address;
+ return 1;
}
- return rc;
+ return 0;
}
/* Only handle flash writes. */
if (writebuf != NULL)
{
- LONGEST xfered;
-
switch (object)
{
case TARGET_OBJECT_FLASH:
{
if (ptid_equal (magic_null_ptid, ptid))
xsnprintf (buf, sizeof buf, "Thread <main>");
- else if (rs->extended && remote_multi_process_p (rs))
+ else if (remote_multi_process_p (rs))
if (ptid_get_lwp (ptid) == 0)
return normal_pid_to_str (ptid);
else
{
struct remote_state *rs = get_remote_state ();
- /* Only extended-remote handles being attached to multiple
- processes, even though plain remote can use the multi-process
- thread id extensions, so that GDB knows the target process's
- PID. */
- return rs->extended && remote_multi_process_p (rs);
+ return remote_multi_process_p (rs);
}
static int
enum btrace_read_type type)
{
struct packet_config *packet = &remote_protocol_packets[PACKET_qXfer_btrace];
- struct remote_state *rs = get_remote_state ();
struct cleanup *cleanup;
const char *annex;
char *xml;
return 0;
}
+/* Implementation of the to_execution_direction method for the remote
+ target. */
+
+static enum exec_direction_kind
+remote_execution_direction (struct target_ops *self)
+{
+ struct remote_state *rs = get_remote_state ();
+
+ return rs->last_resume_exec_dir;
+}
+
static void
init_remote_ops (void)
{
remote_ops.to_load = remote_load;
remote_ops.to_mourn_inferior = remote_mourn;
remote_ops.to_pass_signals = remote_pass_signals;
+ remote_ops.to_set_syscall_catchpoint = remote_set_syscall_catchpoint;
remote_ops.to_program_signals = remote_program_signals;
remote_ops.to_thread_alive = remote_thread_alive;
+ remote_ops.to_thread_name = remote_thread_name;
remote_ops.to_update_thread_list = remote_update_thread_list;
remote_ops.to_pid_to_str = remote_pid_to_str;
remote_ops.to_extra_thread_info = remote_threads_extra_info;
remote_ops.to_get_ada_task_ptid = remote_get_ada_task_ptid;
remote_ops.to_stop = remote_stop;
remote_ops.to_interrupt = remote_interrupt;
- remote_ops.to_check_pending_interrupt = remote_check_pending_interrupt;
+ remote_ops.to_pass_ctrlc = remote_pass_ctrlc;
remote_ops.to_xfer_partial = remote_xfer_partial;
remote_ops.to_rcmd = remote_rcmd;
remote_ops.to_pid_to_exec_file = remote_pid_to_exec_file;
remote_ops.to_can_async_p = remote_can_async_p;
remote_ops.to_is_async_p = remote_is_async_p;
remote_ops.to_async = remote_async;
+ remote_ops.to_thread_events = remote_thread_events;
remote_ops.to_can_do_single_step = remote_can_do_single_step;
remote_ops.to_terminal_inferior = remote_terminal_inferior;
remote_ops.to_terminal_ours = remote_terminal_ours;
remote_ops.to_btrace_conf = remote_btrace_conf;
remote_ops.to_augmented_libraries_svr4_read =
remote_augmented_libraries_svr4_read;
+ remote_ops.to_follow_fork = remote_follow_fork;
+ remote_ops.to_follow_exec = remote_follow_exec;
+ remote_ops.to_insert_fork_catchpoint = remote_insert_fork_catchpoint;
+ remote_ops.to_remove_fork_catchpoint = remote_remove_fork_catchpoint;
+ remote_ops.to_insert_vfork_catchpoint = remote_insert_vfork_catchpoint;
+ remote_ops.to_remove_vfork_catchpoint = remote_remove_vfork_catchpoint;
+ remote_ops.to_insert_exec_catchpoint = remote_insert_exec_catchpoint;
+ remote_ops.to_remove_exec_catchpoint = remote_remove_exec_catchpoint;
+ remote_ops.to_execution_direction = remote_execution_direction;
}
/* Set up the extended remote vector by making a copy of the standard
Specify the serial device it is connected to (e.g. /dev/ttya).";
extended_remote_ops.to_open = extended_remote_open;
extended_remote_ops.to_create_inferior = extended_remote_create_inferior;
- extended_remote_ops.to_mourn_inferior = extended_remote_mourn;
extended_remote_ops.to_detach = extended_remote_detach;
extended_remote_ops.to_attach = extended_remote_attach;
extended_remote_ops.to_post_attach = extended_remote_post_attach;
- extended_remote_ops.to_kill = extended_remote_kill;
extended_remote_ops.to_supports_disable_randomization
= extended_remote_supports_disable_randomization;
- extended_remote_ops.to_follow_fork = remote_follow_fork;
- extended_remote_ops.to_follow_exec = remote_follow_exec;
- extended_remote_ops.to_insert_fork_catchpoint
- = remote_insert_fork_catchpoint;
- extended_remote_ops.to_remove_fork_catchpoint
- = remote_remove_fork_catchpoint;
- extended_remote_ops.to_insert_vfork_catchpoint
- = remote_insert_vfork_catchpoint;
- extended_remote_ops.to_remove_vfork_catchpoint
- = remote_remove_vfork_catchpoint;
- extended_remote_ops.to_insert_exec_catchpoint
- = remote_insert_exec_catchpoint;
- extended_remote_ops.to_remove_exec_catchpoint
- = remote_remove_exec_catchpoint;
}
static int
static void
remote_async_serial_handler (struct serial *scb, void *context)
{
- struct remote_state *rs = (struct remote_state *) context;
-
/* Don't propogate error information up to the client. Instead let
the client find out about the error by querying the target. */
inferior_event_handler (INF_REG_EVENT, NULL);
event loop to process them. */
if (!QUEUE_is_empty (stop_reply_p, stop_reply_queue))
mark_async_event_handler (remote_async_inferior_event_token);
+ /* For simplicity, below we clear the pending events token
+ without remembering whether it is marked, so here we always
+ mark it. If there's actually no pending notification to
+ process, this ends up being a no-op (other than a spurious
+ event-loop wakeup). */
+ if (target_is_non_stop_p ())
+ mark_async_event_handler (rs->notif_state->get_pending_events_token);
}
else
{
serial_async (rs->remote_desc, NULL, NULL);
+ /* If the core is disabling async, it doesn't want to be
+ disturbed with target events. Clear all async event sources
+ too. */
clear_async_event_handler (remote_async_inferior_event_token);
+ if (target_is_non_stop_p ())
+ clear_async_event_handler (rs->notif_state->get_pending_events_token);
+ }
+}
+
+/* Implementation of the to_thread_events method. */
+
+static void
+remote_thread_events (struct target_ops *ops, int enable)
+{
+ struct remote_state *rs = get_remote_state ();
+ size_t size = get_remote_packet_size ();
+
+ if (packet_support (PACKET_QThreadEvents) == PACKET_DISABLE)
+ return;
+
+ xsnprintf (rs->buf, size, "QThreadEvents:%x", enable ? 1 : 0);
+ putpkt (rs->buf);
+ getpkt (&rs->buf, &rs->buf_size, 0);
+
+ switch (packet_ok (rs->buf,
+ &remote_protocol_packets[PACKET_QThreadEvents]))
+ {
+ case PACKET_OK:
+ if (strcmp (rs->buf, "OK") != 0)
+ error (_("Remote refused setting thread events: %s"), rs->buf);
+ break;
+ case PACKET_ERROR:
+ warning (_("Remote failure reply: %s"), rs->buf);
+ break;
+ case PACKET_UNKNOWN:
+ break;
}
}
void
_initialize_remote (void)
{
- struct remote_state *rs;
struct cmd_list_element *cmd;
const char *cmd_name;
when it exits. */
observer_attach_inferior_exit (discard_pending_stop_replies);
- /* Set up signal handlers. */
- async_sigint_remote_token =
- create_async_signal_handler (async_remote_interrupt, NULL);
- async_sigint_remote_twice_token =
- create_async_signal_handler (async_remote_interrupt_twice, NULL);
-
#if 0
init_remote_threadtests ();
#endif
add_packet_config_cmd (&remote_protocol_packets[PACKET_QPassSignals],
"QPassSignals", "pass-signals", 0);
+ add_packet_config_cmd (&remote_protocol_packets[PACKET_QCatchSyscalls],
+ "QCatchSyscalls", "catch-syscalls", 0);
+
add_packet_config_cmd (&remote_protocol_packets[PACKET_QProgramSignals],
"QProgramSignals", "program-signals", 0);
add_packet_config_cmd (&remote_protocol_packets[PACKET_exec_event_feature],
"exec-event-feature", "exec-event-feature", 0);
+ add_packet_config_cmd (&remote_protocol_packets[PACKET_vCtrlC],
+ "vCtrlC", "ctrl-c", 0);
+
+ add_packet_config_cmd (&remote_protocol_packets[PACKET_QThreadEvents],
+ "QThreadEvents", "thread-events", 0);
+
+ add_packet_config_cmd (&remote_protocol_packets[PACKET_no_resumed],
+ "N stop reply", "no-resumed-stop-reply", 0);
+
/* Assert that we've registered "set remote foo-packet" commands
for all packet configs. */
{