/* 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;
static void initialize_sigint_signal_handler (void);
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 forever, int *is_notif);
static void handle_remote_sigint (int);
static void handle_remote_sigint_twice (int);
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 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);
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 (int pid);
+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;
long regnum; /* GDB's internal register number. */
LONGEST pnum; /* Remote protocol register number. */
int in_g_packet; /* Always part of G packet. */
- /* long size in bytes; == register_size (target_gdbarch, regnum);
+ /* long size in bytes; == register_size (target_gdbarch (), regnum);
at present. */
- /* char *name; == gdbarch_register_name (target_gdbarch, regnum);
+ /* char *name; == gdbarch_register_name (target_gdbarch (), regnum);
at present. */
};
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);
}
TRY_CATCH (ex, RETURN_MASK_ALL)
{
- gdbarch_relocate_instruction (target_gdbarch, &to, from);
+ gdbarch_relocate_instruction (target_gdbarch (), &to, from);
}
if (ex.reason >= 0)
{
static struct remote_arch_state *
get_remote_arch_state (void)
{
- return gdbarch_data (target_gdbarch, remote_gdbarch_data_handle);
+ return gdbarch_data (target_gdbarch (), remote_gdbarch_data_handle);
}
/* Fetch the global remote target state. */
static struct packet_reg *
packet_reg_from_regnum (struct remote_arch_state *rsa, long regnum)
{
- if (regnum < 0 && regnum >= gdbarch_num_regs (target_gdbarch))
+ if (regnum < 0 && regnum >= gdbarch_num_regs (target_gdbarch ()))
return NULL;
else
{
{
int i;
- for (i = 0; i < gdbarch_num_regs (target_gdbarch); i++)
+ for (i = 0; i < gdbarch_num_regs (target_gdbarch ()); i++)
{
struct packet_reg *r = &rsa->regs[i];
some remote targets this variable is principly provided to
facilitate backward compatibility. */
-static int remote_address_size;
+static unsigned int remote_address_size;
/* Temporary to track who currently owns the terminal. See
remote_terminal_* for more details. */
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 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;
if (attached == -1)
attached = remote_query_attached (pid);
- if (gdbarch_has_global_solist (target_gdbarch))
+ if (gdbarch_has_global_solist (target_gdbarch ()))
{
/* If the target shares code across all inferiors, then every
attach adds a new inferior. */
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 */
inferior_ptid = null_ptid;
discard_all_inferiors ();
- /* We're no longer interested in any of these events. */
- discard_pending_stop_replies (-1);
+ /* Stop replies may from inferiors which are still unknown to GDB.
+ We are closing the remote target, so we should discard
+ everything, including the stop replies from GDB-unknown
+ inferiors. */
+ discard_pending_stop_replies (NULL);
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 ();
}
/* 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))
char *wait_status = NULL;
immediate_quit++; /* Allow user to interrupt it. */
+ QUIT;
if (interrupt_on_connect)
send_interrupt_sequence ();
/* On OSs where the list of libraries is global to all
processes, we fetch them early. */
- if (gdbarch_has_global_solist (target_gdbarch))
+ if (gdbarch_has_global_solist (target_gdbarch ()))
solib_add (NULL, from_tty, target, auto_solib_add);
if (non_stop)
else if (rs->non_stop_aware)
{
/* Don't assume that the stub can operate in all-stop mode.
- Request it explicitely. */
+ Request it explicitly. */
putpkt ("QNonStop:0");
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.
supported for non-stop; it could be, but it is tricky if
there are no stopped threads when we connect. */
if (remote_read_description_p (target)
- && gdbarch_target_desc (target_gdbarch) == NULL)
+ && gdbarch_target_desc (target_gdbarch ()) == NULL)
{
target_clear_description ();
target_find_description ();
mechanism. */
if (strcmp (rs->buf, "OK") != 0)
{
- struct stop_reply *stop_reply;
- struct cleanup *old_chain;
-
- 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);
+ struct notif_client *notif = ¬if_client_stop;
- /* 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. */
rs->starting_up = 0;
/* If breakpoints are global, insert them now. */
- if (gdbarch_has_global_breakpoints (target_gdbarch)
+ if (gdbarch_has_global_breakpoints (target_gdbarch ())
&& breakpoints_always_inserted_mode ())
insert_breakpoints ();
}
xsnprintf (msg, get_remote_packet_size (), "qSymbol::%s", &reply[8]);
else
{
- int addr_size = gdbarch_addr_bit (target_gdbarch) / 8;
+ int addr_size = gdbarch_addr_bit (target_gdbarch ()) / 8;
CORE_ADDR sym_addr = SYMBOL_VALUE_ADDRESS (sym);
/* If this is a function address, return the start of code
instead of any data function descriptor. */
- sym_addr = gdbarch_convert_from_func_ptr_addr (target_gdbarch,
+ sym_addr = gdbarch_convert_from_func_ptr_addr (target_gdbarch (),
sym_addr,
¤t_target);
{ "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 (from_tty && !extended)
puts_filtered (_("Ending remote debugging.\n"));
- discard_pending_stop_replies (pid);
target_mourn_inferior ();
}
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);
}
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;
handle_remote_sigint (int sig)
{
signal (sig, handle_remote_sigint_twice);
- mark_async_signal_handler_wrapper (sigint_remote_token);
+ mark_async_signal_handler (sigint_remote_token);
}
/* Signal handler for SIGINT, installed after SIGINT has already been
handle_remote_sigint_twice (int sig)
{
signal (sig, handle_remote_sigint);
- mark_async_signal_handler_wrapper (sigint_remote_twice_token);
+ mark_async_signal_handler (sigint_remote_twice_token);
}
/* Perform the real interruption of the target execution, in response
if (query (_("Interrupted while waiting for the program.\n\
Give up (and stop debugging it)? ")))
{
- pop_target ();
+ remote_unpush_target ();
deprecated_throw_reason (RETURN_QUIT);
}
}
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;
-};
+} *stop_reply_p;
-/* The list of already fetched and acknowledged stop events. */
-static struct stop_reply *stop_reply_queue;
-
-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)
}
}
-/* Discard all pending stop replies of inferior PID. If PID is -1,
+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 (int pid)
+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
- && (pid == -1
- || ptid_get_pid (pending_stop_reply->ptid) == pid))
+ if (reply != NULL
+ && (inf == NULL
+ || 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 (pid == -1
- || ptid_get_pid (reply->ptid) == 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;
+
+ 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));
- stop_reply_xfree (r);
+ 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;
- }
+ struct stop_reply *r = remote_notif_remove_queued_reply (ptid);
- it_link = &it->next;
- it = *it_link;
- }
-
- 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
cached_reg.num = reg->regnum;
fieldsize = hex2bin (p, cached_reg.data,
- register_size (target_gdbarch,
+ register_size (target_gdbarch (),
reg->regnum));
p += 2 * fieldsize;
- if (fieldsize < register_size (target_gdbarch,
+ if (fieldsize < register_size (target_gdbarch (),
reg->regnum))
warning (_("Remote reply is too short: %s"), buf);
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. */
if (stop_reply->regcache)
{
struct regcache *regcache
- = get_thread_arch_regcache (ptid, target_gdbarch);
+ = get_thread_arch_regcache (ptid, target_gdbarch ());
cached_reg_t *reg;
int ix;
struct remote_state *rs = get_remote_state ();
struct stop_reply *stop_reply;
int ret;
+ int is_notif = 0;
/* If in non-stop mode, get out of getpkt even if a
notification is received. */
ret = getpkt_or_notif_sane (&rs->buf, &rs->buf_size,
- 0 /* forever */);
+ 0 /* forever */, &is_notif);
while (1)
{
- if (ret != -1)
+ if (ret != -1 && !is_notif)
switch (rs->buf[0])
{
case 'E': /* Error of some sort. */
/* 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);
/* Otherwise do a blocking wait. */
ret = getpkt_or_notif_sane (&rs->buf, &rs->buf_size,
- 1 /* forever */);
+ 1 /* forever */, &is_notif);
}
}
else
{
int ret;
+ int is_notif;
if (!target_is_async_p ())
{
ofunc = signal (SIGINT, remote_interrupt);
/* If the user hit C-c before this packet, or between packets,
pretend that it was hit right here. */
- if (quit_flag)
+ if (check_quit_flag ())
{
- quit_flag = 0;
+ clear_quit_flag ();
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);
+
+ /* GDB gets a notification. Return to core as this event is
+ not interesting. */
+ if (ret != -1 && is_notif)
+ return minus_one_ptid;
+
if (!target_is_async_p ())
signal (SIGINT, ofunc);
}
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);
}
static CORE_ADDR
remote_address_masked (CORE_ADDR addr)
{
- int address_size = remote_address_size;
+ unsigned int address_size = remote_address_size;
/* If "remoteaddresssize" was not set, default to target address size. */
if (!address_size)
- address_size = gdbarch_addr_bit (target_gdbarch);
+ address_size = gdbarch_addr_bit (target_gdbarch ());
if (address_size > 0
&& address_size < (sizeof (ULONGEST) * 8))
/* 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, size_t length)
-{
- 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,
remote_flash_erase (struct target_ops *ops,
ULONGEST address, LONGEST length)
{
- int addr_size = gdbarch_addr_bit (target_gdbarch) / 8;
+ int addr_size = gdbarch_addr_bit (target_gdbarch ()) / 8;
int saved_remote_timeout = remote_timeout;
enum packet_result ret;
struct cleanup *back_to = make_cleanup (restore_remote_timeout,
/* 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
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
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 +. */
}
str);
do_cleanups (old_chain);
}
- handle_notification (rs->buf, val);
+ handle_notification (rs->buf);
/* We're in sync now, rewait for the ack. */
tcount = 0;
}
0, this function is allowed to time out gracefully and return an
indication of this to the caller. Otherwise return the number of
bytes read. If EXPECTING_NOTIF, consider receiving a notification
- enough reason to return to the caller. */
+ enough reason to return to the caller. *IS_NOTIF is an output
+ boolean that indicates whether *BUF holds a notification or not
+ (a regular packet). */
static int
getpkt_or_notif_sane_1 (char **buf, long *sizeof_buf, int forever,
- int expecting_notif)
+ int expecting_notif, int *is_notif)
{
struct remote_state *rs = get_remote_state ();
int c;
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;
}
str);
do_cleanups (old_chain);
}
+ if (is_notif != NULL)
+ *is_notif = 1;
- handle_notification (*buf, val);
+ handle_notification (*buf);
/* Notifications require no acknowledgement. */
if (expecting_notif)
- return -1;
+ return val;
}
}
}
static int
getpkt_sane (char **buf, long *sizeof_buf, int forever)
{
- return getpkt_or_notif_sane_1 (buf, sizeof_buf, forever, 0);
+ return getpkt_or_notif_sane_1 (buf, sizeof_buf, forever, 0, NULL);
}
static int
-getpkt_or_notif_sane (char **buf, long *sizeof_buf, int forever)
+getpkt_or_notif_sane (char **buf, long *sizeof_buf, int forever,
+ int *is_notif)
{
- return getpkt_or_notif_sane_1 (buf, sizeof_buf, forever, 1);
+ return getpkt_or_notif_sane_1 (buf, sizeof_buf, forever, 1,
+ is_notif);
}
\f
connected. */
rs->waiting_for_stop_reply = 0;
- /* We're no longer interested in these events. */
- discard_pending_stop_replies (ptid_get_pid (inferior_ptid));
-
/* If the current general thread belonged to the process we just
detached from or has exited, the remote side current general
thread becomes undefined. Considering a case like this:
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 ();
CORE_ADDR addr;
struct remote_state *rs;
char *p, *endbuf;
+ char *message;
/* The length field should be set to the size of a breakpoint
instruction, even though we aren't inserting one ourselves. */
switch (packet_ok (rs->buf, &remote_protocol_packets[PACKET_Z1]))
{
case PACKET_ERROR:
+ if (rs->buf[1] == '.')
+ {
+ message = strchr (rs->buf + 2, '.');
+ if (message)
+ error (_("Remote failure reply: %s"), message + 1);
+ }
+ return -1;
case PACKET_UNKNOWN:
return -1;
case PACKET_OK:
{
asection *s;
struct cleanup *old_chain;
- char *sectdata;
+ gdb_byte *sectdata;
const char *sectname;
bfd_size_type size;
bfd_vma lma;
if (res == -1)
error (_("target memory fault, section %s, range %s -- %s"), sectname,
- paddress (target_gdbarch, lma),
- paddress (target_gdbarch, lma + size));
+ paddress (target_gdbarch (), lma),
+ paddress (target_gdbarch (), lma + size));
printf_filtered ("Section %s, range %s -- %s: ", sectname,
- paddress (target_gdbarch, lma),
- paddress (target_gdbarch, lma + size));
+ paddress (target_gdbarch (), lma),
+ paddress (target_gdbarch (), lma + size));
if (res)
printf_filtered ("matched.\n");
else
/* 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;
}
const gdb_byte *pattern, ULONGEST pattern_len,
CORE_ADDR *found_addrp)
{
- int addr_size = gdbarch_addr_bit (target_gdbarch) / 8;
+ int addr_size = gdbarch_addr_bit (target_gdbarch ()) / 8;
struct remote_state *rs = get_remote_state ();
int max_size = get_memory_write_packet_size ();
struct packet_config *packet =
/* 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_read_description_p (struct target_ops *target)
{
struct remote_g_packet_data *data
- = gdbarch_data (target_gdbarch, remote_g_packet_data_handle);
+ = gdbarch_data (target_gdbarch (), remote_g_packet_data_handle);
if (!VEC_empty (remote_g_packet_guess_s, data->guesses))
return 1;
remote_read_description (struct target_ops *target)
{
struct remote_g_packet_data *data
- = gdbarch_data (target_gdbarch, remote_g_packet_data_handle);
+ = gdbarch_data (target_gdbarch (), remote_g_packet_data_handle);
/* Do not try this during initial connection, when we do not know
whether there is a running but stopped thread. */
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. */
bfd *
remote_bfd_open (const char *remote_file, const char *target)
{
- bfd *abfd = bfd_openr_iovec (remote_file, target,
- remote_bfd_iovec_open, NULL,
- remote_bfd_iovec_pread,
- remote_bfd_iovec_close,
- remote_bfd_iovec_stat);
+ bfd *abfd = gdb_bfd_openr_iovec (remote_file, target,
+ remote_bfd_iovec_open, NULL,
+ remote_bfd_iovec_pread,
+ remote_bfd_iovec_close,
+ remote_bfd_iovec_stat);
- if (abfd != NULL)
- gdb_bfd_stash_filename (abfd);
return abfd;
}
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);
{
int isize;
- if (gdbarch_fast_tracepoint_valid_at (target_gdbarch,
+ if (gdbarch_fast_tracepoint_valid_at (target_gdbarch (),
tpaddr, &isize, NULL))
xsnprintf (buf + strlen (buf), BUF_SIZE - strlen (buf), ":F%x",
isize);
/* 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;
-
- /* Set some defaults. */
- ts->running_known = 0;
- ts->stop_reason = trace_stop_reason_unknown;
- ts->traceframe_count = -1;
- ts->buffer_free = 0;
+ ts->filename = NULL;
if (*p++ != 'T')
error (_("Bogus trace status reply from target: %s"), target_buf);
+ /* Function 'parse_trace_status' sets default value of each field of
+ 'ts' at first, so we don't have to do it here. */
parse_trace_status (p, ts);
return ts->running;
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)
{
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 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;
}
/* 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)
ui_out_field_string (uiout, "name", list->name);
ui_out_text (uiout, ": ");
if (list->type == show_cmd)
- do_setshow_command ((char *) NULL, from_tty, list);
+ do_show_command ((char *) NULL, from_tty, list);
else
cmd_func (list, NULL, from_tty);
/* Close the tuple. */
{
struct remote_state *rs;
struct cmd_list_element *cmd;
- char *cmd_name;
+ const char *cmd_name;
/* architecture specific data */
remote_gdbarch_data_handle =
/* Hook into new objfile notification. */
observer_attach_new_objfile (remote_new_objfile);
+ /* We're no longer interested in notification events of an inferior
+ when it exits. */
+ observer_attach_inferior_exit (discard_pending_stop_replies);
/* Set up signal handlers. */
sigint_remote_token =
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_integer_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_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