/* Remote target communications for serial-line targets in custom GDB protocol
- Copyright (C) 1988-2012 Free Software Foundation, Inc.
+ Copyright (C) 1988-2013 Free Software Foundation, Inc.
This file is part of GDB.
#include "gdb-stabs.h"
#include "gdbthread.h"
#include "remote.h"
+#include "remote-notif.h"
#include "regcache.h"
#include "value.h"
#include "gdb_assert.h"
#include "cli/cli-setshow.h"
#include "target-descriptions.h"
#include "gdb_bfd.h"
+#include "filestuff.h"
#include <ctype.h>
#include <sys/time.h>
#include "ax.h"
#include "ax-gdb.h"
#include "agent.h"
+#include "btrace.h"
/* Temp hacks for tracepoint encoding migration. */
static char *target_buf;
enum { REMOTE_ALIGN_WRITES = 16 };
/* Prototypes for local functions. */
-static void cleanup_sigint_signal_handler (void *dummy);
-static void initialize_sigint_signal_handler (void);
+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 handle_remote_sigint (int);
-static void handle_remote_sigint_twice (int);
-static void async_remote_interrupt (gdb_client_data);
-void async_remote_interrupt_twice (gdb_client_data);
+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_open_1 (char *, int, struct target_ops *, int extended_p);
-static void remote_close (int quitting);
+static void remote_close (void);
static void remote_mourn (struct target_ops *ops);
static int readchar (int timeout);
+static void remote_serial_write (const char *str, int len);
+
static void remote_kill (struct target_ops *ops);
static int tohex (int nib);
static void remote_detach (struct target_ops *ops, char *args, int from_tty);
-static void remote_interrupt (int signo);
-
-static void remote_interrupt_twice (int signo);
+static void sync_remote_interrupt_twice (int signo);
static void interrupt_query (void);
static int fromhex (int a);
-extern int hex2bin (const char *hex, gdb_byte *bin, int count);
-
-extern int bin2hex (const gdb_byte *bin, char *hex, int count);
-
static int putpkt_binary (char *buf, int cnt);
static void check_binary_download (CORE_ADDR addr);
static void remote_query_supported (void);
-static void remote_check_symbols (struct objfile *objfile);
+static void remote_check_symbols (void);
void _initialize_remote (void);
struct stop_reply;
-static struct stop_reply *stop_reply_xmalloc (void);
static void stop_reply_xfree (struct stop_reply *);
-static void do_stop_reply_xfree (void *arg);
-static void remote_parse_stop_reply (char *buf, struct stop_reply *);
+static void remote_parse_stop_reply (char *, struct stop_reply *);
static void push_stop_reply (struct stop_reply *);
-static void remote_get_pending_stop_replies (void);
static void discard_pending_stop_replies (struct inferior *);
static int peek_stop_reply (ptid_t ptid);
static void remote_async_inferior_event_handler (gdb_client_data);
-static void remote_async_get_pending_events_handler (gdb_client_data);
static void remote_terminal_ours (void);
static int remote_can_run_breakpoint_commands (void);
-/* The non-stop remote protocol provisions for one pending stop reply.
- This is where we keep it until it is acknowledged. */
-
-static struct stop_reply *pending_stop_reply = NULL;
-
/* For "remote". */
static struct cmd_list_element *remote_cmdlist;
static struct cmd_list_element *remote_set_cmdlist;
static struct cmd_list_element *remote_show_cmdlist;
+/* Stub vCont actions support.
+
+ Each field is a boolean flag indicating whether the stub reports
+ support for the corresponding action. */
+
+struct vCont_action_support
+{
+ /* vCont;t */
+ int t;
+
+ /* vCont;r */
+ int r;
+};
+
+/* Controls whether GDB is willing to use range stepping. */
+
+static int use_range_stepping = 1;
+
/* Description of the remote protocol state for the currently
connected target. This is per-target state, and independent of the
selected architecture. */
/* True if the stub reports support for non-stop mode. */
int non_stop_aware;
- /* True if the stub reports support for vCont;t. */
- int support_vCont_t;
+ /* The status of the stub support for the various vCont actions. */
+ struct vCont_action_support supports_vCont;
/* True if the stub reports support for conditional tracepoints. */
int cond_tracepoints;
/* True if the stub can collect strings using tracenz bytecode. */
int string_tracing;
+ /* True if the stub supports qXfer:libraries-svr4:read with a
+ non-empty annex. */
+ int augmented_libraries_svr4_read;
+
/* Nonzero if the user has pressed Ctrl-C, but the target hasn't
responded to that. */
int ctrlc_pending_p;
else
error (_("remote.c: error in outgoing packet at field #%ld."),
strtol (buf, NULL, 16));
- case '2':
- error (_("trace API error 0x%s."), ++buf);
default:
error (_("Target returns error code '%s'."), buf);
}
PACKET_qGetTIBAddr,
PACKET_qGetTLSAddr,
PACKET_qSupported,
+ PACKET_qTStatus,
PACKET_QPassSignals,
PACKET_QProgramSignals,
PACKET_qSearch_memory,
PACKET_qXfer_fdpic,
PACKET_QDisableRandomization,
PACKET_QAgent,
+ PACKET_QTBuffer_size,
+ PACKET_Qbtrace_off,
+ PACKET_Qbtrace_bts,
+ PACKET_qXfer_btrace,
PACKET_MAX
};
static int use_threadextra_query;
/* Tokens for use by the asynchronous signal handlers for SIGINT. */
-static struct async_signal_handler *sigint_remote_twice_token;
-static struct async_signal_handler *sigint_remote_token;
+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
static struct async_event_handler *remote_async_inferior_event_token;
-/* Asynchronous signal handle registered as event loop source for when
- the remote sent us a %Stop notification. The registered callback
- will do a vStopped sequence to pull the rest of the events out of
- the remote side into our event queue. */
-
-static struct async_event_handler *remote_async_get_pending_events_token;
\f
static ptid_t magic_null_ptid;
bufp = rs->buf;
if (bufp[0] != '\0') /* q packet recognized */
{
+ struct cleanup *old_chain;
+ char *saved_reply;
+
+ /* remote_notice_new_inferior (in the loop below) may make
+ new RSP calls, which clobber rs->buf. Work with a
+ copy. */
+ bufp = saved_reply = xstrdup (rs->buf);
+ old_chain = make_cleanup (free_current_contents, &saved_reply);
+
while (*bufp++ == 'm') /* reply contains one or more TID */
{
do
}
}
while (*bufp++ == ','); /* comma-separated list */
+ free_current_contents (&saved_reply);
putpkt ("qsThreadInfo");
getpkt (&rs->buf, &rs->buf_size, 0);
- bufp = rs->buf;
+ bufp = saved_reply = xstrdup (rs->buf);
}
+ do_cleanups (old_chain);
return; /* done */
}
}
/* Clean up connection to a remote debugger. */
static void
-remote_close (int quitting)
+remote_close (void)
{
if (remote_desc == NULL)
return; /* already closed */
if (remote_async_inferior_event_token)
delete_async_event_handler (&remote_async_inferior_event_token);
- if (remote_async_get_pending_events_token)
- delete_async_event_handler (&remote_async_get_pending_events_token);
+
+ remote_notif_unregister_async_event_handler ();
+
+ trace_reset_local_state ();
}
/* Query the remote side for the text, data and bss offsets. */
send_interrupt_sequence (void)
{
if (interrupt_sequence_mode == interrupt_sequence_control_c)
- serial_write (remote_desc, "\x03", 1);
+ remote_serial_write ("\x03", 1);
else if (interrupt_sequence_mode == interrupt_sequence_break)
serial_send_break (remote_desc);
else if (interrupt_sequence_mode == interrupt_sequence_break_g)
{
serial_send_break (remote_desc);
- serial_write (remote_desc, "g", 1);
+ remote_serial_write ("g", 1);
}
else
internal_error (__FILE__, __LINE__,
interrupt_sequence_mode);
}
+
+/* If STOP_REPLY is a T stop reply, look for the "thread" register,
+ and extract the PTID. Returns NULL_PTID if not found. */
+
+static ptid_t
+stop_reply_extract_thread (char *stop_reply)
+{
+ if (stop_reply[0] == 'T' && strlen (stop_reply) > 3)
+ {
+ char *p;
+
+ /* Txx r:val ; r:val (...) */
+ p = &stop_reply[3];
+
+ /* Look for "register" named "thread". */
+ while (*p != '\0')
+ {
+ char *p1;
+
+ p1 = strchr (p, ':');
+ if (p1 == NULL)
+ return null_ptid;
+
+ if (strncmp (p, "thread", p1 - p) == 0)
+ return read_ptid (++p1, &p);
+
+ p1 = strchr (p, ';');
+ if (p1 == NULL)
+ return null_ptid;
+ p1++;
+
+ p = p1;
+ }
+ }
+
+ return null_ptid;
+}
+
/* Query the remote target for which is the current thread/process,
add it to our tables, and update INFERIOR_PTID. The caller is
responsible for setting the state such that the remote end is ready
- to return the current thread. */
+ to return the current thread.
+
+ This function is called after handling the '?' or 'vRun' packets,
+ whose response is a stop reply from which we can also try
+ extracting the thread. If the target doesn't support the explicit
+ qC query, we infer the current thread from that stop reply, passed
+ in in WAIT_STATUS, which may be NULL. */
static void
-add_current_inferior_and_thread (void)
+add_current_inferior_and_thread (char *wait_status)
{
struct remote_state *rs = get_remote_state ();
int fake_pid_p = 0;
- ptid_t ptid;
+ ptid_t ptid = null_ptid;
inferior_ptid = null_ptid;
- /* Now, if we have thread information, update inferior_ptid. */
- ptid = remote_current_thread (inferior_ptid);
+ /* Now, if we have thread information, update inferior_ptid. First
+ if we have a stop reply handy, maybe it's a T stop reply with a
+ "thread" register we can extract the current thread from. If
+ not, ask the remote which is the current thread, with qC. The
+ former method avoids a roundtrip. Note we don't use
+ remote_parse_stop_reply as that makes use of the target
+ architecture, which we haven't yet fully determined at this
+ point. */
+ if (wait_status != NULL)
+ ptid = stop_reply_extract_thread (wait_status);
+ if (ptid_equal (ptid, null_ptid))
+ ptid = remote_current_thread (inferior_ptid);
+
if (!ptid_equal (ptid, null_ptid))
{
if (!remote_multi_process_p (rs))
error (_("Remote refused setting all-stop mode with: %s"), rs->buf);
}
+ /* Upload TSVs regardless of whether the target is running or not. The
+ remote stub, such as GDBserver, may have some predefined or builtin
+ TSVs, even if the target is not running. */
+ if (remote_get_trace_status (current_trace_status ()) != -1)
+ {
+ struct uploaded_tsv *uploaded_tsvs = NULL;
+
+ remote_upload_trace_state_variables (&uploaded_tsvs);
+ merge_uploaded_trace_state_variables (&uploaded_tsvs);
+ }
+
/* Check whether the target is running now. */
putpkt ("?");
getpkt (&rs->buf, &rs->buf_size, 0);
/* Let the stub know that we want it to return the thread. */
set_continue_thread (minus_one_ptid);
- add_current_inferior_and_thread ();
+ add_current_inferior_and_thread (wait_status);
/* init_wait_for_inferior should be called before get_offsets in order
to manage `inserted' flag in bp loc in a correct state.
mechanism. */
if (strcmp (rs->buf, "OK") != 0)
{
- struct stop_reply *stop_reply;
- struct cleanup *old_chain;
+ struct notif_client *notif = ¬if_client_stop;
- stop_reply = stop_reply_xmalloc ();
- old_chain = make_cleanup (do_stop_reply_xfree, stop_reply);
-
- remote_parse_stop_reply (rs->buf, stop_reply);
- discard_cleanups (old_chain);
-
- /* get_pending_stop_replies acks this one, and gets the rest
- out. */
- pending_stop_reply = stop_reply;
- remote_get_pending_stop_replies ();
+ /* remote_notif_get_pending_replies acks this one, and gets
+ the rest out. */
+ notif_client_stop.pending_event
+ = remote_notif_parse (notif, rs->buf);
+ remote_notif_get_pending_events (notif);
/* Make sure that threads that were stopped remain
stopped. */
if (target_has_execution)
{
if (exec_bfd) /* No use without an exec file. */
- remote_check_symbols (symfile_objfile);
+ remote_check_symbols ();
}
/* Possibly the target has been engaged in a trace run started
if (remote_get_trace_status (current_trace_status ()) != -1)
{
struct uploaded_tp *uploaded_tps = NULL;
- struct uploaded_tsv *uploaded_tsvs = NULL;
if (current_trace_status ()->running)
printf_filtered (_("Trace is already running on the target.\n"));
- /* Get trace state variables first, they may be checked when
- parsing uploaded commands. */
-
- remote_upload_trace_state_variables (&uploaded_tsvs);
-
- merge_uploaded_trace_state_variables (&uploaded_tsvs);
-
remote_upload_tracepoints (&uploaded_tps);
merge_uploaded_tracepoints (&uploaded_tps);
/* Symbol look-up. */
static void
-remote_check_symbols (struct objfile *objfile)
+remote_check_symbols (void)
{
struct remote_state *rs = get_remote_state ();
char *msg, *reply, *tmp;
rs->string_tracing = (support == PACKET_ENABLE);
}
-static struct protocol_feature remote_protocol_features[] = {
+static void
+remote_augmented_libraries_svr4_read_feature
+ (const struct protocol_feature *feature,
+ enum packet_support support, const char *value)
+{
+ struct remote_state *rs = get_remote_state ();
+
+ rs->augmented_libraries_svr4_read = (support == PACKET_ENABLE);
+}
+
+static const struct protocol_feature remote_protocol_features[] = {
{ "PacketSize", PACKET_DISABLE, remote_packet_size, -1 },
{ "qXfer:auxv:read", PACKET_DISABLE, remote_supported_packet,
PACKET_qXfer_auxv },
PACKET_qXfer_libraries },
{ "qXfer:libraries-svr4:read", PACKET_DISABLE, remote_supported_packet,
PACKET_qXfer_libraries_svr4 },
+ { "augmented-libraries-svr4-read", PACKET_DISABLE,
+ remote_augmented_libraries_svr4_read_feature, -1 },
{ "qXfer:memory-map:read", PACKET_DISABLE, remote_supported_packet,
PACKET_qXfer_memory_map },
{ "qXfer:spu:read", PACKET_DISABLE, remote_supported_packet,
{ "QDisableRandomization", PACKET_DISABLE, remote_supported_packet,
PACKET_QDisableRandomization },
{ "QAgent", PACKET_DISABLE, remote_supported_packet, PACKET_QAgent},
+ { "QTBuffer:size", PACKET_DISABLE,
+ remote_supported_packet, PACKET_QTBuffer_size},
{ "tracenz", PACKET_DISABLE,
remote_string_tracing_feature, -1 },
+ { "Qbtrace:off", PACKET_DISABLE, remote_supported_packet, PACKET_Qbtrace_off },
+ { "Qbtrace:bts", PACKET_DISABLE, remote_supported_packet, PACKET_Qbtrace_bts },
+ { "qXfer:btrace:read", PACKET_DISABLE, remote_supported_packet,
+ PACKET_qXfer_btrace }
};
static char *remote_support_xml;
}
}
+/* 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);
+}
static void
remote_open_1 (char *name, int from_tty,
wait_forever_enabled_p = 1;
/* If we're connected to a running target, target_preopen will kill it.
- But if we're connected to a target system with no running process,
- then we will still be connected when it returns. Ask this question
- first, before target_preopen has a chance to kill anything. */
+ Ask this question first, before target_preopen has a chance to kill
+ anything. */
if (remote_desc != NULL && !have_inferiors ())
{
- if (!from_tty
- || query (_("Already connected to a remote target. Disconnect? ")))
- pop_target ();
- else
+ if (from_tty
+ && !query (_("Already connected to a remote target. Disconnect? ")))
error (_("Still connected."));
}
+ /* Here the possibly existing remote target gets unpushed. */
target_preopen (from_tty);
- unpush_target (target);
-
- /* This time without a query. If we were connected to an
- extended-remote target and target_preopen killed the running
- process, we may still be connected. If we are starting "target
- remote" now, the extended-remote target will not have been
- removed by unpush_target. */
- if (remote_desc != NULL && !have_inferiors ())
- pop_target ();
-
/* Make sure we send the passed signals list the next time we resume. */
xfree (last_pass_packet);
last_pass_packet = NULL;
remote_async_inferior_event_token
= create_async_event_handler (remote_async_inferior_event_handler,
NULL);
- remote_async_get_pending_events_token
- = create_async_event_handler (remote_async_get_pending_events_handler,
- NULL);
+ remote_notif_register_async_event_handler ();
/* Reset the target state; these things will be queried either by
remote_query_supported or as they are needed. */
/* Pop the partially set up target - unless something else did
already before throwing the exception. */
if (remote_desc != NULL)
- pop_target ();
+ remote_unpush_target ();
if (target_async_permitted)
wait_forever_enabled_p = 1;
throw_exception (ex);
if (target_can_async_p ())
{
- struct stop_reply *stop_reply;
- struct cleanup *old_chain;
+ struct notif_event *reply
+ = remote_notif_parse (¬if_client_stop, wait_status);
- stop_reply = stop_reply_xmalloc ();
- old_chain = make_cleanup (do_stop_reply_xfree, stop_reply);
- remote_parse_stop_reply (wait_status, stop_reply);
- discard_cleanups (old_chain);
- push_stop_reply (stop_reply);
+ push_stop_reply ((struct stop_reply *) reply);
target_async (inferior_event_handler, 0);
}
support_S = 0;
support_c = 0;
support_C = 0;
- rs->support_vCont_t = 0;
+ rs->supports_vCont.t = 0;
+ rs->supports_vCont.r = 0;
while (p && *p == ';')
{
p++;
else if (*p == 'C' && (*(p + 1) == ';' || *(p + 1) == 0))
support_C = 1;
else if (*p == 't' && (*(p + 1) == ';' || *(p + 1) == 0))
- rs->support_vCont_t = 1;
+ rs->supports_vCont.t = 1;
+ else if (*p == 'r' && (*(p + 1) == ';' || *(p + 1) == 0))
+ rs->supports_vCont.r = 1;
p = strchr (p, ';');
}
if (step && siggnal != GDB_SIGNAL_0)
p += xsnprintf (p, endp - p, ";S%02x", siggnal);
+ else if (step
+ /* GDB is willing to range step. */
+ && use_range_stepping
+ /* Target supports range stepping. */
+ && rs->supports_vCont.r
+ /* We don't currently support range stepping multiple
+ threads with a wildcard (though the protocol allows it,
+ so stubs shouldn't make an active effort to forbid
+ it). */
+ && !(remote_multi_process_p (rs) && ptid_is_pid (ptid)))
+ {
+ struct thread_info *tp;
+
+ if (ptid_equal (ptid, minus_one_ptid))
+ {
+ /* If we don't know about the target thread's tid, then
+ we're resuming magic_null_ptid (see caller). */
+ tp = find_thread_ptid (magic_null_ptid);
+ }
+ else
+ tp = find_thread_ptid (ptid);
+ gdb_assert (tp != NULL);
+
+ if (tp->control.may_range_step)
+ {
+ int addr_size = gdbarch_addr_bit (target_gdbarch ()) / 8;
+
+ p += xsnprintf (p, endp - p, ";r%s,%s",
+ phex_nz (tp->control.step_range_start,
+ addr_size),
+ phex_nz (tp->control.step_range_end,
+ addr_size));
+ }
+ else
+ p += xsnprintf (p, endp - p, ";s");
+ }
else if (step)
p += xsnprintf (p, endp - p, ";s");
else if (siggnal != GDB_SIGNAL_0)
struct remote_state *rs = get_remote_state ();
char *buf;
+ /* In all-stop, we can't mark REMOTE_ASYNC_GET_PENDING_EVENTS_TOKEN
+ (explained in remote-notif.c:handle_notification) so
+ remote_notif_process is not called. We need find a place where
+ 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)
+ remote_notif_process (¬if_client_stop);
+
last_sent_signal = siggnal;
last_sent_step = step;
/* Set up the signal handler for SIGINT, while the target is
executing, ovewriting the 'regular' SIGINT signal handler. */
static void
-initialize_sigint_signal_handler (void)
+async_initialize_sigint_signal_handler (void)
{
- signal (SIGINT, handle_remote_sigint);
+ signal (SIGINT, async_handle_remote_sigint);
}
/* Signal handler for SIGINT, while the target is executing. */
static void
-handle_remote_sigint (int sig)
+async_handle_remote_sigint (int sig)
{
- signal (sig, handle_remote_sigint_twice);
- mark_async_signal_handler (sigint_remote_token);
+ signal (sig, async_handle_remote_sigint_twice);
+ mark_async_signal_handler (async_sigint_remote_token);
}
/* 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
-handle_remote_sigint_twice (int sig)
+async_handle_remote_sigint_twice (int sig)
{
- signal (sig, handle_remote_sigint);
- mark_async_signal_handler (sigint_remote_twice_token);
+ signal (sig, async_handle_remote_sigint);
+ mark_async_signal_handler (async_sigint_remote_twice_token);
}
/* Perform the real interruption of the target execution, in response
/* Perform interrupt, if the first attempt did not succeed. Just give
up on the target alltogether. */
-void
+static void
async_remote_interrupt_twice (gdb_client_data arg)
{
if (remote_debug)
/* Reinstall the usual SIGINT handlers, after the target has
stopped. */
static void
-cleanup_sigint_signal_handler (void *dummy)
+async_cleanup_sigint_signal_handler (void *dummy)
{
signal (SIGINT, handle_sigint);
}
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
-remote_interrupt (int signo)
+sync_remote_interrupt (int signo)
{
/* If this doesn't work, try more severe steps. */
- signal (signo, remote_interrupt_twice);
+ signal (signo, sync_remote_interrupt_twice);
- gdb_call_async_signal_handler (sigint_remote_token, 1);
+ gdb_call_async_signal_handler (async_sigint_remote_token, 1);
}
/* The user typed ^C twice. */
static void
-remote_interrupt_twice (int signo)
+sync_remote_interrupt_twice (int signo)
{
signal (signo, ofunc);
- gdb_call_async_signal_handler (sigint_remote_twice_token, 1);
- signal (signo, remote_interrupt);
+ 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
if (remote_protocol_packets[PACKET_vCont].support == PACKET_SUPPORT_UNKNOWN)
remote_vcont_probe (rs);
- if (!rs->support_vCont_t)
+ if (!rs->supports_vCont.t)
error (_("Remote server does not support stopping threads"));
if (ptid_equal (ptid, minus_one_ptid)
if (target_can_async_p ())
{
signal (SIGINT, handle_sigint);
- deprecated_throw_reason (RETURN_QUIT);
+ quit ();
}
else
{
if (query (_("Interrupted while waiting for the program.\n\
Give up (and stop debugging it)? ")))
{
- pop_target ();
- deprecated_throw_reason (RETURN_QUIT);
+ remote_unpush_target ();
+ quit ();
}
}
return;
delete_file_handler (input_fd);
remote_async_terminal_ours_p = 0;
- initialize_sigint_signal_handler ();
+ 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. */
/* See FIXME in remote_terminal_inferior. */
if (remote_async_terminal_ours_p)
return;
- cleanup_sigint_signal_handler (NULL);
+ async_cleanup_sigint_signal_handler (NULL);
add_file_handler (input_fd, stdin_event_handler, 0);
remote_async_terminal_ours_p = 1;
}
DEF_VEC_O(cached_reg_t);
-struct stop_reply
+typedef struct stop_reply
{
- struct stop_reply *next;
+ struct notif_event base;
+ /* The identifier of the thread about this event */
ptid_t ptid;
struct target_waitstatus ws;
int replay_event;
int core;
-};
-
-/* The list of already fetched and acknowledged stop events. */
-static struct stop_reply *stop_reply_queue;
+} *stop_reply_p;
-static struct stop_reply *
-stop_reply_xmalloc (void)
-{
- struct stop_reply *r = XMALLOC (struct stop_reply);
-
- r->next = NULL;
- return r;
-}
+DECLARE_QUEUE_P (stop_reply_p);
+DEFINE_QUEUE_P (stop_reply_p);
+/* The list of already fetched and acknowledged stop events. This
+ queue is used for notification Stop, and other notifications
+ don't need queue for their events, because the notification events
+ of Stop can't be consumed immediately, so that events should be
+ queued first, and be consumed by remote_wait_{ns,as} one per
+ time. Other notifications can consume their events immediately,
+ so queue is not needed for them. */
+static QUEUE (stop_reply_p) *stop_reply_queue;
static void
stop_reply_xfree (struct stop_reply *r)
}
}
+static void
+remote_notif_stop_parse (struct notif_client *self, char *buf,
+ struct notif_event *event)
+{
+ remote_parse_stop_reply (buf, (struct stop_reply *) event);
+}
+
+static void
+remote_notif_stop_ack (struct notif_client *self, char *buf,
+ struct notif_event *event)
+{
+ struct stop_reply *stop_reply = (struct stop_reply *) event;
+
+ /* acknowledge */
+ putpkt ((char *) self->ack_command);
+
+ if (stop_reply->ws.kind == TARGET_WAITKIND_IGNORE)
+ /* We got an unknown stop reply. */
+ error (_("Unknown stop reply"));
+
+ push_stop_reply (stop_reply);
+}
+
+static int
+remote_notif_stop_can_get_pending_events (struct notif_client *self)
+{
+ /* We can't get pending events in remote_notif_process for
+ notification stop, and we have to do this in remote_wait_ns
+ instead. If we fetch all queued events from stub, remote stub
+ may exit and we have no chance to process them back in
+ remote_wait_ns. */
+ mark_async_event_handler (remote_async_inferior_event_token);
+ return 0;
+}
+
+static void
+stop_reply_dtr (struct notif_event *event)
+{
+ struct stop_reply *r = (struct stop_reply *) event;
+
+ VEC_free (cached_reg_t, r->regcache);
+}
+
+static struct notif_event *
+remote_notif_stop_alloc_reply (void)
+{
+ struct notif_event *r
+ = (struct notif_event *) XMALLOC (struct stop_reply);
+
+ r->dtr = stop_reply_dtr;
+
+ return r;
+}
+
+/* A client of notification Stop. */
+
+struct notif_client notif_client_stop =
+{
+ "Stop",
+ "vStopped",
+ remote_notif_stop_parse,
+ remote_notif_stop_ack,
+ remote_notif_stop_can_get_pending_events,
+ remote_notif_stop_alloc_reply,
+ NULL,
+};
+
+/* A parameter to pass data in and out. */
+
+struct queue_iter_param
+{
+ void *input;
+ struct stop_reply *output;
+};
+
+/* Remove all queue elements meet the condition it checks. */
+
+static int
+remote_notif_remove_all (QUEUE (stop_reply_p) *q,
+ QUEUE_ITER (stop_reply_p) *iter,
+ stop_reply_p event,
+ void *data)
+{
+ struct queue_iter_param *param = data;
+ struct inferior *inf = param->input;
+
+ if (inf == NULL || ptid_get_pid (event->ptid) == inf->pid)
+ {
+ stop_reply_xfree (event);
+ QUEUE_remove_elem (stop_reply_p, q, iter);
+ }
+
+ return 1;
+}
+
/* Discard all pending stop replies of inferior INF. If INF is NULL,
discard everything. */
static void
discard_pending_stop_replies (struct inferior *inf)
{
- struct stop_reply *prev = NULL, *reply, *next;
+ int i;
+ struct queue_iter_param param;
+ struct stop_reply *reply
+ = (struct stop_reply *) notif_client_stop.pending_event;
/* Discard the in-flight notification. */
- if (pending_stop_reply != NULL
+ if (reply != NULL
&& (inf == NULL
- || ptid_get_pid (pending_stop_reply->ptid) == inf->pid))
+ || ptid_get_pid (reply->ptid) == inf->pid))
{
- stop_reply_xfree (pending_stop_reply);
- pending_stop_reply = NULL;
+ stop_reply_xfree (reply);
+ notif_client_stop.pending_event = NULL;
}
+ param.input = inf;
+ param.output = NULL;
/* Discard the stop replies we have already pulled with
vStopped. */
- for (reply = stop_reply_queue; reply; reply = next)
- {
- next = reply->next;
- if (inf == NULL
- || ptid_get_pid (reply->ptid) == inf->pid)
- {
- if (reply == stop_reply_queue)
- stop_reply_queue = reply->next;
- else
- prev->next = reply->next;
+ QUEUE_iterate (stop_reply_p, stop_reply_queue,
+ remote_notif_remove_all, ¶m);
+}
- stop_reply_xfree (reply);
- }
- else
- prev = reply;
+/* A parameter to pass data in and out. */
+
+static int
+remote_notif_remove_once_on_match (QUEUE (stop_reply_p) *q,
+ QUEUE_ITER (stop_reply_p) *iter,
+ stop_reply_p event,
+ void *data)
+{
+ struct queue_iter_param *param = data;
+ ptid_t *ptid = param->input;
+
+ if (ptid_match (event->ptid, *ptid))
+ {
+ param->output = event;
+ QUEUE_remove_elem (stop_reply_p, q, iter);
+ return 0;
}
+
+ return 1;
}
-/* Cleanup wrapper. */
+/* Remove the first reply in 'stop_reply_queue' which matches
+ PTID. */
-static void
-do_stop_reply_xfree (void *arg)
+static struct stop_reply *
+remote_notif_remove_queued_reply (ptid_t ptid)
{
- struct stop_reply *r = arg;
+ struct queue_iter_param param;
- stop_reply_xfree (r);
+ param.input = &ptid;
+ param.output = NULL;
+
+ QUEUE_iterate (stop_reply_p, stop_reply_queue,
+ remote_notif_remove_once_on_match, ¶m);
+ if (notif_debug)
+ fprintf_unfiltered (gdb_stdlog,
+ "notif: discard queued event: 'Stop' in %s\n",
+ target_pid_to_str (ptid));
+
+ return param.output;
}
/* Look for a queued stop reply belonging to PTID. If one is found,
static struct stop_reply *
queued_stop_reply (ptid_t ptid)
{
- struct stop_reply *it;
- struct stop_reply **it_link;
-
- it = stop_reply_queue;
- it_link = &stop_reply_queue;
- while (it)
- {
- if (ptid_match (it->ptid, ptid))
- {
- *it_link = it->next;
- it->next = NULL;
- break;
- }
-
- it_link = &it->next;
- it = *it_link;
- }
+ struct stop_reply *r = remote_notif_remove_queued_reply (ptid);
- if (stop_reply_queue)
+ if (!QUEUE_is_empty (stop_reply_p, stop_reply_queue))
/* There's still at least an event left. */
mark_async_event_handler (remote_async_inferior_event_token);
- return it;
+ return r;
}
/* Push a fully parsed stop reply in the stop reply queue. Since we
static void
push_stop_reply (struct stop_reply *new_event)
{
- struct stop_reply *event;
+ QUEUE_enque (stop_reply_p, stop_reply_queue, new_event);
- if (stop_reply_queue)
- {
- for (event = stop_reply_queue;
- event && event->next;
- event = event->next)
- ;
-
- event->next = new_event;
- }
- else
- stop_reply_queue = new_event;
+ if (notif_debug)
+ fprintf_unfiltered (gdb_stdlog,
+ "notif: push 'Stop' %s to queue %d\n",
+ target_pid_to_str (new_event->ptid),
+ QUEUE_length (stop_reply_p,
+ stop_reply_queue));
mark_async_event_handler (remote_async_inferior_event_token);
}
+static int
+stop_reply_match_ptid_and_ws (QUEUE (stop_reply_p) *q,
+ QUEUE_ITER (stop_reply_p) *iter,
+ struct stop_reply *event,
+ void *data)
+{
+ ptid_t *ptid = data;
+
+ return !(ptid_equal (*ptid, event->ptid)
+ && event->ws.kind == TARGET_WAITKIND_STOPPED);
+}
+
/* Returns true if we have a stop reply for PTID. */
static int
peek_stop_reply (ptid_t ptid)
{
- struct stop_reply *it;
-
- for (it = stop_reply_queue; it; it = it->next)
- if (ptid_equal (ptid, it->ptid))
- {
- if (it->ws.kind == TARGET_WAITKIND_STOPPED)
- return 1;
- }
-
- return 0;
+ return !QUEUE_iterate (stop_reply_p, stop_reply_queue,
+ stop_reply_match_ptid_and_ws, &ptid);
}
/* Parse the stop reply in BUF. Either the function succeeds, and the
error (_("No process or thread specified in stop reply: %s"), buf);
}
-/* When the stub wants to tell GDB about a new stop reply, it sends a
- stop notification (%Stop). Those can come it at any time, hence,
- we have to make sure that any pending putpkt/getpkt sequence we're
- making is finished, before querying the stub for more events with
- vStopped. E.g., if we started a vStopped sequence immediatelly
- upon receiving the %Stop notification, something like this could
- happen:
+/* When the stub wants to tell GDB about a new notification reply, it
+ sends a notification (%Stop, for example). Those can come it at
+ any time, hence, we have to make sure that any pending
+ putpkt/getpkt sequence we're making is finished, before querying
+ the stub for more events with the corresponding ack command
+ (vStopped, for example). E.g., if we started a vStopped sequence
+ immediately upon receiving the notification, something like this
+ could happen:
1.1) --> Hg 1
1.2) <-- OK
Obviously, the reply in step #1.6 would be unexpected to a vStopped
query.
- To solve this, whenever we parse a %Stop notification sucessfully,
+ To solve this, whenever we parse a %Stop notification successfully,
we mark the REMOTE_ASYNC_GET_PENDING_EVENTS_TOKEN, and carry on
doing whatever we were doing:
2.9) --> OK
*/
-static void
-remote_get_pending_stop_replies (void)
+void
+remote_notif_get_pending_events (struct notif_client *nc)
{
struct remote_state *rs = get_remote_state ();
- if (pending_stop_reply)
+ if (nc->pending_event)
{
- /* acknowledge */
- putpkt ("vStopped");
+ if (notif_debug)
+ fprintf_unfiltered (gdb_stdlog,
+ "notif: process: '%s' ack pending event\n",
+ nc->name);
- /* Now we can rely on it. */
- push_stop_reply (pending_stop_reply);
- pending_stop_reply = NULL;
+ /* acknowledge */
+ nc->ack (nc, rs->buf, nc->pending_event);
+ nc->pending_event = NULL;
while (1)
{
if (strcmp (rs->buf, "OK") == 0)
break;
else
- {
- struct cleanup *old_chain;
- struct stop_reply *stop_reply = stop_reply_xmalloc ();
-
- old_chain = make_cleanup (do_stop_reply_xfree, stop_reply);
- remote_parse_stop_reply (rs->buf, stop_reply);
-
- /* acknowledge */
- putpkt ("vStopped");
-
- if (stop_reply->ws.kind != TARGET_WAITKIND_IGNORE)
- {
- /* Now we can rely on it. */
- discard_cleanups (old_chain);
- push_stop_reply (stop_reply);
- }
- else
- /* We got an unknown stop reply. */
- do_cleanups (old_chain);
- }
+ remote_notif_ack (nc, rs->buf);
}
}
+ else
+ {
+ if (notif_debug)
+ fprintf_unfiltered (gdb_stdlog,
+ "notif: process: '%s' no pending reply\n",
+ nc->name);
+ }
}
-
/* Called when it is decided that STOP_REPLY holds the info of the
event that is to be returned to the core. This function always
destroys STOP_REPLY. */
/* Acknowledge a pending stop reply that may have arrived in the
mean time. */
- if (pending_stop_reply != NULL)
- remote_get_pending_stop_replies ();
+ if (notif_client_stop.pending_event != NULL)
+ remote_notif_get_pending_events (¬if_client_stop);
/* If indeed we noticed a stop reply, we're done. */
stop_reply = queued_stop_reply (ptid);
else
{
int ret;
+ int is_notif;
if (!target_is_async_p ())
{
- ofunc = signal (SIGINT, remote_interrupt);
+ 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 ();
- remote_interrupt (SIGINT);
+ sync_remote_interrupt (SIGINT);
}
}
_never_ wait for ever -> test on target_is_async_p().
However, before we do that we need to ensure that the caller
knows how to take the target into/out of async mode. */
- ret = getpkt_sane (&rs->buf, &rs->buf_size, wait_forever_enabled_p);
+ ret = getpkt_or_notif_sane (&rs->buf, &rs->buf_size,
+ wait_forever_enabled_p, &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)
+ return minus_one_ptid;
}
buf = rs->buf;
break;
case 'T': case 'S': case 'X': case 'W':
{
- struct stop_reply *stop_reply;
- struct cleanup *old_chain;
+ struct stop_reply *stop_reply
+ = (struct stop_reply *) remote_notif_parse (¬if_client_stop,
+ rs->buf);
- stop_reply = stop_reply_xmalloc ();
- old_chain = make_cleanup (do_stop_reply_xfree, stop_reply);
- remote_parse_stop_reply (buf, stop_reply);
- discard_cleanups (old_chain);
event_ptid = process_stop_reply (stop_reply, status);
break;
}
{
/* If there are are events left in the queue tell the event loop
to return here. */
- if (stop_reply_queue)
+ if (!QUEUE_is_empty (stop_reply_p, stop_reply_queue))
mark_async_event_handler (remote_async_inferior_event_token);
}
/* Binary mode. Send target system values byte by byte, in
increasing byte addresses. Only escape certain critical
characters. */
- payload_length = remote_escape_output (myaddr, todo, p, &nr_bytes,
- payload_size);
+ payload_length = remote_escape_output (myaddr, todo, (gdb_byte *) p,
+ &nr_bytes, payload_size);
/* If not all TODO bytes fit, then we'll need another packet. Make
a second try to keep the end of the packet aligned. Don't do
- memaddr);
if (new_nr_bytes != nr_bytes)
payload_length = remote_escape_output (myaddr, new_nr_bytes,
- p, &nr_bytes,
+ (gdb_byte *) p, &nr_bytes,
payload_size);
}
/* Return what we have. Let higher layers handle partial reads. */
return i;
}
-\f
-
-/* Remote notification handler. */
-
-static void
-handle_notification (char *buf)
-{
- if (strncmp (buf, "Stop:", 5) == 0)
- {
- if (pending_stop_reply)
- {
- /* We've already parsed the in-flight stop-reply, but the
- stub for some reason thought we didn't, possibly due to
- timeout on its side. Just ignore it. */
- if (remote_debug)
- fprintf_unfiltered (gdb_stdlog, "ignoring resent notification\n");
- }
- else
- {
- struct cleanup *old_chain;
- struct stop_reply *reply = stop_reply_xmalloc ();
-
- old_chain = make_cleanup (do_stop_reply_xfree, reply);
-
- remote_parse_stop_reply (buf + 5, reply);
-
- discard_cleanups (old_chain);
-
- /* Be careful to only set it after parsing, since an error
- may be thrown then. */
- pending_stop_reply = reply;
-
- /* Notify the event loop there's a stop reply to acknowledge
- and that there may be more events to fetch. */
- mark_async_event_handler (remote_async_get_pending_events_token);
-
- if (remote_debug)
- fprintf_unfiltered (gdb_stdlog, "stop notification captured\n");
- }
- }
- else
- {
- /* We ignore notifications we don't recognize, for compatibility
- with newer stubs. */
- }
-}
\f
/* Read or write LEN bytes from inferior memory at MEMADDR,
/* Stuff for dealing with the packets which are part of this protocol.
See comment at top of file for details. */
+/* Close/unpush the remote target, and throw a TARGET_CLOSE_ERROR
+ error to higher layers. Called when a serial error is detected.
+ The exception message is STRING, followed by a colon and a blank,
+ the system error message for errno at function entry and final dot
+ for output compatibility with throw_perror_with_name. */
+
+static void
+unpush_and_perror (const char *string)
+{
+ int saved_errno = errno;
+
+ remote_unpush_target ();
+ throw_error (TARGET_CLOSE_ERROR, "%s: %s.", string,
+ safe_strerror (saved_errno));
+}
+
/* Read a single character from the remote end. */
static int
switch ((enum serial_rc) ch)
{
case SERIAL_EOF:
- pop_target ();
- error (_("Remote connection closed"));
+ remote_unpush_target ();
+ throw_error (TARGET_CLOSE_ERROR, _("Remote connection closed"));
/* no return */
case SERIAL_ERROR:
- pop_target ();
- perror_with_name (_("Remote communication error. "
- "Target disconnected."));
+ unpush_and_perror (_("Remote communication error. "
+ "Target disconnected."));
/* no return */
case SERIAL_TIMEOUT:
break;
return ch;
}
+/* Wrapper for serial_write that closes the target and throws if
+ writing fails. */
+
+static void
+remote_serial_write (const char *str, int len)
+{
+ if (serial_write (remote_desc, str, len))
+ {
+ unpush_and_perror (_("Remote communication error. "
+ "Target disconnected."));
+ }
+}
+
/* Send the command in *BUF to the remote machine, and read the reply
into *BUF. Report an error if we get an error reply. Resize
*BUF using xrealloc if necessary to hold the result, and update
gdb_flush (gdb_stdlog);
do_cleanups (old_chain);
}
- if (serial_write (remote_desc, buf2, p - buf2))
- perror_with_name (_("putpkt: write failed"));
+ remote_serial_write (buf2, p - buf2);
/* If this is a no acks version of the remote protocol, send the
packet and move on. */
doesn't get retransmitted when we resend this
packet. */
skip_frame ();
- serial_write (remote_desc, "+", 1);
+ remote_serial_write ("+", 1);
continue; /* Now, go look for +. */
}
if (forever) /* Watchdog went off? Kill the target. */
{
QUIT;
- pop_target ();
- error (_("Watchdog timeout has expired. Target detached."));
+ remote_unpush_target ();
+ throw_error (TARGET_CLOSE_ERROR,
+ _("Watchdog timeout has expired. "
+ "Target detached."));
}
if (remote_debug)
fputs_filtered ("Timed out.\n", gdb_stdlog);
break;
}
- serial_write (remote_desc, "-", 1);
+ remote_serial_write ("-", 1);
}
if (tries > MAX_TRIES)
/* Skip the ack char if we're in no-ack mode. */
if (!rs->noack_mode)
- serial_write (remote_desc, "+", 1);
+ remote_serial_write ("+", 1);
return -1;
}
/* Skip the ack char if we're in no-ack mode. */
if (!rs->noack_mode)
- serial_write (remote_desc, "+", 1);
+ remote_serial_write ("+", 1);
if (is_notif != NULL)
*is_notif = 0;
return val;
if (packet_ok (rs->buf, &remote_protocol_packets[PACKET_vRun]) == PACKET_OK)
{
- /* We have a wait response; we don't need it, though. All is well. */
+ /* We have a wait response. All is well. */
return 0;
}
else if (remote_protocol_packets[PACKET_vRun].support == PACKET_DISABLE)
extended_remote_create_inferior_1 (char *exec_file, char *args,
char **env, int from_tty)
{
+ int run_worked;
+ char *stop_reply;
+ struct remote_state *rs = get_remote_state ();
+
/* If running asynchronously, register the target file descriptor
with the event loop. */
if (target_can_async_p ())
extended_remote_disable_randomization (disable_randomization);
/* Now restart the remote server. */
- if (extended_remote_run (args) == -1)
+ run_worked = extended_remote_run (args) != -1;
+ if (!run_worked)
{
/* vRun was not supported. Fail if we need it to do what the
user requested. */
init_wait_for_inferior ();
}
- add_current_inferior_and_thread ();
+ /* vRun's success return is a stop reply. */
+ stop_reply = run_worked ? rs->buf : NULL;
+ add_current_inferior_and_thread (stop_reply);
/* Get updated offsets, if the stub uses qOffsets. */
get_offsets ();
int bpsize;
struct condition_list *cond = NULL;
+ /* Make sure the remote is pointing at the right process, if
+ necessary. */
+ if (!gdbarch_has_global_breakpoints (target_gdbarch ()))
+ set_general_process ();
+
gdbarch_remote_breakpoint_from_pc (gdbarch, &addr, &bpsize);
rs = get_remote_state ();
char *p = rs->buf;
char *endbuf = rs->buf + get_remote_packet_size ();
+ /* Make sure the remote is pointing at the right process, if
+ necessary. */
+ if (!gdbarch_has_global_breakpoints (target_gdbarch ()))
+ set_general_process ();
+
*(p++) = 'z';
*(p++) = '0';
*(p++) = ',';
if (remote_protocol_packets[PACKET_Z0 + packet].support == PACKET_DISABLE)
return 1;
+ /* Make sure the remote is pointing at the right process, if
+ necessary. */
+ if (!gdbarch_has_global_breakpoints (target_gdbarch ()))
+ set_general_process ();
+
xsnprintf (rs->buf, endbuf - rs->buf, "Z%x,", packet);
p = strchr (rs->buf, '\0');
addr = remote_address_masked (addr);
if (remote_protocol_packets[PACKET_Z0 + packet].support == PACKET_DISABLE)
return -1;
+ /* Make sure the remote is pointing at the right process, if
+ necessary. */
+ if (!gdbarch_has_global_breakpoints (target_gdbarch ()))
+ set_general_process ();
+
xsnprintf (rs->buf, endbuf - rs->buf, "z%x,", packet);
p = strchr (rs->buf, '\0');
addr = remote_address_masked (addr);
if (remote_protocol_packets[PACKET_Z1].support == PACKET_DISABLE)
return -1;
+ /* Make sure the remote is pointing at the right process, if
+ necessary. */
+ if (!gdbarch_has_global_breakpoints (target_gdbarch ()))
+ set_general_process ();
+
rs = get_remote_state ();
p = rs->buf;
endbuf = rs->buf + get_remote_packet_size ();
if (remote_protocol_packets[PACKET_Z1].support == PACKET_DISABLE)
return -1;
+ /* Make sure the remote is pointing at the right process, if
+ necessary. */
+ if (!gdbarch_has_global_breakpoints (target_gdbarch ()))
+ set_general_process ();
+
*(p++) = 'z';
*(p++) = '1';
*(p++) = ',';
_("remote_remove_hw_breakpoint: reached end of function"));
}
-/* Table used by the crc32 function to calcuate the checksum. */
-
-static unsigned long crc32_table[256] =
-{0, 0};
-
-static unsigned long
-crc32 (const unsigned char *buf, 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--)
- {
- crc = (crc << 8) ^ crc32_table[((crc >> 24) ^ *buf) & 255];
- buf++;
- }
- return crc;
-}
-
/* Verify memory using the "qCRC:" request. */
static int
unsigned long host_crc, target_crc;
char *tmp;
+ /* Make sure the remote is pointing at the right process. */
+ set_general_process ();
+
/* FIXME: assumes lma can fit into long. */
xsnprintf (rs->buf, get_remote_packet_size (), "qCRC:%lx,%lx",
(long) lma, (long) size);
/* Be clever; compute the host_crc before waiting for target
reply. */
- host_crc = crc32 (data, size, 0xffffffff);
+ host_crc = xcrc32 (data, size, 0xffffffff);
getpkt (&rs->buf, &rs->buf_size, 0);
if (rs->buf[0] == 'E')
{
asection *s;
struct cleanup *old_chain;
- char *sectdata;
+ gdb_byte *sectdata;
const char *sectname;
bfd_size_type size;
bfd_vma lma;
if (!exec_bfd)
error (_("command cannot be used without an exec file"));
+ /* Make sure the remote is pointing at the right process. */
+ set_general_process ();
+
for (s = exec_bfd->sections; s; s = s->next)
{
if (!(s->flags & SEC_LOAD))
/* Escape as much data as fits into rs->buf. */
buf_len = remote_escape_output
- (writebuf, len, (rs->buf + i), &max_size, max_size);
+ (writebuf, len, (gdb_byte *) rs->buf + i, &max_size, max_size);
if (putpkt_binary (rs->buf, i + buf_len) < 0
|| getpkt_sane (&rs->buf, &rs->buf_size, 0) < 0
error (_("Remote qXfer reply contained no data."));
/* Got some data. */
- i = remote_unescape_input (rs->buf + 1, packet_len - 1, readbuf, n);
+ i = remote_unescape_input ((gdb_byte *) rs->buf + 1,
+ packet_len - 1, readbuf, n);
/* 'l' is an EOF marker, possibly including a final block of data,
or possibly empty. If we have the final block of a non-empty
return remote_read_qxfer (ops, "uib", annex, readbuf, offset, len,
&remote_protocol_packets[PACKET_qXfer_uib]);
+ case TARGET_OBJECT_BTRACE:
+ return remote_read_qxfer (ops, "btrace", annex, readbuf, offset, len,
+ &remote_protocol_packets[PACKET_qXfer_btrace]);
+
default:
return -1;
}
pattern, pattern_len, found_addrp);
}
+ /* Make sure the remote is pointing at the right process. */
+ set_general_process ();
+
/* Insert header. */
i = snprintf (rs->buf, max_size,
"qSearch:memory:%s;%s;",
/* Escape as much data as fits into rs->buf. */
escaped_pattern_len =
- remote_escape_output (pattern, pattern_len, (rs->buf + i),
+ remote_escape_output (pattern, pattern_len, (gdb_byte *) rs->buf + i,
&used_pattern_len, max_size);
/* Bail if the pattern is too large. */
remote_buffer_add_int (&p, &left, offset);
remote_buffer_add_string (&p, &left, ",");
- p += remote_escape_output (write_buf, len, p, &out_len,
+ p += remote_escape_output (write_buf, len, (gdb_byte *) p, &out_len,
get_remote_packet_size () - (p - rs->buf));
return remote_hostio_send_command (p - rs->buf, PACKET_vFile_pwrite,
if (ret < 0)
return ret;
- read_len = remote_unescape_input (attachment, attachment_len,
+ read_len = remote_unescape_input ((gdb_byte *) attachment, attachment_len,
read_buf, len);
if (read_len != ret)
error (_("Read returned %d, but %d bytes."), ret, (int) read_len);
ret = xmalloc (len + 1);
- read_len = remote_unescape_input (attachment, attachment_len,
- ret, len);
+ read_len = remote_unescape_input ((gdb_byte *) attachment, attachment_len,
+ (gdb_byte *) ret, len);
if (read_len != len)
error (_("Readlink returned %d, but %d bytes."), len, read_len);
connection was already torn down. */
remote_hostio_close (fd, &remote_errno);
- return 1;
+ /* Zero means success. */
+ return 0;
}
static file_ptr
pos = 0;
while (nbytes > pos)
{
- bytes = remote_hostio_pread (fd, (char *)buf + pos, nbytes - pos,
+ bytes = remote_hostio_pread (fd, (gdb_byte *) buf + pos, nbytes - pos,
offset + pos, &remote_errno);
if (bytes == 0)
/* Success, but no bytes, means end-of-file. */
if (!remote_desc)
error (_("command can only be used with remote target"));
- file = fopen (local_file, "rb");
+ file = gdb_fopen_cloexec (local_file, "rb");
if (file == NULL)
perror_with_name (local_file);
back_to = make_cleanup_fclose (file);
if (fd == -1)
remote_hostio_error (remote_errno);
- file = fopen (local_file, "wb");
+ file = gdb_fopen_cloexec (local_file, "wb");
if (file == NULL)
perror_with_name (local_file);
back_to = make_cleanup_fclose (file);
struct breakpoint *b = loc->owner;
struct tracepoint *t = (struct tracepoint *) b;
- encode_actions (loc->owner, loc, &tdp_actions, &stepping_actions);
+ encode_actions_rsp (loc, &tdp_actions, &stepping_actions);
old_chain = make_cleanup (free_actions_list_cleanup_wrapper,
tdp_actions);
(void) make_cleanup (free_actions_list_cleanup_wrapper,
return; /* No information to give. */
strcpy (target_buf, "QTro");
+ offset = strlen (target_buf);
for (s = exec_bfd->sections; s; s = s->next)
{
char tmp1[40], tmp2[40];
/* FIXME we need to get register block size some other way. */
extern int trace_regblock_size;
volatile struct gdb_exception ex;
+ enum packet_result result;
+
+ if (remote_protocol_packets[PACKET_qTStatus].support == PACKET_DISABLE)
+ return -1;
trace_regblock_size = get_remote_arch_state ()->sizeof_g_packet;
}
if (ex.reason < 0)
{
- exception_fprintf (gdb_stderr, ex, "qTStatus: ");
- return -1;
+ if (ex.error != TARGET_CLOSE_ERROR)
+ {
+ exception_fprintf (gdb_stderr, ex, "qTStatus: ");
+ return -1;
+ }
+ throw_exception (ex);
}
+ result = packet_ok (p, &remote_protocol_packets[PACKET_qTStatus]);
+
/* If the remote target doesn't do tracing, flag it. */
- if (*p == '\0')
+ if (result == PACKET_UNKNOWN)
return -1;
/* We're working with a live target. */
- ts->from_file = 0;
+ ts->filename = NULL;
if (*p++ != 'T')
error (_("Bogus trace status reply from target: %s"), target_buf);
static int
remote_trace_find (enum trace_find_type type, int num,
- ULONGEST addr1, ULONGEST addr2,
+ CORE_ADDR addr1, CORE_ADDR addr2,
int *tpp)
{
struct remote_state *rs = get_remote_state ();
}
}
+static void
+remote_set_trace_buffer_size (LONGEST val)
+{
+ if (remote_protocol_packets[PACKET_QTBuffer_size].support
+ != PACKET_DISABLE)
+ {
+ struct remote_state *rs = get_remote_state ();
+ char *buf = rs->buf;
+ char *endbuf = rs->buf + get_remote_packet_size ();
+ enum packet_result result;
+
+ gdb_assert (val >= 0 || val == -1);
+ buf += xsnprintf (buf, endbuf - buf, "QTBuffer:size:");
+ /* Send -1 as literal "-1" to avoid host size dependency. */
+ if (val < 0)
+ {
+ *buf++ = '-';
+ buf += hexnumstr (buf, (ULONGEST) -val);
+ }
+ else
+ buf += hexnumstr (buf, (ULONGEST) val);
+
+ putpkt (rs->buf);
+ remote_get_noisy_reply (&rs->buf, &rs->buf_size);
+ result = packet_ok (rs->buf,
+ &remote_protocol_packets[PACKET_QTBuffer_size]);
+
+ if (result != PACKET_OK)
+ warning (_("Bogus reply from target: %s"), rs->buf);
+ }
+}
+
static int
-remote_set_trace_notes (char *user, char *notes, char *stop_notes)
+remote_set_trace_notes (const char *user, const char *notes,
+ const char *stop_notes)
{
struct remote_state *rs = get_remote_state ();
char *reply;
if (user)
{
buf += xsnprintf (buf, endbuf - buf, "user:");
- nbytes = bin2hex (user, buf, 0);
+ nbytes = bin2hex ((gdb_byte *) user, buf, 0);
buf += 2 * nbytes;
*buf++ = ';';
}
if (notes)
{
buf += xsnprintf (buf, endbuf - buf, "notes:");
- nbytes = bin2hex (notes, buf, 0);
+ nbytes = bin2hex ((gdb_byte *) notes, buf, 0);
buf += 2 * nbytes;
*buf++ = ';';
}
if (stop_notes)
{
buf += xsnprintf (buf, endbuf - buf, "tstop:");
- nbytes = bin2hex (stop_notes, buf, 0);
+ nbytes = bin2hex ((gdb_byte *) stop_notes, buf, 0);
buf += 2 * nbytes;
*buf++ = ';';
}
return (remote_protocol_packets[PACKET_QAgent].support != PACKET_DISABLE);
}
+struct btrace_target_info
+{
+ /* The ptid of the traced thread. */
+ ptid_t ptid;
+};
+
+/* Check whether the target supports branch tracing. */
+
+static int
+remote_supports_btrace (void)
+{
+ if (remote_protocol_packets[PACKET_Qbtrace_off].support != PACKET_ENABLE)
+ return 0;
+ if (remote_protocol_packets[PACKET_Qbtrace_bts].support != PACKET_ENABLE)
+ return 0;
+ if (remote_protocol_packets[PACKET_qXfer_btrace].support != PACKET_ENABLE)
+ return 0;
+
+ return 1;
+}
+
+/* Enable branch tracing. */
+
+static struct btrace_target_info *
+remote_enable_btrace (ptid_t ptid)
+{
+ struct btrace_target_info *tinfo = NULL;
+ struct packet_config *packet = &remote_protocol_packets[PACKET_Qbtrace_bts];
+ struct remote_state *rs = get_remote_state ();
+ char *buf = rs->buf;
+ char *endbuf = rs->buf + get_remote_packet_size ();
+
+ if (packet->support != PACKET_ENABLE)
+ error (_("Target does not support branch tracing."));
+
+ set_general_thread (ptid);
+
+ buf += xsnprintf (buf, endbuf - buf, "%s", packet->name);
+ putpkt (rs->buf);
+ getpkt (&rs->buf, &rs->buf_size, 0);
+
+ if (packet_ok (rs->buf, packet) == PACKET_ERROR)
+ {
+ if (rs->buf[0] == 'E' && rs->buf[1] == '.')
+ error (_("Could not enable branch tracing for %s: %s"),
+ target_pid_to_str (ptid), rs->buf + 2);
+ else
+ error (_("Could not enable branch tracing for %s."),
+ target_pid_to_str (ptid));
+ }
+
+ tinfo = xzalloc (sizeof (*tinfo));
+ tinfo->ptid = ptid;
+
+ return tinfo;
+}
+
+/* Disable branch tracing. */
+
+static void
+remote_disable_btrace (struct btrace_target_info *tinfo)
+{
+ struct packet_config *packet = &remote_protocol_packets[PACKET_Qbtrace_off];
+ struct remote_state *rs = get_remote_state ();
+ char *buf = rs->buf;
+ char *endbuf = rs->buf + get_remote_packet_size ();
+
+ if (packet->support != PACKET_ENABLE)
+ error (_("Target does not support branch tracing."));
+
+ set_general_thread (tinfo->ptid);
+
+ buf += xsnprintf (buf, endbuf - buf, "%s", packet->name);
+ putpkt (rs->buf);
+ getpkt (&rs->buf, &rs->buf_size, 0);
+
+ if (packet_ok (rs->buf, packet) == PACKET_ERROR)
+ {
+ if (rs->buf[0] == 'E' && rs->buf[1] == '.')
+ error (_("Could not disable branch tracing for %s: %s"),
+ target_pid_to_str (tinfo->ptid), rs->buf + 2);
+ else
+ error (_("Could not disable branch tracing for %s."),
+ target_pid_to_str (tinfo->ptid));
+ }
+
+ xfree (tinfo);
+}
+
+/* Teardown branch tracing. */
+
+static void
+remote_teardown_btrace (struct btrace_target_info *tinfo)
+{
+ /* We must not talk to the target during teardown. */
+ xfree (tinfo);
+}
+
+/* Read the branch trace. */
+
+static VEC (btrace_block_s) *
+remote_read_btrace (struct btrace_target_info *tinfo,
+ enum btrace_read_type type)
+{
+ struct packet_config *packet = &remote_protocol_packets[PACKET_qXfer_btrace];
+ struct remote_state *rs = get_remote_state ();
+ VEC (btrace_block_s) *btrace = NULL;
+ const char *annex;
+ char *xml;
+
+ if (packet->support != PACKET_ENABLE)
+ error (_("Target does not support branch tracing."));
+
+#if !defined(HAVE_LIBEXPAT)
+ error (_("Cannot process branch tracing result. XML parsing not supported."));
+#endif
+
+ switch (type)
+ {
+ case btrace_read_all:
+ annex = "all";
+ break;
+ case btrace_read_new:
+ annex = "new";
+ break;
+ default:
+ internal_error (__FILE__, __LINE__,
+ _("Bad branch tracing read type: %u."),
+ (unsigned int) type);
+ }
+
+ xml = target_read_stralloc (¤t_target,
+ TARGET_OBJECT_BTRACE, annex);
+ if (xml != NULL)
+ {
+ struct cleanup *cleanup = make_cleanup (xfree, xml);
+
+ btrace = parse_xml_btrace (xml);
+ do_cleanups (cleanup);
+ }
+
+ return btrace;
+}
+
+static int
+remote_augmented_libraries_svr4_read (void)
+{
+ struct remote_state *rs = get_remote_state ();
+
+ return rs->augmented_libraries_svr4_read;
+}
+
static void
init_remote_ops (void)
{
remote_ops.to_get_min_fast_tracepoint_insn_len = remote_get_min_fast_tracepoint_insn_len;
remote_ops.to_set_disconnected_tracing = remote_set_disconnected_tracing;
remote_ops.to_set_circular_trace_buffer = remote_set_circular_trace_buffer;
+ remote_ops.to_set_trace_buffer_size = remote_set_trace_buffer_size;
remote_ops.to_set_trace_notes = remote_set_trace_notes;
remote_ops.to_core_of_thread = remote_core_of_thread;
remote_ops.to_verify_memory = remote_verify_memory;
remote_ops.to_traceframe_info = remote_traceframe_info;
remote_ops.to_use_agent = remote_use_agent;
remote_ops.to_can_use_agent = remote_can_use_agent;
+ remote_ops.to_supports_btrace = remote_supports_btrace;
+ remote_ops.to_enable_btrace = remote_enable_btrace;
+ remote_ops.to_disable_btrace = remote_disable_btrace;
+ remote_ops.to_teardown_btrace = remote_teardown_btrace;
+ remote_ops.to_read_btrace = remote_read_btrace;
+ remote_ops.to_augmented_libraries_svr4_read =
+ remote_augmented_libraries_svr4_read;
}
/* Set up the extended remote vector by making a copy of the standard
inferior_event_handler (INF_REG_EVENT, NULL);
}
-static void
-remote_async_get_pending_events_handler (gdb_client_data data)
-{
- remote_get_pending_stop_replies ();
-}
-
static void
remote_async (void (*callback) (enum inferior_event_type event_type,
void *context), void *context)
remote_new_objfile (struct objfile *objfile)
{
if (remote_desc != 0) /* Have a remote connection. */
- remote_check_symbols (objfile);
+ remote_check_symbols ();
}
/* Pull all the tracepoints defined on the target and create local
return 0;
}
+/* The "set/show range-stepping" show hook. */
+
+static void
+show_range_stepping (struct ui_file *file, int from_tty,
+ struct cmd_list_element *c,
+ const char *value)
+{
+ fprintf_filtered (file,
+ _("Debugger's willingness to use range stepping "
+ "is %s.\n"), value);
+}
+
+/* The "set/show range-stepping" set hook. */
+
+static void
+set_range_stepping (char *ignore_args, int from_tty,
+ struct cmd_list_element *c)
+{
+ /* Whene enabling, check whether range stepping is actually
+ supported by the target, and warn if not. */
+ if (use_range_stepping)
+ {
+ if (remote_desc != NULL)
+ {
+ struct remote_state *rs = get_remote_state ();
+
+ if (remote_protocol_packets[PACKET_vCont].support == PACKET_SUPPORT_UNKNOWN)
+ remote_vcont_probe (rs);
+
+ if (remote_protocol_packets[PACKET_vCont].support == PACKET_ENABLE
+ && rs->supports_vCont.r)
+ return;
+ }
+
+ warning (_("Range stepping is not supported by the current target"));
+ }
+}
+
void
_initialize_remote (void)
{
struct remote_state *rs;
struct cmd_list_element *cmd;
- char *cmd_name;
+ const char *cmd_name;
/* architecture specific data */
remote_gdbarch_data_handle =
observer_attach_inferior_exit (discard_pending_stop_replies);
/* Set up signal handlers. */
- sigint_remote_token =
+ async_sigint_remote_token =
create_async_signal_handler (async_remote_interrupt, NULL);
- sigint_remote_twice_token =
+ async_sigint_remote_twice_token =
create_async_signal_handler (async_remote_interrupt_twice, NULL);
#if 0
init_remote_threadtests ();
#endif
+ stop_reply_queue = QUEUE_alloc (stop_reply_p, stop_reply_xfree);
/* set/show remote ... */
add_prefix_cmd ("remote", class_maintenance, set_remote_cmd, _("\
breakpoints is %s. */
&remote_set_cmdlist, &remote_show_cmdlist);
- add_setshow_uinteger_cmd ("remoteaddresssize", class_obscure,
- &remote_address_size, _("\
+ add_setshow_zuinteger_cmd ("remoteaddresssize", class_obscure,
+ &remote_address_size, _("\
Set the maximum size of the address (in bits) in a memory packet."), _("\
Show the maximum size of the address (in bits) in a memory packet."), NULL,
- NULL,
- NULL, /* FIXME: i18n: */
- &setlist, &showlist);
+ NULL,
+ NULL, /* FIXME: i18n: */
+ &setlist, &showlist);
add_packet_config_cmd (&remote_protocol_packets[PACKET_X],
"X", "binary-download", 1);
add_packet_config_cmd
(&remote_protocol_packets[PACKET_qXfer_traceframe_info],
- "qXfer:trace-frame-info:read", "traceframe-info", 0);
+ "qXfer:traceframe-info:read", "traceframe-info", 0);
add_packet_config_cmd (&remote_protocol_packets[PACKET_qXfer_uib],
"qXfer:uib:read", "unwind-info-block", 0);
add_packet_config_cmd (&remote_protocol_packets[PACKET_qSearch_memory],
"qSearch:memory", "search-memory", 0);
+ add_packet_config_cmd (&remote_protocol_packets[PACKET_qTStatus],
+ "qTStatus", "trace-status", 0);
+
add_packet_config_cmd (&remote_protocol_packets[PACKET_vFile_open],
"vFile:open", "hostio-open", 0);
add_packet_config_cmd (&remote_protocol_packets[PACKET_QAgent],
"QAgent", "agent", 0);
+ add_packet_config_cmd (&remote_protocol_packets[PACKET_QTBuffer_size],
+ "QTBuffer:size", "trace-buffer-size", 0);
+
+ add_packet_config_cmd (&remote_protocol_packets[PACKET_Qbtrace_off],
+ "Qbtrace:off", "disable-btrace", 0);
+
+ add_packet_config_cmd (&remote_protocol_packets[PACKET_Qbtrace_bts],
+ "Qbtrace:bts", "enable-btrace", 0);
+
+ add_packet_config_cmd (&remote_protocol_packets[PACKET_qXfer_btrace],
+ "qXfer:btrace", "read-btrace", 0);
+
/* Keep the old ``set remote Z-packet ...'' working. Each individual
Z sub-packet has its own set and show commands, but users may
have sets to this variable in their .gdbinit files (or in their
Show the remote pathname for \"run\""), NULL, NULL, NULL,
&remote_set_cmdlist, &remote_show_cmdlist);
+ add_setshow_boolean_cmd ("range-stepping", class_run,
+ &use_range_stepping, _("\
+Enable or disable range stepping."), _("\
+Show whether target-assisted range stepping is enabled."), _("\
+If on, and the target supports it, when stepping a source line, GDB\n\
+tells the target to step the corresponding range of addresses itself instead\n\
+of issuing multiple single-steps. This speeds up source level\n\
+stepping. If off, GDB always issues single-steps, even if range\n\
+stepping is supported by the target. The default is on."),
+ set_range_stepping,
+ show_range_stepping,
+ &setlist,
+ &showlist);
+
/* Eventually initialize fileio. See fileio.c */
initialize_remote_fileio (remote_set_cmdlist, remote_show_cmdlist);