/* Remote target communications for serial-line targets in custom GDB protocol
- Copyright (C) 1988-2016 Free Software Foundation, Inc.
+ Copyright (C) 1988-2017 Free Software Foundation, Inc.
This file is part of GDB.
#include "btrace.h"
#include "record-btrace.h"
#include <algorithm>
-
-/* Temp hacks for tracepoint encoding migration. */
-static char *target_buf;
-static long target_buf_size;
+#include "common/scoped_restore.h"
+#include "environ.h"
+#include "common/byte-vector.h"
/* Per-program-space data key. */
static const struct program_space_data *remote_pspace_data;
static void interrupt_query (void);
-static void set_general_thread (struct ptid ptid);
-static void set_continue_thread (struct ptid ptid);
+static void set_general_thread (ptid_t ptid);
+static void set_continue_thread (ptid_t ptid);
static void get_offsets (void);
static void print_packet (const char *);
-static void compare_sections_command (char *, int);
-
-static void packet_command (char *, int);
-
static int stub_unpack_int (char *buff, int fieldlength);
static ptid_t remote_current_thread (ptid_t oldptid);
const char *value);
static char *write_ptid (char *buf, const char *endbuf, ptid_t ptid);
-static ptid_t read_ptid (char *buf, char **obuf);
+static ptid_t read_ptid (const char *buf, const char **obuf);
static void remote_set_permissions (struct target_ops *self);
static void remote_check_symbols (void);
-void _initialize_remote (void);
-
struct stop_reply;
static void stop_reply_xfree (struct stop_reply *);
static void remote_parse_stop_reply (char *, struct stop_reply *);
static void remote_unpush_and_throw (void);
+static struct remote_state *get_remote_state (void);
+
/* For "remote". */
static struct cmd_list_element *remote_cmdlist;
#define MAXTHREADLISTRESULTS 32
+/* The max number of chars in debug output. The rest of chars are
+ omitted. */
+
+#define REMOTE_DEBUG_MAX_CHAR 512
+
/* Data for the vFile:pread readahead cache. */
struct readahead_cache
char *name;
int core;
+ /* Thread handle, perhaps a pthread_t or thread_t value, stored as a
+ sequence of bytes. */
+ gdb::byte_vector *thread_handle;
+
/* Whether the target stopped for a breakpoint/watchpoint. */
enum target_stop_reason stop_reason;
/* This is set to the data address of the access causing the target
to stop for a watchpoint. */
CORE_ADDR watch_data_address;
+
+ /* Fields used by the vCont action coalescing implemented in
+ remote_resume / remote_commit_resume. remote_resume stores each
+ thread's last resume request in these fields, so that a later
+ remote_commit_resume knows which is the proper action for this
+ thread to include in the vCont packet. */
+
+ /* True if the last target_resume call for this thread was a step
+ request, false if a continue request. */
+ int last_resume_step;
+
+ /* The signal specified in the last target_resume call for this
+ thread. */
+ enum gdb_signal last_resume_sig;
+
+ /* Whether this thread was already vCont-resumed on the remote
+ side. */
+ int vcont_resumed;
};
static void
{
xfree (info->extra);
xfree (info->name);
+ delete info->thread_handle;
xfree (info);
}
}
/* Utility: wait for reply from stub, while accepting "O" packets. */
+
static char *
-remote_get_noisy_reply (char **buf_p,
- long *sizeof_buf)
+remote_get_noisy_reply ()
{
+ struct remote_state *rs = get_remote_state ();
+
do /* Loop on reply from remote stub. */
{
char *buf;
QUIT; /* Allow user to bail out with ^C. */
- getpkt (buf_p, sizeof_buf, 0);
- buf = *buf_p;
+ getpkt (&rs->buf, &rs->buf_size, 0);
+ buf = rs->buf;
if (buf[0] == 'E')
trace_error (buf);
else if (startswith (buf, "qRelocInsn:"))
{
ULONGEST ul;
CORE_ADDR from, to, org_to;
- char *p, *pp;
+ const char *p, *pp;
int adjusted_size = 0;
int relocated = 0;
{
adjusted_size = to - org_to;
- xsnprintf (buf, *sizeof_buf, "qRelocInsn:%x", adjusted_size);
+ xsnprintf (buf, rs->buf_size, "qRelocInsn:%x", adjusted_size);
putpkt (buf);
}
}
static struct gdbarch_data *remote_gdbarch_data_handle;
static struct remote_arch_state *
-get_remote_arch_state (void)
+get_remote_arch_state (struct gdbarch *gdbarch)
{
- gdb_assert (target_gdbarch () != NULL);
+ gdb_assert (gdbarch != NULL);
return ((struct remote_arch_state *)
- gdbarch_data (target_gdbarch (), remote_gdbarch_data_handle));
+ gdbarch_data (gdbarch, remote_gdbarch_data_handle));
}
/* Fetch the global remote target state. */
function which calls getpkt also needs to be mindful of changes
to rs->buf, but this call limits the number of places which run
into trouble. */
- get_remote_arch_state ();
+ get_remote_arch_state (target_gdbarch ());
return get_remote_state_raw ();
}
/* The "set/show remote exec-file" set command hook. */
static void
-set_remote_exec_file (char *ignored, int from_tty,
+set_remote_exec_file (const char *ignored, int from_tty,
struct cmd_list_element *c)
{
gdb_assert (remote_exec_file_var != NULL);
remote_register_number_and_offset (struct gdbarch *gdbarch, int regnum,
int *pnum, int *poffset)
{
- struct packet_reg *regs;
- struct cleanup *old_chain;
-
gdb_assert (regnum < gdbarch_num_regs (gdbarch));
- regs = XCNEWVEC (struct packet_reg, gdbarch_num_regs (gdbarch));
- old_chain = make_cleanup (xfree, regs);
+ std::vector<packet_reg> regs (gdbarch_num_regs (gdbarch));
- map_regcache_remote_table (gdbarch, regs);
+ map_regcache_remote_table (gdbarch, regs.data ());
*pnum = regs[regnum].pnum;
*poffset = regs[regnum].offset;
- do_cleanups (old_chain);
-
return *pnum != -1;
}
get_remote_packet_size (void)
{
struct remote_state *rs = get_remote_state ();
- struct remote_arch_state *rsa = get_remote_arch_state ();
+ remote_arch_state *rsa = get_remote_arch_state (target_gdbarch ());
if (rs->explicit_packet_size)
return rs->explicit_packet_size;
}
static struct packet_reg *
-packet_reg_from_regnum (struct remote_arch_state *rsa, long regnum)
+packet_reg_from_regnum (struct gdbarch *gdbarch, struct remote_arch_state *rsa,
+ long regnum)
{
- if (regnum < 0 && regnum >= gdbarch_num_regs (target_gdbarch ()))
+ if (regnum < 0 && regnum >= gdbarch_num_regs (gdbarch))
return NULL;
else
{
}
static struct packet_reg *
-packet_reg_from_pnum (struct remote_arch_state *rsa, LONGEST pnum)
+packet_reg_from_pnum (struct gdbarch *gdbarch, struct remote_arch_state *rsa,
+ LONGEST pnum)
{
int i;
- for (i = 0; i < gdbarch_num_regs (target_gdbarch ()); i++)
+ for (i = 0; i < gdbarch_num_regs (gdbarch); i++)
{
struct packet_reg *r = &rsa->regs[i];
static int remote_break;
static void
-set_remotebreak (char *args, int from_tty, struct cmd_list_element *c)
+set_remotebreak (const char *args, int from_tty, struct cmd_list_element *c)
{
if (remote_break)
interrupt_sequence_mode = interrupt_sequence_break;
static unsigned int remote_address_size;
-/* Temporary to track who currently owns the terminal. See
- remote_terminal_* for more details. */
-
-static int remote_async_terminal_ours_p;
-
\f
/* User configurable variables for the number of characters in a
memory read/write packet. MIN (rsa->remote_packet_size,
struct memory_packet_config
{
- char *name;
+ const char *name;
long size;
int fixed_p;
};
get_memory_packet_size (struct memory_packet_config *config)
{
struct remote_state *rs = get_remote_state ();
- struct remote_arch_state *rsa = get_remote_arch_state ();
+ remote_arch_state *rsa = get_remote_arch_state (target_gdbarch ());
long what_they_get;
if (config->fixed_p)
something really big then do a sanity check. */
static void
-set_memory_packet_size (char *args, struct memory_packet_config *config)
+set_memory_packet_size (const char *args, struct memory_packet_config *config)
{
int fixed_p = config->fixed_p;
long size = config->size;
};
static void
-set_memory_write_packet_size (char *args, int from_tty)
+set_memory_write_packet_size (const char *args, int from_tty)
{
set_memory_packet_size (args, &memory_write_packet_config);
}
static void
-show_memory_write_packet_size (char *args, int from_tty)
+show_memory_write_packet_size (const char *args, int from_tty)
{
show_memory_packet_size (&memory_write_packet_config);
}
};
static void
-set_memory_read_packet_size (char *args, int from_tty)
+set_memory_read_packet_size (const char *args, int from_tty)
{
set_memory_packet_size (args, &memory_read_packet_config);
}
static void
-show_memory_read_packet_size (char *args, int from_tty)
+show_memory_read_packet_size (const char *args, int from_tty)
{
show_memory_packet_size (&memory_read_packet_config);
}
static void
show_packet_config_cmd (struct packet_config *config)
{
- char *support = "internal-error";
+ const char *support = "internal-error";
switch (packet_config_support (config))
{
PACKET_QPassSignals,
PACKET_QCatchSyscalls,
PACKET_QProgramSignals,
+ PACKET_QSetWorkingDir,
+ PACKET_QStartupWithShell,
+ PACKET_QEnvironmentHexEncoded,
+ PACKET_QEnvironmentReset,
+ PACKET_QEnvironmentUnset,
PACKET_qCRC,
PACKET_qSearch_memory,
PACKET_vAttach,
static enum auto_boolean remote_Z_packet_detect;
static void
-set_remote_protocol_Z_packet_cmd (char *args, int from_tty,
+set_remote_protocol_Z_packet_cmd (const char *args, int from_tty,
struct cmd_list_element *c)
{
int i;
/* If no main executable is currently open then attempt to
open the file that was executed to create this inferior. */
if (try_open_exec && get_exec_file (0) == NULL)
- exec_file_locate_attach (pid, 1);
+ exec_file_locate_attach (pid, 0, 1);
return inf;
}
+static struct private_thread_info *
+ get_private_info_thread (struct thread_info *info);
+
/* Add thread PTID to GDB's thread list. Tag it as executing/running
according to RUNNING. */
remote_add_thread (ptid_t ptid, int running, int executing)
{
struct remote_state *rs = get_remote_state ();
+ struct thread_info *thread;
/* GDB historically didn't pull threads in the initial connection
setup. If the remote target doesn't even have a concept of
might be confusing to the user. Be silent then, preserving the
age old behavior. */
if (rs->starting_up)
- add_thread_silent (ptid);
+ thread = add_thread_silent (ptid);
else
- add_thread (ptid);
+ thread = add_thread (ptid);
+ get_private_info_thread (thread)->vcont_resumed = executing;
set_executing (ptid, executing);
set_running (ptid, running);
}
}
}
-/* Return the private thread data, creating it if necessary. */
+/* Return THREAD's private thread data, creating it if necessary. */
static struct private_thread_info *
-demand_private_info (ptid_t ptid)
+get_private_info_thread (struct thread_info *thread)
{
- struct thread_info *info = find_thread_ptid (ptid);
-
- gdb_assert (info);
+ gdb_assert (thread != NULL);
- if (!info->priv)
+ if (thread->priv == NULL)
{
- info->priv = XNEW (struct private_thread_info);
- info->private_dtor = free_private_thread_info;
- info->priv->core = -1;
- info->priv->extra = NULL;
- info->priv->name = NULL;
+ struct private_thread_info *priv = XNEW (struct private_thread_info);
+
+ thread->private_dtor = free_private_thread_info;
+ thread->priv = priv;
+
+ priv->core = -1;
+ priv->extra = NULL;
+ priv->name = NULL;
+ priv->name = NULL;
+ priv->last_resume_step = 0;
+ priv->last_resume_sig = GDB_SIGNAL_0;
+ priv->vcont_resumed = 0;
+ priv->thread_handle = nullptr;
}
- return info->priv;
+ return thread->priv;
+}
+
+/* Return PTID's private thread data, creating it if necessary. */
+
+static struct private_thread_info *
+get_private_info_ptid (ptid_t ptid)
+{
+ struct thread_info *info = find_thread_ptid (ptid);
+
+ return get_private_info_thread (info);
}
/* Call this function as a result of
int pid, int needed, int any_count,
int table_size, int *table)
{
- char *catch_packet;
+ const char *catch_packet;
enum packet_result result;
int n_sysno = 0;
pid, needed, any_count, n_sysno);
}
+ std::string built_packet;
if (needed)
{
/* Prepare a packet with the sysno list, assuming max 8+1
characters for a sysno. If the resulting packet size is too
big, fallback on the non-selective packet. */
const int maxpktsz = strlen ("QCatchSyscalls:1") + n_sysno * 9 + 1;
-
- catch_packet = (char *) xmalloc (maxpktsz);
- strcpy (catch_packet, "QCatchSyscalls:1");
+ built_packet.reserve (maxpktsz);
+ built_packet = "QCatchSyscalls:1";
if (!any_count)
{
- int i;
- char *p;
-
- p = catch_packet;
- p += strlen (p);
-
/* Add in catch_packet each syscall to be caught (table[i] != 0). */
- for (i = 0; i < table_size; i++)
+ for (int i = 0; i < table_size; i++)
{
if (table[i] != 0)
- p += xsnprintf (p, catch_packet + maxpktsz - p, ";%x", i);
+ string_appendf (built_packet, ";%x", i);
}
}
- if (strlen (catch_packet) > get_remote_packet_size ())
+ if (built_packet.size () > get_remote_packet_size ())
{
/* catch_packet too big. Fallback to less efficient
non selective mode, with GDB doing the filtering. */
- catch_packet[sizeof ("QCatchSyscalls:1") - 1] = 0;
+ catch_packet = "QCatchSyscalls:1";
}
+ else
+ catch_packet = built_packet.c_str ();
}
else
- catch_packet = xstrdup ("QCatchSyscalls:0");
+ catch_packet = "QCatchSyscalls:0";
- {
- struct cleanup *old_chain = make_cleanup (xfree, catch_packet);
- struct remote_state *rs = get_remote_state ();
+ struct remote_state *rs = get_remote_state ();
- putpkt (catch_packet);
- getpkt (&rs->buf, &rs->buf_size, 0);
- result = packet_ok (rs->buf, &remote_protocol_packets[PACKET_QCatchSyscalls]);
- do_cleanups (old_chain);
- if (result == PACKET_OK)
- return 0;
- else
- return -1;
- }
+ putpkt (catch_packet);
+ getpkt (&rs->buf, &rs->buf_size, 0);
+ result = packet_ok (rs->buf, &remote_protocol_packets[PACKET_QCatchSyscalls]);
+ if (result == PACKET_OK)
+ return 0;
+ else
+ return -1;
}
/* If 'QProgramSignals' is supported, tell the remote stub what
thread. If GEN is set, set the general thread, if not, then set
the step/continue thread. */
static void
-set_thread (struct ptid ptid, int gen)
+set_thread (ptid_t ptid, int gen)
{
struct remote_state *rs = get_remote_state ();
ptid_t state = gen ? rs->general_thread : rs->continue_thread;
}
static void
-set_general_thread (struct ptid ptid)
+set_general_thread (ptid_t ptid)
{
set_thread (ptid, 1);
}
static void
-set_continue_thread (struct ptid ptid)
+set_continue_thread (ptid_t ptid)
{
set_thread (ptid, 0);
}
return buf;
}
-/* Extract a PTID from BUF. If non-null, OBUF is set to the to one
- passed the last parsed char. Returns null_ptid on error. */
+/* Extract a PTID from BUF. If non-null, OBUF is set to one past the
+ last parsed char. Returns null_ptid if no thread id is found, and
+ throws an error if the thread id has an invalid format. */
static ptid_t
-read_ptid (char *buf, char **obuf)
+read_ptid (const char *buf, const char **obuf)
{
- char *p = buf;
- char *pp;
+ const char *p = buf;
+ const char *pp;
ULONGEST pid = 0, tid = 0;
if (*p == 'p')
/* The core the thread was running on. -1 if not known. */
int core;
+
+ /* The thread handle associated with the thread. */
+ gdb::byte_vector *thread_handle;
+
} thread_item_t;
DEF_VEC_O(thread_item_t);
{
xfree (item->extra);
xfree (item->name);
+ delete item->thread_handle;
}
VEC_free (thread_item_t, context->items);
item.core = -1;
item.name = NULL;
item.extra = NULL;
+ item.thread_handle = nullptr;
VEC_safe_push (thread_item_t, context->items, &item);
getpkt (&rs->buf, &rs->buf_size, 0);
if (rs->buf[0] == 'Q' && rs->buf[1] == 'C')
{
- char *obuf;
+ const char *obuf;
ptid_t result;
result = read_ptid (&rs->buf[2], &obuf);
attr = xml_find_attribute (attributes, "name");
item.name = attr != NULL ? xstrdup ((const char *) attr->value) : NULL;
+ attr = xml_find_attribute (attributes, "handle");
+ if (attr != NULL)
+ {
+ item.thread_handle = new gdb::byte_vector
+ (strlen ((const char *) attr->value) / 2);
+ hex2bin ((const char *) attr->value, item.thread_handle->data (),
+ item.thread_handle->size ());
+ }
+ else
+ item.thread_handle = nullptr;
+
item.extra = 0;
VEC_safe_push (thread_item_t, data->items, &item);
{ "id", GDB_XML_AF_NONE, NULL, NULL },
{ "core", GDB_XML_AF_OPTIONAL, gdb_xml_parse_attr_ulongest, NULL },
{ "name", GDB_XML_AF_OPTIONAL, NULL, NULL },
+ { "handle", GDB_XML_AF_OPTIONAL, NULL, NULL },
{ NULL, GDB_XML_AF_NONE, NULL, NULL }
};
#if defined(HAVE_LIBEXPAT)
if (packet_support (PACKET_qXfer_threads) == PACKET_ENABLE)
{
- char *xml = target_read_stralloc (ops, TARGET_OBJECT_THREADS, NULL);
- struct cleanup *back_to = make_cleanup (xfree, xml);
+ gdb::unique_xmalloc_ptr<char> xml
+ = target_read_stralloc (ops, TARGET_OBJECT_THREADS, NULL);
if (xml != NULL && *xml != '\0')
{
gdb_xml_parse_quick (_("threads"), "threads.dtd",
- threads_elements, xml, context);
+ threads_elements, xml.get (), context);
}
- do_cleanups (back_to);
return 1;
}
#endif
if (rs->use_threadinfo_query)
{
- char *bufp;
+ const char *bufp;
putpkt ("qfThreadInfo");
getpkt (&rs->buf, &rs->buf_size, 0);
item.core = -1;
item.name = NULL;
item.extra = NULL;
+ item.thread_handle = nullptr;
VEC_safe_push (thread_item_t, context->items, &item);
}
remote_notice_new_inferior (item->ptid, executing);
- info = demand_private_info (item->ptid);
+ info = get_private_info_ptid (item->ptid);
info->core = item->core;
info->extra = item->extra;
item->extra = NULL;
info->name = item->name;
item->name = NULL;
+ info->thread_handle = item->thread_handle;
+ item->thread_handle = nullptr;
}
}
}
* Optional: targets are not required to implement this function.
*/
-static char *
+static const char *
remote_threads_extra_info (struct target_ops *self, struct thread_info *tp)
{
struct remote_state *rs = get_remote_state ();
if (*p++ == 'm')
{
- parse_static_tracepoint_marker_definition (p, &p, marker);
+ parse_static_tracepoint_marker_definition (p, NULL, marker);
return 1;
}
VEC(static_tracepoint_marker_p) *markers = NULL;
struct static_tracepoint_marker *marker = NULL;
struct cleanup *old_chain;
- char *p;
+ const char *p;
/* Ask for a first packet of static tracepoint marker
definition. */
{
if (stop_reply[0] == 'T' && strlen (stop_reply) > 3)
{
- char *p;
+ const char *p;
/* Txx r:val ; r:val (...) */
p = &stop_reply[3];
/* Look for "register" named "thread". */
while (*p != '\0')
{
- char *p1;
+ const char *p1;
p1 = strchr (p, ':');
if (p1 == NULL)
{
struct remote_state *rs = get_remote_state ();
int fake_pid_p = 0;
- ptid_t ptid;
inferior_ptid = null_ptid;
/* Now, if we have thread information, update inferior_ptid. */
- ptid = get_current_thread (wait_status);
+ ptid_t curr_ptid = get_current_thread (wait_status);
- if (!ptid_equal (ptid, null_ptid))
+ if (curr_ptid != null_ptid)
{
if (!remote_multi_process_p (rs))
fake_pid_p = 1;
-
- inferior_ptid = ptid;
}
else
{
(such as kill) won't work. This variable serves (at least)
double duty as both the pid of the target process (if it has
such), and as a flag indicating that a target is active. */
- inferior_ptid = magic_null_ptid;
+ curr_ptid = magic_null_ptid;
fake_pid_p = 1;
}
- remote_add_inferior (fake_pid_p, ptid_get_pid (inferior_ptid), -1, 1);
+ remote_add_inferior (fake_pid_p, ptid_get_pid (curr_ptid), -1, 1);
- /* Add the main thread. */
- add_thread_silent (inferior_ptid);
+ /* Add the main thread and switch to it. Don't try reading
+ registers yet, since we haven't fetched the target description
+ yet. */
+ thread_info *tp = add_thread_silent (curr_ptid);
+ switch_to_thread_no_regs (tp);
}
/* Print info about a thread that was found already stopped on
set_executing (event_ptid, 0);
set_running (event_ptid, 0);
+ thread->priv->vcont_resumed = 0;
}
/* "Notice" the new inferiors before anything related to
/* On OSs where the list of libraries is global to all
processes, we fetch them early. */
if (gdbarch_has_global_solist (target_gdbarch ()))
- solib_add (NULL, from_tty, target, auto_solib_add);
+ solib_add (NULL, from_tty, auto_solib_add);
if (target_is_non_stop_p ())
{
PACKET_QCatchSyscalls },
{ "QProgramSignals", PACKET_DISABLE, remote_supported_packet,
PACKET_QProgramSignals },
+ { "QSetWorkingDir", PACKET_DISABLE, remote_supported_packet,
+ PACKET_QSetWorkingDir },
+ { "QStartupWithShell", PACKET_DISABLE, remote_supported_packet,
+ PACKET_QStartupWithShell },
+ { "QEnvironmentHexEncoded", PACKET_DISABLE, remote_supported_packet,
+ PACKET_QEnvironmentHexEncoded },
+ { "QEnvironmentReset", PACKET_DISABLE, remote_supported_packet,
+ PACKET_QEnvironmentReset },
+ { "QEnvironmentUnset", PACKET_DISABLE, remote_supported_packet,
+ PACKET_QEnvironmentUnset },
{ "QStartNoAckMode", PACKET_DISABLE, remote_supported_packet,
PACKET_QStartNoAckMode },
{ "multiprocess", PACKET_DISABLE, remote_supported_packet,
instead.
- The target has been resumed in the foreground
- (target_terminal_is_ours is false) with a synchronous resume
+ (target_terminal::is_ours is false) with a synchronous resume
packet, and we're blocked waiting for the stop reply, thus a
Ctrl-C should be immediately sent to the target.
remote_unpush_and_throw ();
}
/* If ^C has already been sent once, offer to disconnect. */
- else if (!target_terminal_is_ours () && rs->ctrlc_pending_p)
+ else if (!target_terminal::is_ours () && rs->ctrlc_pending_p)
interrupt_query ();
/* All-stop protocol, and blocked waiting for stop reply. Send
an interrupt request. */
- else if (!target_terminal_is_ours () && rs->waiting_for_stop_reply)
+ else if (!target_terminal::is_ours () && rs->waiting_for_stop_reply)
target_interrupt (inferior_ptid);
else
rs->got_ctrlc_during_io = 1;
readahead_cache_invalidate ();
- /* Start out by owning the terminal. */
- remote_async_terminal_ours_p = 1;
-
if (target_async_permitted)
{
/* FIXME: cagney/1999-09-23: During the initial connection it is
/* If doing detach-on-fork, we don't mourn, because that will delete
breakpoints that should be available for the followed inferior. */
if (!is_fork_parent)
- target_mourn_inferior ();
+ target_mourn_inferior (inferior_ptid);
else
{
inferior_ptid = null_ptid;
return p;
}
+/* Set the target running, using the packets that use Hc
+ (c/s/C/S). */
+
+static void
+remote_resume_with_hc (struct target_ops *ops,
+ ptid_t ptid, int step, enum gdb_signal siggnal)
+{
+ struct remote_state *rs = get_remote_state ();
+ struct thread_info *thread;
+ char *buf;
+
+ rs->last_sent_signal = siggnal;
+ rs->last_sent_step = step;
+
+ /* The c/s/C/S resume packets use Hc, so set the continue
+ thread. */
+ if (ptid_equal (ptid, minus_one_ptid))
+ set_continue_thread (any_thread_ptid);
+ else
+ set_continue_thread (ptid);
+
+ ALL_NON_EXITED_THREADS (thread)
+ resume_clear_thread_private_info (thread);
+
+ buf = rs->buf;
+ if (execution_direction == EXEC_REVERSE)
+ {
+ /* We don't pass signals to the target in reverse exec mode. */
+ if (info_verbose && siggnal != GDB_SIGNAL_0)
+ warning (_(" - Can't pass signal %d to target in reverse: ignored."),
+ siggnal);
+
+ if (step && packet_support (PACKET_bs) == PACKET_DISABLE)
+ error (_("Remote reverse-step not supported."));
+ if (!step && packet_support (PACKET_bc) == PACKET_DISABLE)
+ error (_("Remote reverse-continue not supported."));
+
+ strcpy (buf, step ? "bs" : "bc");
+ }
+ else if (siggnal != GDB_SIGNAL_0)
+ {
+ buf[0] = step ? 'S' : 'C';
+ buf[1] = tohex (((int) siggnal >> 4) & 0xf);
+ buf[2] = tohex (((int) siggnal) & 0xf);
+ buf[3] = '\0';
+ }
+ else
+ strcpy (buf, step ? "s" : "c");
+
+ putpkt (buf);
+}
+
/* Resume the remote inferior by using a "vCont" packet. The thread
to be resumed is PTID; STEP and SIGGNAL indicate whether the
resumed thread should be single-stepped and/or signalled. If PTID
be stepped and/or signalled is given in the global INFERIOR_PTID.
This function returns non-zero iff it resumes the inferior.
- This function issues a strict subset of all possible vCont commands at the
- moment. */
+ This function issues a strict subset of all possible vCont commands
+ at the moment. */
static int
-remote_vcont_resume (ptid_t ptid, int step, enum gdb_signal siggnal)
+remote_resume_with_vcont (ptid_t ptid, int step, enum gdb_signal siggnal)
{
struct remote_state *rs = get_remote_state ();
char *p;
char *endp;
+ /* No reverse execution actions defined for vCont. */
+ if (execution_direction == EXEC_REVERSE)
+ return 0;
+
if (packet_support (PACKET_vCont) == PACKET_SUPPORT_UNKNOWN)
remote_vcont_probe (rs);
ptid_t ptid, int step, enum gdb_signal siggnal)
{
struct remote_state *rs = get_remote_state ();
- char *buf;
- struct thread_info *thread;
+
+ /* When connected in non-stop mode, the core resumes threads
+ individually. Resuming remote threads directly in target_resume
+ would thus result in sending one packet per thread. Instead, to
+ minimize roundtrip latency, here we just store the resume
+ request; the actual remote resumption will be done in
+ target_commit_resume / remote_commit_resume, where we'll be able
+ to do vCont action coalescing. */
+ if (target_is_non_stop_p () && execution_direction != EXEC_REVERSE)
+ {
+ struct private_thread_info *remote_thr;
+
+ if (ptid_equal (minus_one_ptid, ptid) || ptid_is_pid (ptid))
+ remote_thr = get_private_info_ptid (inferior_ptid);
+ else
+ remote_thr = get_private_info_ptid (ptid);
+ remote_thr->last_resume_step = step;
+ remote_thr->last_resume_sig = siggnal;
+ return;
+ }
/* In all-stop, we can't mark REMOTE_ASYNC_GET_PENDING_EVENTS_TOKEN
(explained in remote-notif.c:handle_notification) so
if (!target_is_non_stop_p ())
remote_notif_process (rs->notif_state, ¬if_client_stop);
- rs->last_sent_signal = siggnal;
- rs->last_sent_step = step;
-
rs->last_resume_exec_dir = execution_direction;
- /* The vCont packet doesn't need to specify threads via Hc. */
- /* No reverse support (yet) for vCont. */
- if (execution_direction != EXEC_REVERSE)
- if (remote_vcont_resume (ptid, step, siggnal))
- goto done;
-
- /* All other supported resume packets do use Hc, so set the continue
- thread. */
- if (ptid_equal (ptid, minus_one_ptid))
- set_continue_thread (any_thread_ptid);
- else
- set_continue_thread (ptid);
-
- ALL_NON_EXITED_THREADS (thread)
- resume_clear_thread_private_info (thread);
+ /* Prefer vCont, and fallback to s/c/S/C, which use Hc. */
+ if (!remote_resume_with_vcont (ptid, step, siggnal))
+ remote_resume_with_hc (ops, ptid, step, siggnal);
- buf = rs->buf;
- if (execution_direction == EXEC_REVERSE)
- {
- /* We don't pass signals to the target in reverse exec mode. */
- if (info_verbose && siggnal != GDB_SIGNAL_0)
- warning (_(" - Can't pass signal %d to target in reverse: ignored."),
- siggnal);
-
- if (step && packet_support (PACKET_bs) == PACKET_DISABLE)
- error (_("Remote reverse-step not supported."));
- if (!step && packet_support (PACKET_bc) == PACKET_DISABLE)
- error (_("Remote reverse-continue not supported."));
-
- strcpy (buf, step ? "bs" : "bc");
- }
- else if (siggnal != GDB_SIGNAL_0)
- {
- buf[0] = step ? 'S' : 'C';
- buf[1] = tohex (((int) siggnal >> 4) & 0xf);
- buf[2] = tohex (((int) siggnal) & 0xf);
- buf[3] = '\0';
- }
- else
- strcpy (buf, step ? "s" : "c");
-
- putpkt (buf);
-
- done:
/* We are about to start executing the inferior, let's register it
with the event loop. NOTE: this is the one place where all the
execution commands end up. We could alternatively do this in each
if (!target_is_non_stop_p ())
rs->waiting_for_stop_reply = 1;
}
+
+static void check_pending_events_prevent_wildcard_vcont
+ (int *may_global_wildcard_vcont);
+static int is_pending_fork_parent_thread (struct thread_info *thread);
+
+/* Private per-inferior info for target remote processes. */
+
+struct private_inferior
+{
+ /* Whether we can send a wildcard vCont for this process. */
+ int may_wildcard_vcont;
+};
+
+/* Structure used to track the construction of a vCont packet in the
+ outgoing packet buffer. This is used to send multiple vCont
+ packets if we have more actions than would fit a single packet. */
+
+struct vcont_builder
+{
+ /* Pointer to the first action. P points here if no action has been
+ appended yet. */
+ char *first_action;
+
+ /* Where the next action will be appended. */
+ char *p;
+
+ /* The end of the buffer. Must never write past this. */
+ char *endp;
+};
+
+/* Prepare the outgoing buffer for a new vCont packet. */
+
+static void
+vcont_builder_restart (struct vcont_builder *builder)
+{
+ struct remote_state *rs = get_remote_state ();
+
+ builder->p = rs->buf;
+ builder->endp = rs->buf + get_remote_packet_size ();
+ builder->p += xsnprintf (builder->p, builder->endp - builder->p, "vCont");
+ builder->first_action = builder->p;
+}
+
+/* If the vCont packet being built has any action, send it to the
+ remote end. */
+
+static void
+vcont_builder_flush (struct vcont_builder *builder)
+{
+ struct remote_state *rs;
+
+ if (builder->p == builder->first_action)
+ return;
+
+ rs = get_remote_state ();
+ putpkt (rs->buf);
+ getpkt (&rs->buf, &rs->buf_size, 0);
+ if (strcmp (rs->buf, "OK") != 0)
+ error (_("Unexpected vCont reply in non-stop mode: %s"), rs->buf);
+}
+
+/* The largest action is range-stepping, with its two addresses. This
+ is more than sufficient. If a new, bigger action is created, it'll
+ quickly trigger a failed assertion in append_resumption (and we'll
+ just bump this). */
+#define MAX_ACTION_SIZE 200
+
+/* Append a new vCont action in the outgoing packet being built. If
+ the action doesn't fit the packet along with previous actions, push
+ what we've got so far to the remote end and start over a new vCont
+ packet (with the new action). */
+
+static void
+vcont_builder_push_action (struct vcont_builder *builder,
+ ptid_t ptid, int step, enum gdb_signal siggnal)
+{
+ char buf[MAX_ACTION_SIZE + 1];
+ char *endp;
+ size_t rsize;
+
+ endp = append_resumption (buf, buf + sizeof (buf),
+ ptid, step, siggnal);
+
+ /* Check whether this new action would fit in the vCont packet along
+ with previous actions. If not, send what we've got so far and
+ start a new vCont packet. */
+ rsize = endp - buf;
+ if (rsize > builder->endp - builder->p)
+ {
+ vcont_builder_flush (builder);
+ vcont_builder_restart (builder);
+
+ /* Should now fit. */
+ gdb_assert (rsize <= builder->endp - builder->p);
+ }
+
+ memcpy (builder->p, buf, rsize);
+ builder->p += rsize;
+ *builder->p = '\0';
+}
+
+/* to_commit_resume implementation. */
+
+static void
+remote_commit_resume (struct target_ops *ops)
+{
+ struct remote_state *rs = get_remote_state ();
+ struct inferior *inf;
+ struct thread_info *tp;
+ int any_process_wildcard;
+ int may_global_wildcard_vcont;
+ struct vcont_builder vcont_builder;
+
+ /* If connected in all-stop mode, we'd send the remote resume
+ request directly from remote_resume. Likewise if
+ reverse-debugging, as there are no defined vCont actions for
+ reverse execution. */
+ if (!target_is_non_stop_p () || execution_direction == EXEC_REVERSE)
+ return;
+
+ /* Try to send wildcard actions ("vCont;c" or "vCont;c:pPID.-1")
+ instead of resuming all threads of each process individually.
+ However, if any thread of a process must remain halted, we can't
+ send wildcard resumes and must send one action per thread.
+
+ Care must be taken to not resume threads/processes the server
+ side already told us are stopped, but the core doesn't know about
+ yet, because the events are still in the vStopped notification
+ queue. For example:
+
+ #1 => vCont s:p1.1;c
+ #2 <= OK
+ #3 <= %Stopped T05 p1.1
+ #4 => vStopped
+ #5 <= T05 p1.2
+ #6 => vStopped
+ #7 <= OK
+ #8 (infrun handles the stop for p1.1 and continues stepping)
+ #9 => vCont s:p1.1;c
+
+ The last vCont above would resume thread p1.2 by mistake, because
+ the server has no idea that the event for p1.2 had not been
+ handled yet.
+
+ The server side must similarly ignore resume actions for the
+ thread that has a pending %Stopped notification (and any other
+ threads with events pending), until GDB acks the notification
+ with vStopped. Otherwise, e.g., the following case is
+ mishandled:
+
+ #1 => g (or any other packet)
+ #2 <= [registers]
+ #3 <= %Stopped T05 p1.2
+ #4 => vCont s:p1.1;c
+ #5 <= OK
+
+ Above, the server must not resume thread p1.2. GDB can't know
+ that p1.2 stopped until it acks the %Stopped notification, and
+ since from GDB's perspective all threads should be running, it
+ sends a "c" action.
+
+ Finally, special care must also be given to handling fork/vfork
+ events. A (v)fork event actually tells us that two processes
+ stopped -- the parent and the child. Until we follow the fork,
+ we must not resume the child. Therefore, if we have a pending
+ fork follow, we must not send a global wildcard resume action
+ (vCont;c). We can still send process-wide wildcards though. */
+
+ /* Start by assuming a global wildcard (vCont;c) is possible. */
+ may_global_wildcard_vcont = 1;
+
+ /* And assume every process is individually wildcard-able too. */
+ ALL_NON_EXITED_INFERIORS (inf)
+ {
+ if (inf->priv == NULL)
+ inf->priv = XNEW (struct private_inferior);
+ inf->priv->may_wildcard_vcont = 1;
+ }
+
+ /* Check for any pending events (not reported or processed yet) and
+ disable process and global wildcard resumes appropriately. */
+ check_pending_events_prevent_wildcard_vcont (&may_global_wildcard_vcont);
+
+ ALL_NON_EXITED_THREADS (tp)
+ {
+ /* If a thread of a process is not meant to be resumed, then we
+ can't wildcard that process. */
+ if (!tp->executing)
+ {
+ tp->inf->priv->may_wildcard_vcont = 0;
+
+ /* And if we can't wildcard a process, we can't wildcard
+ everything either. */
+ may_global_wildcard_vcont = 0;
+ continue;
+ }
+
+ /* If a thread is the parent of an unfollowed fork, then we
+ can't do a global wildcard, as that would resume the fork
+ child. */
+ if (is_pending_fork_parent_thread (tp))
+ may_global_wildcard_vcont = 0;
+ }
+
+ /* Now let's build the vCont packet(s). Actions must be appended
+ from narrower to wider scopes (thread -> process -> global). If
+ we end up with too many actions for a single packet vcont_builder
+ flushes the current vCont packet to the remote side and starts a
+ new one. */
+ vcont_builder_restart (&vcont_builder);
+
+ /* Threads first. */
+ ALL_NON_EXITED_THREADS (tp)
+ {
+ struct private_thread_info *remote_thr = tp->priv;
+
+ if (!tp->executing || remote_thr->vcont_resumed)
+ continue;
+
+ gdb_assert (!thread_is_in_step_over_chain (tp));
+
+ if (!remote_thr->last_resume_step
+ && remote_thr->last_resume_sig == GDB_SIGNAL_0
+ && tp->inf->priv->may_wildcard_vcont)
+ {
+ /* We'll send a wildcard resume instead. */
+ remote_thr->vcont_resumed = 1;
+ continue;
+ }
+
+ vcont_builder_push_action (&vcont_builder, tp->ptid,
+ remote_thr->last_resume_step,
+ remote_thr->last_resume_sig);
+ remote_thr->vcont_resumed = 1;
+ }
+
+ /* Now check whether we can send any process-wide wildcard. This is
+ to avoid sending a global wildcard in the case nothing is
+ supposed to be resumed. */
+ any_process_wildcard = 0;
+
+ ALL_NON_EXITED_INFERIORS (inf)
+ {
+ if (inf->priv->may_wildcard_vcont)
+ {
+ any_process_wildcard = 1;
+ break;
+ }
+ }
+
+ if (any_process_wildcard)
+ {
+ /* If all processes are wildcard-able, then send a single "c"
+ action, otherwise, send an "all (-1) threads of process"
+ continue action for each running process, if any. */
+ if (may_global_wildcard_vcont)
+ {
+ vcont_builder_push_action (&vcont_builder, minus_one_ptid,
+ 0, GDB_SIGNAL_0);
+ }
+ else
+ {
+ ALL_NON_EXITED_INFERIORS (inf)
+ {
+ if (inf->priv->may_wildcard_vcont)
+ {
+ vcont_builder_push_action (&vcont_builder,
+ pid_to_ptid (inf->pid),
+ 0, GDB_SIGNAL_0);
+ }
+ }
+ }
+ }
+
+ vcont_builder_flush (&vcont_builder);
+}
+
\f
/* Non-stop version of target_stop. Uses `vCont;t' to stop a remote
static void
remote_terminal_inferior (struct target_ops *self)
{
- /* FIXME: cagney/1999-09-27: Make calls to target_terminal_*()
- idempotent. The event-loop GDB talking to an asynchronous target
- with a synchronous command calls this function from both
- event-top.c and infrun.c/infcmd.c. Once GDB stops trying to
- transfer the terminal to the target when it shouldn't this guard
- can go away. */
- if (!remote_async_terminal_ours_p)
- return;
- remote_async_terminal_ours_p = 0;
/* NOTE: At this point we could also register our selves as the
recipient of all input. Any characters typed could then be
passed on down to the target. */
static void
remote_terminal_ours (struct target_ops *self)
{
- /* See FIXME in remote_terminal_inferior. */
- if (remote_async_terminal_ours_p)
- return;
- remote_async_terminal_ours_p = 1;
}
static void
gdb_flush (gdb_stdtarg);
}
-typedef struct cached_reg
-{
- int num;
- gdb_byte data[MAX_REGISTER_SIZE];
-} cached_reg_t;
-
DEF_VEC_O(cached_reg_t);
typedef struct stop_reply
struct target_waitstatus ws;
+ /* The architecture associated with the expedited registers. */
+ gdbarch *arch;
+
/* Expedited registers. This makes remote debugging a bit more
efficient for those targets that provide critical registers as
part of their normal status mechanism (as another roundtrip to
stop_reply_dtr (struct notif_event *event)
{
struct stop_reply *r = (struct stop_reply *) event;
+ cached_reg_t *reg;
+ int ix;
+
+ for (ix = 0;
+ VEC_iterate (cached_reg_t, r->regcache, ix, reg);
+ ix++)
+ xfree (reg->data);
VEC_free (cached_reg_t, r->regcache);
}
struct stop_reply *output;
};
-/* Determine if THREAD is a pending fork parent thread. ARG contains
+/* Determine if THREAD_PTID is a pending fork parent thread. ARG contains
the pid of the process that owns the threads we want to check, or
-1 if we want to check all threads. */
return 0;
}
+/* Return the thread's pending status used to determine whether the
+ thread is a fork parent stopped at a fork event. */
+
+static struct target_waitstatus *
+thread_pending_fork_status (struct thread_info *thread)
+{
+ if (thread->suspend.waitstatus_pending_p)
+ return &thread->suspend.waitstatus;
+ else
+ return &thread->pending_follow;
+}
+
+/* Determine if THREAD is a pending fork parent thread. */
+
+static int
+is_pending_fork_parent_thread (struct thread_info *thread)
+{
+ struct target_waitstatus *ws = thread_pending_fork_status (thread);
+ int pid = -1;
+
+ return is_pending_fork_parent (ws, pid, thread->ptid);
+}
+
/* Check whether EVENT is a fork event, and if it is, remove the
fork child from the context list passed in DATA. */
/* For any threads stopped at a fork event, remove the corresponding
fork child threads from the CONTEXT list. */
ALL_NON_EXITED_THREADS (thread)
- {
- struct target_waitstatus *ws;
-
- if (thread->suspend.waitstatus_pending_p)
- ws = &thread->suspend.waitstatus;
- else
- ws = &thread->pending_follow;
+ {
+ struct target_waitstatus *ws = thread_pending_fork_status (thread);
if (is_pending_fork_parent (ws, pid, thread->ptid))
{
remove_child_of_pending_fork, ¶m);
}
+/* Check whether EVENT would prevent a global or process wildcard
+ vCont action. */
+
+static int
+check_pending_event_prevents_wildcard_vcont_callback
+ (QUEUE (stop_reply_p) *q,
+ QUEUE_ITER (stop_reply_p) *iter,
+ stop_reply_p event,
+ void *data)
+{
+ struct inferior *inf;
+ int *may_global_wildcard_vcont = (int *) data;
+
+ if (event->ws.kind == TARGET_WAITKIND_NO_RESUMED
+ || event->ws.kind == TARGET_WAITKIND_NO_HISTORY)
+ return 1;
+
+ if (event->ws.kind == TARGET_WAITKIND_FORKED
+ || event->ws.kind == TARGET_WAITKIND_VFORKED)
+ *may_global_wildcard_vcont = 0;
+
+ inf = find_inferior_ptid (event->ptid);
+
+ /* This may be the first time we heard about this process.
+ Regardless, we must not do a global wildcard resume, otherwise
+ we'd resume this process too. */
+ *may_global_wildcard_vcont = 0;
+ if (inf != NULL)
+ inf->priv->may_wildcard_vcont = 0;
+
+ return 1;
+}
+
+/* Check whether any event pending in the vStopped queue would prevent
+ a global or process wildcard vCont action. Clear
+ *may_global_wildcard if we can't do a global wildcard (vCont;c),
+ and clear the event inferior's may_wildcard_vcont flag if we can't
+ do a process-wide wildcard resume (vCont;c:pPID.-1). */
+
+static void
+check_pending_events_prevent_wildcard_vcont (int *may_global_wildcard)
+{
+ struct notif_client *notif = ¬if_client_stop;
+
+ remote_notif_get_pending_events (notif);
+ QUEUE_iterate (stop_reply_p, stop_reply_queue,
+ check_pending_event_prevents_wildcard_vcont_callback,
+ may_global_wildcard);
+}
+
/* Remove stop replies in the queue if its pid is equal to the given
inferior's pid. */
static void
remote_parse_stop_reply (char *buf, struct stop_reply *event)
{
- struct remote_arch_state *rsa = get_remote_arch_state ();
+ remote_arch_state *rsa = NULL;
ULONGEST addr;
- char *p;
+ const char *p;
int skipregs = 0;
event->ptid = null_ptid;
p = &buf[3]; /* after Txx */
while (*p)
{
- char *p1;
+ const char *p1;
int fieldsize;
p1 = strchr (p, ':');
else
{
ULONGEST pnum;
- char *p_temp;
+ const char *p_temp;
if (skipregs)
{
reason. */
if (p_temp == p1)
{
- struct packet_reg *reg = packet_reg_from_pnum (rsa, pnum);
+ /* If we haven't parsed the event's thread yet, find
+ it now, in order to find the architecture of the
+ reported expedited registers. */
+ if (event->ptid == null_ptid)
+ {
+ const char *thr = strstr (p1 + 1, ";thread:");
+ if (thr != NULL)
+ event->ptid = read_ptid (thr + strlen (";thread:"),
+ NULL);
+ else
+ event->ptid = magic_null_ptid;
+ }
+
+ if (rsa == NULL)
+ {
+ inferior *inf = (event->ptid == null_ptid
+ ? NULL
+ : find_inferior_ptid (event->ptid));
+ /* If this is the first time we learn anything
+ about this process, skip the registers
+ included in this packet, since we don't yet
+ know which architecture to use to parse them.
+ We'll determine the architecture later when
+ we process the stop reply and retrieve the
+ target description, via
+ remote_notice_new_inferior ->
+ post_create_inferior. */
+ if (inf == NULL)
+ {
+ p = strchrnul (p1 + 1, ';');
+ p++;
+ continue;
+ }
+
+ event->arch = inf->gdbarch;
+ rsa = get_remote_arch_state (event->arch);
+ }
+
+ packet_reg *reg
+ = packet_reg_from_pnum (event->arch, rsa, pnum);
cached_reg_t cached_reg;
if (reg == NULL)
hex_string (pnum), p, buf);
cached_reg.num = reg->regnum;
+ cached_reg.data = (gdb_byte *)
+ xmalloc (register_size (event->arch, reg->regnum));
p = p1 + 1;
fieldsize = hex2bin (p, cached_reg.data,
- register_size (target_gdbarch (),
- reg->regnum));
+ register_size (event->arch, reg->regnum));
p += 2 * fieldsize;
- if (fieldsize < register_size (target_gdbarch (),
- reg->regnum))
+ if (fieldsize < register_size (event->arch, reg->regnum))
warning (_("Remote reply is too short: %s"), buf);
VEC_safe_push (cached_reg_t, event->regcache, &cached_reg);
break;
case 'w': /* Thread exited. */
{
- char *p;
+ const char *p;
ULONGEST value;
event->ws.kind = TARGET_WAITKIND_THREAD_EXITED;
case 'W': /* Target exited. */
case 'X':
{
- char *p;
+ const char *p;
int pid;
ULONGEST value;
if (stop_reply->regcache)
{
struct regcache *regcache
- = get_thread_arch_regcache (ptid, target_gdbarch ());
+ = get_thread_arch_regcache (ptid, stop_reply->arch);
cached_reg_t *reg;
int ix;
for (ix = 0;
- VEC_iterate(cached_reg_t, stop_reply->regcache, ix, reg);
+ VEC_iterate (cached_reg_t, stop_reply->regcache, ix, reg);
ix++)
+ {
regcache_raw_supply (regcache, reg->num, reg->data);
+ xfree (reg->data);
+ }
+
VEC_free (cached_reg_t, stop_reply->regcache);
}
remote_notice_new_inferior (ptid, 0);
- remote_thr = demand_private_info (ptid);
+ remote_thr = get_private_info_ptid (ptid);
remote_thr->core = stop_reply->core;
remote_thr->stop_reason = stop_reply->stop_reason;
remote_thr->watch_data_address = stop_reply->watch_data_address;
+ remote_thr->vcont_resumed = 0;
}
stop_reply_xfree (stop_reply);
{
/* Zero length reply means that we tried 'S' or 'C' and the
remote system doesn't support it. */
- target_terminal_ours_for_output ();
+ target_terminal::ours_for_output ();
printf_filtered
("Can't send signals to this remote system. %s not sent.\n",
gdb_signal_to_name (rs->last_sent_signal));
rs->last_sent_signal = GDB_SIGNAL_0;
- target_terminal_inferior ();
+ target_terminal::inferior ();
strcpy (buf, rs->last_sent_step ? "s" : "c");
putpkt (buf);
static int
fetch_register_using_p (struct regcache *regcache, struct packet_reg *reg)
{
+ struct gdbarch *gdbarch = regcache->arch ();
struct remote_state *rs = get_remote_state ();
char *buf, *p;
- char regp[MAX_REGISTER_SIZE];
+ gdb_byte *regp = (gdb_byte *) alloca (register_size (gdbarch, reg->regnum));
int i;
if (packet_support (PACKET_p) == PACKET_DISABLE)
return 0;
case PACKET_ERROR:
error (_("Could not fetch register \"%s\"; remote failure reply '%s'"),
- gdbarch_register_name (get_regcache_arch (regcache),
+ gdbarch_register_name (regcache->arch (),
reg->regnum),
buf);
}
static void
process_g_packet (struct regcache *regcache)
{
- struct gdbarch *gdbarch = get_regcache_arch (regcache);
+ struct gdbarch *gdbarch = regcache->arch ();
struct remote_state *rs = get_remote_state ();
- struct remote_arch_state *rsa = get_remote_arch_state ();
+ remote_arch_state *rsa = get_remote_arch_state (gdbarch);
int i, buf_len;
char *p;
char *regs;
/* Further sanity checks, with knowledge of the architecture. */
if (buf_len > 2 * rsa->sizeof_g_packet)
- error (_("Remote 'g' packet reply is too long: %s"), rs->buf);
+ error (_("Remote 'g' packet reply is too long (expected %ld bytes, got %d "
+ "bytes): %s"), rsa->sizeof_g_packet, buf_len / 2, rs->buf);
/* Save the size of the packet sent to us by the target. It is used
as a heuristic when determining the max size of packets that the
the 'p' packet must be used. */
if (buf_len < 2 * rsa->sizeof_g_packet)
{
- rsa->sizeof_g_packet = buf_len / 2;
+ long sizeof_g_packet = buf_len / 2;
for (i = 0; i < gdbarch_num_regs (gdbarch); i++)
{
+ long offset = rsa->regs[i].offset;
+ long reg_size = register_size (gdbarch, i);
+
if (rsa->regs[i].pnum == -1)
continue;
- if (rsa->regs[i].offset >= rsa->sizeof_g_packet)
+ if (offset >= sizeof_g_packet)
rsa->regs[i].in_g_packet = 0;
+ else if (offset + reg_size > sizeof_g_packet)
+ error (_("Truncated register %d in remote 'g' packet"), i);
else
rsa->regs[i].in_g_packet = 1;
}
+
+ /* Looks valid enough, we can assume this is the correct length
+ for a 'g' packet. It's important not to adjust
+ rsa->sizeof_g_packet if we have truncated registers otherwise
+ this "if" won't be run the next time the method is called
+ with a packet of the same size and one of the internal errors
+ below will trigger instead. */
+ rsa->sizeof_g_packet = sizeof_g_packet;
}
regs = (char *) alloca (rsa->sizeof_g_packet);
for (i = 0; i < gdbarch_num_regs (gdbarch); i++)
{
struct packet_reg *r = &rsa->regs[i];
+ long reg_size = register_size (gdbarch, i);
if (r->in_g_packet)
{
- if (r->offset * 2 >= strlen (rs->buf))
+ if ((r->offset + reg_size) * 2 > strlen (rs->buf))
/* This shouldn't happen - we adjusted in_g_packet above. */
internal_error (__FILE__, __LINE__,
_("unexpected end of 'g' packet reply"));
remote_fetch_registers (struct target_ops *ops,
struct regcache *regcache, int regnum)
{
- struct remote_arch_state *rsa = get_remote_arch_state ();
+ struct gdbarch *gdbarch = regcache->arch ();
+ remote_arch_state *rsa = get_remote_arch_state (gdbarch);
int i;
set_remote_traceframe ();
- set_general_thread (inferior_ptid);
+ set_general_thread (regcache_get_ptid (regcache));
if (regnum >= 0)
{
- struct packet_reg *reg = packet_reg_from_regnum (rsa, regnum);
+ packet_reg *reg = packet_reg_from_regnum (gdbarch, rsa, regnum);
gdb_assert (reg != NULL);
fetch_registers_using_g (regcache);
- for (i = 0; i < gdbarch_num_regs (get_regcache_arch (regcache)); i++)
+ for (i = 0; i < gdbarch_num_regs (gdbarch); i++)
if (!rsa->regs[i].in_g_packet)
if (!fetch_register_using_p (regcache, &rsa->regs[i]))
{
static void
remote_prepare_to_store (struct target_ops *self, struct regcache *regcache)
{
- struct remote_arch_state *rsa = get_remote_arch_state ();
+ remote_arch_state *rsa = get_remote_arch_state (regcache->arch ());
int i;
- gdb_byte buf[MAX_REGISTER_SIZE];
/* Make sure the entire registers array is valid. */
switch (packet_support (PACKET_P))
case PACKET_DISABLE:
case PACKET_SUPPORT_UNKNOWN:
/* Make sure all the necessary registers are cached. */
- for (i = 0; i < gdbarch_num_regs (get_regcache_arch (regcache)); i++)
+ for (i = 0; i < gdbarch_num_regs (regcache->arch ()); i++)
if (rsa->regs[i].in_g_packet)
- regcache_raw_read (regcache, rsa->regs[i].regnum, buf);
+ regcache_raw_update (regcache, rsa->regs[i].regnum);
break;
case PACKET_ENABLE:
break;
store_register_using_P (const struct regcache *regcache,
struct packet_reg *reg)
{
- struct gdbarch *gdbarch = get_regcache_arch (regcache);
+ struct gdbarch *gdbarch = regcache->arch ();
struct remote_state *rs = get_remote_state ();
/* Try storing a single register. */
char *buf = rs->buf;
- gdb_byte regp[MAX_REGISTER_SIZE];
+ gdb_byte *regp = (gdb_byte *) alloca (register_size (gdbarch, reg->regnum));
char *p;
if (packet_support (PACKET_P) == PACKET_DISABLE)
store_registers_using_G (const struct regcache *regcache)
{
struct remote_state *rs = get_remote_state ();
- struct remote_arch_state *rsa = get_remote_arch_state ();
+ remote_arch_state *rsa = get_remote_arch_state (regcache->arch ());
gdb_byte *regs;
char *p;
regs = (gdb_byte *) alloca (rsa->sizeof_g_packet);
memset (regs, 0, rsa->sizeof_g_packet);
- for (i = 0; i < gdbarch_num_regs (get_regcache_arch (regcache)); i++)
+ for (i = 0; i < gdbarch_num_regs (regcache->arch ()); i++)
{
struct packet_reg *r = &rsa->regs[i];
each byte encoded as two hex characters. */
p = rs->buf;
*p++ = 'G';
- /* remote_prepare_to_store insures that rsa->sizeof_g_packet gets
- updated. */
bin2hex (regs, p, rsa->sizeof_g_packet);
putpkt (rs->buf);
getpkt (&rs->buf, &rs->buf_size, 0);
remote_store_registers (struct target_ops *ops,
struct regcache *regcache, int regnum)
{
- struct remote_arch_state *rsa = get_remote_arch_state ();
+ struct gdbarch *gdbarch = regcache->arch ();
+ remote_arch_state *rsa = get_remote_arch_state (gdbarch);
int i;
set_remote_traceframe ();
- set_general_thread (inferior_ptid);
+ set_general_thread (regcache_get_ptid (regcache));
if (regnum >= 0)
{
- struct packet_reg *reg = packet_reg_from_regnum (rsa, regnum);
+ packet_reg *reg = packet_reg_from_regnum (gdbarch, rsa, regnum);
gdb_assert (reg != NULL);
store_registers_using_G (regcache);
- for (i = 0; i < gdbarch_num_regs (get_regcache_arch (regcache)); i++)
+ for (i = 0; i < gdbarch_num_regs (gdbarch); i++)
if (!rsa->regs[i].in_g_packet)
if (!store_register_using_P (regcache, &rsa->regs[i]))
/* See above for why we do not issue an error here. */
/* Return UNITS_WRITTEN, not TODO_UNITS, in case escape chars caused us to
send fewer units than we'd planned. */
*xfered_len_units = (ULONGEST) units_written;
- return TARGET_XFER_OK;
+ return (*xfered_len_units != 0) ? TARGET_XFER_OK : TARGET_XFER_EOF;
}
/* Write memory data directly to the remote machine.
remote_write_bytes (CORE_ADDR memaddr, const gdb_byte *myaddr, ULONGEST len,
int unit_size, ULONGEST *xfered_len)
{
- char *packet_format = 0;
+ const char *packet_format = NULL;
/* Check whether the target supports binary download. */
check_binary_download (memaddr);
decoded_bytes = hex2bin (p, myaddr, todo_units * unit_size);
/* Return what we have. Let higher layers handle partial reads. */
*xfered_len_units = (ULONGEST) (decoded_bytes / unit_size);
- return TARGET_XFER_OK;
+ return (*xfered_len_units != 0) ? TARGET_XFER_OK : TARGET_XFER_EOF;
}
/* Using the set of read-only target sections of remote, read live
if (get_traceframe_number () != -1)
{
- VEC(mem_range_s) *available;
+ std::vector<mem_range> available;
/* If we fail to get the set of available memory, then the
target does not support querying traceframe info, and so we
target implements the old QTro packet then). */
if (traceframe_available_memory (&available, memaddr, len))
{
- struct cleanup *old_chain;
-
- old_chain = make_cleanup (VEC_cleanup(mem_range_s), &available);
-
- if (VEC_empty (mem_range_s, available)
- || VEC_index (mem_range_s, available, 0)->start != memaddr)
+ if (available.empty () || available[0].start != memaddr)
{
enum target_xfer_status res;
/* Don't read into the traceframe's available
memory. */
- if (!VEC_empty (mem_range_s, available))
+ if (!available.empty ())
{
LONGEST oldlen = len;
- len = VEC_index (mem_range_s, available, 0)->start - memaddr;
+ len = available[0].start - memaddr;
gdb_assert (len <= oldlen);
}
- do_cleanups (old_chain);
-
/* This goes through the topmost target again. */
res = remote_xfer_live_readonly_partial (ops, myaddr, memaddr,
len, unit_size, xfered_len);
/* No use trying further, we know some memory starting
at MEMADDR isn't available. */
*xfered_len = len;
- return TARGET_XFER_UNAVAILABLE;
+ return (*xfered_len != 0) ?
+ TARGET_XFER_UNAVAILABLE : TARGET_XFER_EOF;
}
}
case the target implements the deprecated QTro packet to
cater for older GDBs (the target's knowledge of read-only
sections may be outdated by now). */
- len = VEC_index (mem_range_s, available, 0)->length;
-
- do_cleanups (old_chain);
+ len = available[0].length;
}
}
return packet_check_result (rs->buf);
}
-static void
-restore_remote_timeout (void *p)
-{
- int value = *(int *)p;
-
- remote_timeout = value;
-}
-
/* Flash writing can take quite some time. We'll set
effectively infinite timeout for flash operations.
In future, we'll need to decide on a better approach. */
ULONGEST address, LONGEST length)
{
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,
- &saved_remote_timeout);
-
- remote_timeout = remote_flash_timeout;
+ scoped_restore restore_timeout
+ = make_scoped_restore (&remote_timeout, remote_flash_timeout);
ret = remote_send_printf ("vFlashErase:%s,%s",
phex (address, addr_size),
default:
break;
}
-
- do_cleanups (back_to);
}
static enum target_xfer_status
ULONGEST length, ULONGEST *xfered_len,
const gdb_byte *data)
{
- int saved_remote_timeout = remote_timeout;
- enum target_xfer_status ret;
- struct cleanup *back_to = make_cleanup (restore_remote_timeout,
- &saved_remote_timeout);
-
- remote_timeout = remote_flash_timeout;
- ret = remote_write_bytes_aux ("vFlashWrite:", address, data, length, 1,
- xfered_len,'X', 0);
- do_cleanups (back_to);
-
- return ret;
+ scoped_restore restore_timeout
+ = make_scoped_restore (&remote_timeout, remote_flash_timeout);
+ return remote_write_bytes_aux ("vFlashWrite:", address, data, length, 1,
+ xfered_len,'X', 0);
}
static void
remote_flash_done (struct target_ops *ops)
{
- int saved_remote_timeout = remote_timeout;
int ret;
- struct cleanup *back_to = make_cleanup (restore_remote_timeout,
- &saved_remote_timeout);
- remote_timeout = remote_flash_timeout;
+ scoped_restore restore_timeout
+ = make_scoped_restore (&remote_timeout, remote_flash_timeout);
+
ret = remote_send_printf ("vFlashDone");
- do_cleanups (back_to);
switch (ret)
{
{
int ch;
struct remote_state *rs = get_remote_state ();
- struct cleanup *old_chain;
- old_chain = make_cleanup_override_quit_handler (remote_serial_quit_handler);
-
- rs->got_ctrlc_during_io = 0;
+ {
+ scoped_restore restore_quit
+ = make_scoped_restore (&quit_handler, remote_serial_quit_handler);
- ch = serial_readchar (rs->remote_desc, timeout);
+ rs->got_ctrlc_during_io = 0;
- if (rs->got_ctrlc_during_io)
- set_quit_flag ();
+ ch = serial_readchar (rs->remote_desc, timeout);
- do_cleanups (old_chain);
+ if (rs->got_ctrlc_during_io)
+ set_quit_flag ();
+ }
if (ch >= 0)
return ch;
remote_serial_write (const char *str, int len)
{
struct remote_state *rs = get_remote_state ();
- struct cleanup *old_chain;
- old_chain = make_cleanup_override_quit_handler (remote_serial_quit_handler);
+ scoped_restore restore_quit
+ = make_scoped_restore (&quit_handler, remote_serial_quit_handler);
rs->got_ctrlc_during_io = 0;
if (rs->got_ctrlc_during_io)
set_quit_flag ();
-
- do_cleanups (old_chain);
}
/* Send the command in *BUF to the remote machine, and read the reply
error (_("Remote failure reply: %s"), *buf);
}
-/* Return a pointer to an xmalloc'ed string representing an escaped
- version of BUF, of len N. E.g. \n is converted to \\n, \t to \\t,
- etc. The caller is responsible for releasing the returned
- memory. */
+/* Return a string representing an escaped version of BUF, of len N.
+ E.g. \n is converted to \\n, \t to \\t, etc. */
-static char *
+static std::string
escape_buffer (const char *buf, int n)
{
- struct cleanup *old_chain;
- struct ui_file *stb;
- char *str;
+ string_file stb;
- stb = mem_fileopen ();
- old_chain = make_cleanup_ui_file_delete (stb);
-
- fputstrn_unfiltered (buf, n, '\\', stb);
- str = ui_file_xstrdup (stb, NULL);
- do_cleanups (old_chain);
- return str;
+ stb.putstrn (buf, n, '\\');
+ return std::move (stb.string ());
}
/* Display a null-terminated packet on stdout, for debugging, using C
struct remote_state *rs = get_remote_state ();
int i;
unsigned char csum = 0;
- char *buf2 = (char *) xmalloc (cnt + 6);
- struct cleanup *old_chain = make_cleanup (xfree, buf2);
+ gdb::def_vector<char> data (cnt + 6);
+ char *buf2 = data.data ();
int ch;
int tcount = 0;
if (remote_debug)
{
- struct cleanup *old_chain;
- char *str;
-
*p = '\0';
- str = escape_buffer (buf2, p - buf2);
- old_chain = make_cleanup (xfree, str);
- fprintf_unfiltered (gdb_stdlog, "Sending packet: %s...", str);
+
+ int len = (int) (p - buf2);
+
+ std::string str
+ = escape_buffer (buf2, std::min (len, REMOTE_DEBUG_MAX_CHAR));
+
+ fprintf_unfiltered (gdb_stdlog, "Sending packet: %s", str.c_str ());
+
+ if (str.length () > REMOTE_DEBUG_MAX_CHAR)
+ {
+ fprintf_unfiltered (gdb_stdlog, "[%zu bytes omitted]",
+ str.length () - REMOTE_DEBUG_MAX_CHAR);
+ }
+
+ fprintf_unfiltered (gdb_stdlog, "...");
+
gdb_flush (gdb_stdlog);
- do_cleanups (old_chain);
}
remote_serial_write (buf2, p - buf2);
case '+':
if (remote_debug)
fprintf_unfiltered (gdb_stdlog, "Ack\n");
- do_cleanups (old_chain);
return 1;
case '-':
if (remote_debug)
case SERIAL_TIMEOUT:
tcount++;
if (tcount > 3)
- {
- do_cleanups (old_chain);
- return 0;
- }
+ return 0;
break; /* Retransmit buffer. */
case '$':
{
{
if (remote_debug)
{
- struct cleanup *old_chain;
- char *str;
+ std::string str = escape_buffer (rs->buf, val);
- str = escape_buffer (rs->buf, val);
- old_chain = make_cleanup (xfree, str);
fprintf_unfiltered (gdb_stdlog,
" Notification received: %s\n",
- str);
- do_cleanups (old_chain);
+ str.c_str ());
}
handle_notification (rs->notif_state, rs->buf);
/* We're in sync now, rewait for the ack. */
#endif
}
- do_cleanups (old_chain);
return 0;
}
if (remote_debug)
{
- struct cleanup *old_chain;
- char *str;
+ std::string str = escape_buffer (buf, bc);
- str = escape_buffer (buf, bc);
- old_chain = make_cleanup (xfree, str);
fprintf_unfiltered (gdb_stdlog,
"Bad checksum, sentsum=0x%x, "
"csum=0x%x, buf=%s\n",
- pktcsum, csum, str);
- do_cleanups (old_chain);
+ pktcsum, csum, str.c_str ());
}
/* Number of characters in buffer ignoring trailing
NULL. */
{
if (remote_debug)
{
- struct cleanup *old_chain;
- char *str;
+ std::string str
+ = escape_buffer (*buf,
+ std::min (val, REMOTE_DEBUG_MAX_CHAR));
+
+ fprintf_unfiltered (gdb_stdlog, "Packet received: %s",
+ str.c_str ());
+
+ if (str.length () > REMOTE_DEBUG_MAX_CHAR)
+ {
+ fprintf_unfiltered (gdb_stdlog, "[%zu bytes omitted]",
+ str.length () - REMOTE_DEBUG_MAX_CHAR);
+ }
- str = escape_buffer (*buf, val);
- old_chain = make_cleanup (xfree, str);
- fprintf_unfiltered (gdb_stdlog, "Packet received: %s\n", str);
- do_cleanups (old_chain);
+ fprintf_unfiltered (gdb_stdlog, "\n");
}
/* Skip the ack char if we're in no-ack mode. */
if (remote_debug)
{
- struct cleanup *old_chain;
- char *str;
+ std::string str = escape_buffer (*buf, val);
- str = escape_buffer (*buf, val);
- old_chain = make_cleanup (xfree, str);
fprintf_unfiltered (gdb_stdlog,
" Notification received: %s\n",
- str);
- do_cleanups (old_chain);
+ str.c_str ());
}
if (is_notif != NULL)
*is_notif = 1;
res = remote_vkill (pid, rs);
if (res == 0)
{
- target_mourn_inferior ();
+ target_mourn_inferior (inferior_ptid);
return;
}
}
not in extended mode, mourning the inferior also unpushes
remote_ops from the target stack, which closes the remote
connection. */
- target_mourn_inferior ();
+ target_mourn_inferior (inferior_ptid);
return;
}
xsnprintf (rs->buf, get_remote_packet_size (), "QDisableRandomization:%x",
val);
putpkt (rs->buf);
- reply = remote_get_noisy_reply (&target_buf, &target_buf_size);
+ reply = remote_get_noisy_reply ();
if (*reply == '\0')
error (_("Target does not support QDisableRandomization."));
if (strcmp (reply, "OK") != 0)
}
static int
-extended_remote_run (char *args)
+extended_remote_run (const std::string &args)
{
struct remote_state *rs = get_remote_state ();
int len;
len += 2 * bin2hex ((gdb_byte *) remote_exec_file, rs->buf + len,
strlen (remote_exec_file));
- gdb_assert (args != NULL);
- if (*args)
+ if (!args.empty ())
{
- struct cleanup *back_to;
int i;
- char **argv;
- argv = gdb_buildargv (args);
- back_to = make_cleanup_freeargv (argv);
+ gdb_argv argv (args.c_str ());
for (i = 0; argv[i] != NULL; i++)
{
if (strlen (argv[i]) * 2 + 1 + len >= get_remote_packet_size ())
len += 2 * bin2hex ((gdb_byte *) argv[i], rs->buf + len,
strlen (argv[i]));
}
- do_cleanups (back_to);
}
rs->buf[len++] = '\0';
}
}
+/* Helper function to send set/unset environment packets. ACTION is
+ either "set" or "unset". PACKET is either "QEnvironmentHexEncoded"
+ or "QEnvironmentUnsetVariable". VALUE is the variable to be
+ sent. */
+
+static void
+send_environment_packet (struct remote_state *rs,
+ const char *action,
+ const char *packet,
+ const char *value)
+{
+ /* Convert the environment variable to an hex string, which
+ is the best format to be transmitted over the wire. */
+ std::string encoded_value = bin2hex ((const gdb_byte *) value,
+ strlen (value));
+
+ xsnprintf (rs->buf, get_remote_packet_size (),
+ "%s:%s", packet, encoded_value.c_str ());
+
+ putpkt (rs->buf);
+ getpkt (&rs->buf, &rs->buf_size, 0);
+ if (strcmp (rs->buf, "OK") != 0)
+ warning (_("Unable to %s environment variable '%s' on remote."),
+ action, value);
+}
+
+/* Helper function to handle the QEnvironment* packets. */
+
+static void
+extended_remote_environment_support (struct remote_state *rs)
+{
+ if (packet_support (PACKET_QEnvironmentReset) != PACKET_DISABLE)
+ {
+ putpkt ("QEnvironmentReset");
+ getpkt (&rs->buf, &rs->buf_size, 0);
+ if (strcmp (rs->buf, "OK") != 0)
+ warning (_("Unable to reset environment on remote."));
+ }
+
+ gdb_environ *e = ¤t_inferior ()->environment;
+
+ if (packet_support (PACKET_QEnvironmentHexEncoded) != PACKET_DISABLE)
+ for (const std::string &el : e->user_set_env ())
+ send_environment_packet (rs, "set", "QEnvironmentHexEncoded",
+ el.c_str ());
+
+ if (packet_support (PACKET_QEnvironmentUnset) != PACKET_DISABLE)
+ for (const std::string &el : e->user_unset_env ())
+ send_environment_packet (rs, "unset", "QEnvironmentUnset", el.c_str ());
+}
+
+/* Helper function to set the current working directory for the
+ inferior in the remote target. */
+
+static void
+extended_remote_set_inferior_cwd (struct remote_state *rs)
+{
+ if (packet_support (PACKET_QSetWorkingDir) != PACKET_DISABLE)
+ {
+ const char *inferior_cwd = get_inferior_cwd ();
+
+ if (inferior_cwd != NULL)
+ {
+ std::string hexpath = bin2hex ((const gdb_byte *) inferior_cwd,
+ strlen (inferior_cwd));
+
+ xsnprintf (rs->buf, get_remote_packet_size (),
+ "QSetWorkingDir:%s", hexpath.c_str ());
+ }
+ else
+ {
+ /* An empty inferior_cwd means that the user wants us to
+ reset the remote server's inferior's cwd. */
+ xsnprintf (rs->buf, get_remote_packet_size (),
+ "QSetWorkingDir:");
+ }
+
+ putpkt (rs->buf);
+ getpkt (&rs->buf, &rs->buf_size, 0);
+ if (packet_ok (rs->buf,
+ &remote_protocol_packets[PACKET_QSetWorkingDir])
+ != PACKET_OK)
+ error (_("\
+Remote replied unexpectedly while setting the inferior's working\n\
+directory: %s"),
+ rs->buf);
+
+ }
+}
+
/* In the extended protocol we want to be able to do things like
"run" and have them basically work as expected. So we need
a special create_inferior function. We support changing the
static void
extended_remote_create_inferior (struct target_ops *ops,
- char *exec_file, char *args,
+ const char *exec_file,
+ const std::string &args,
char **env, int from_tty)
{
int run_worked;
if (extended_remote_supports_disable_randomization (ops))
extended_remote_disable_randomization (disable_randomization);
+ /* If startup-with-shell is on, we inform gdbserver to start the
+ remote inferior using a shell. */
+ if (packet_support (PACKET_QStartupWithShell) != PACKET_DISABLE)
+ {
+ xsnprintf (rs->buf, get_remote_packet_size (),
+ "QStartupWithShell:%d", startup_with_shell ? 1 : 0);
+ putpkt (rs->buf);
+ getpkt (&rs->buf, &rs->buf_size, 0);
+ if (strcmp (rs->buf, "OK") != 0)
+ error (_("\
+Remote replied unexpectedly while setting startup-with-shell: %s"),
+ rs->buf);
+ }
+
+ extended_remote_environment_support (rs);
+
+ extended_remote_set_inferior_cwd (rs);
+
/* Now restart the remote server. */
run_worked = extended_remote_run (args) != -1;
if (!run_worked)
user requested. */
if (remote_exec_file[0])
error (_("Remote target does not support \"set remote exec-file\""));
- if (args[0])
+ if (!args.empty ())
error (_("Remote target does not support \"set args\" or run <ARGS>"));
/* Fall back to "R". */
struct bp_target_info *bp_tgt, char *buf,
char *buf_end)
{
- struct agent_expr *aexpr = NULL;
- int i, ix;
-
- if (VEC_empty (agent_expr_p, bp_tgt->conditions))
+ if (bp_tgt->conditions.empty ())
return 0;
buf += strlen (buf);
xsnprintf (buf, buf_end - buf, "%s", ";");
buf++;
- /* Send conditions to the target and free the vector. */
- for (ix = 0;
- VEC_iterate (agent_expr_p, bp_tgt->conditions, ix, aexpr);
- ix++)
+ /* Send conditions to the target. */
+ for (agent_expr *aexpr : bp_tgt->conditions)
{
xsnprintf (buf, buf_end - buf, "X%x,", aexpr->len);
buf += strlen (buf);
- for (i = 0; i < aexpr->len; ++i)
+ for (int i = 0; i < aexpr->len; ++i)
buf = pack_hex_byte (buf, aexpr->buf[i]);
*buf = '\0';
}
remote_add_target_side_commands (struct gdbarch *gdbarch,
struct bp_target_info *bp_tgt, char *buf)
{
- struct agent_expr *aexpr = NULL;
- int i, ix;
-
- if (VEC_empty (agent_expr_p, bp_tgt->tcommands))
+ if (bp_tgt->tcommands.empty ())
return;
buf += strlen (buf);
/* Concatenate all the agent expressions that are commands into the
cmds parameter. */
- for (ix = 0;
- VEC_iterate (agent_expr_p, bp_tgt->tcommands, ix, aexpr);
- ix++)
+ for (agent_expr *aexpr : bp_tgt->tcommands)
{
sprintf (buf, "X%x,", aexpr->len);
buf += strlen (buf);
- for (i = 0; i < aexpr->len; ++i)
+ for (int i = 0; i < aexpr->len; ++i)
buf = pack_hex_byte (buf, aexpr->buf[i]);
*buf = '\0';
}
if (!gdbarch_has_global_breakpoints (target_gdbarch ()))
set_general_process ();
- gdbarch_remote_breakpoint_from_pc (gdbarch, &addr, &bpsize);
-
rs = get_remote_state ();
p = rs->buf;
endbuf = rs->buf + get_remote_packet_size ();
*(p++) = ',';
addr = (ULONGEST) remote_address_masked (addr);
p += hexnumstr (p, addr);
- xsnprintf (p, endbuf - p, ",%d", bpsize);
+ xsnprintf (p, endbuf - p, ",%d", bp_tgt->kind);
if (remote_supports_cond_breakpoints (ops))
remote_add_target_side_condition (gdbarch, bp_tgt, p, endbuf);
case PACKET_ERROR:
return -1;
case PACKET_OK:
- bp_tgt->placed_address = addr;
- bp_tgt->placed_size = bpsize;
return 0;
case PACKET_UNKNOWN:
break;
/* If this breakpoint has target-side commands but this stub doesn't
support Z0 packets, throw error. */
- if (!VEC_empty (agent_expr_p, bp_tgt->tcommands))
+ if (!bp_tgt->tcommands.empty ())
throw_error (NOT_SUPPORTED_ERROR, _("\
Target doesn't support breakpoints that have target side commands."));
addr = (ULONGEST) remote_address_masked (bp_tgt->placed_address);
p += hexnumstr (p, addr);
- xsnprintf (p, endbuf - p, ",%d", bp_tgt->placed_size);
+ xsnprintf (p, endbuf - p, ",%d", bp_tgt->kind);
putpkt (rs->buf);
getpkt (&rs->buf, &rs->buf_size, 0);
struct remote_state *rs;
char *p, *endbuf;
char *message;
- int bpsize;
-
- /* The length field should be set to the size of a breakpoint
- instruction, even though we aren't inserting one ourselves. */
-
- gdbarch_remote_breakpoint_from_pc (gdbarch, &addr, &bpsize);
if (packet_support (PACKET_Z1) == PACKET_DISABLE)
return -1;
addr = remote_address_masked (addr);
p += hexnumstr (p, (ULONGEST) addr);
- xsnprintf (p, endbuf - p, ",%x", bpsize);
+ xsnprintf (p, endbuf - p, ",%x", bp_tgt->kind);
if (remote_supports_cond_breakpoints (self))
remote_add_target_side_condition (gdbarch, bp_tgt, p, endbuf);
case PACKET_UNKNOWN:
return -1;
case PACKET_OK:
- bp_tgt->placed_address = addr;
- bp_tgt->placed_size = bpsize;
return 0;
}
internal_error (__FILE__, __LINE__,
addr = remote_address_masked (bp_tgt->placed_address);
p += hexnumstr (p, (ULONGEST) addr);
- xsnprintf (p, endbuf - p, ",%x", bp_tgt->placed_size);
+ xsnprintf (p, endbuf - p, ",%x", bp_tgt->kind);
putpkt (rs->buf);
getpkt (&rs->buf, &rs->buf_size, 0);
Useful for verifying the image on the target against the exec file. */
static void
-compare_sections_command (char *args, int from_tty)
+compare_sections_command (const char *args, int from_tty)
{
asection *s;
- struct cleanup *old_chain;
gdb_byte *sectdata;
const char *sectname;
bfd_size_type size;
matched = 1; /* Do this section. */
lma = s->lma;
- sectdata = (gdb_byte *) xmalloc (size);
- old_chain = make_cleanup (xfree, sectdata);
- bfd_get_section_contents (exec_bfd, s, sectdata, 0, size);
+ gdb::byte_vector sectdata (size);
+ bfd_get_section_contents (exec_bfd, s, sectdata.data (), 0, size);
- res = target_verify_memory (sectdata, lma, size);
+ res = target_verify_memory (sectdata.data (), lma, size);
if (res == -1)
error (_("target memory fault, section %s, range %s -- %s"), sectname,
printf_filtered ("MIS-MATCHED!\n");
mismatched++;
}
-
- do_cleanups (old_chain);
}
if (mismatched > 0)
warning (_("One or more sections of the target image does not match\n\
unpack_varlen_hex (rs->buf, &n);
*xfered_len = n;
- return TARGET_XFER_OK;
+ return (*xfered_len != 0) ? TARGET_XFER_OK : TARGET_XFER_EOF;
}
/* Read OBJECT_NAME/ANNEX from the remote target using a qXfer packet.
may not, since we don't know how much of it will need to be escaped;
the target is free to respond with slightly less data. We subtract
five to account for the response type and the protocol frame. */
- n = std::min (get_remote_packet_size () - 5, len);
+ n = std::min<LONGEST> (get_remote_packet_size () - 5, len);
snprintf (rs->buf, get_remote_packet_size () - 4, "qXfer:%s:read:%s:%s,%s",
object_name, annex ? annex : "",
phex_nz (offset, sizeof offset),
strcpy ((char *) readbuf, rs->buf);
*xfered_len = strlen ((char *) readbuf);
- return TARGET_XFER_OK;
+ return (*xfered_len != 0) ? TARGET_XFER_OK : TARGET_XFER_EOF;
}
/* Implementation of to_get_memory_xfer_limit. */
}
}
-static VEC(mem_region_s) *
+static std::vector<mem_region>
remote_memory_map (struct target_ops *ops)
{
- VEC(mem_region_s) *result = NULL;
- char *text = target_read_stralloc (¤t_target,
- TARGET_OBJECT_MEMORY_MAP, NULL);
+ std::vector<mem_region> result;
+ gdb::unique_xmalloc_ptr<char> text
+ = target_read_stralloc (¤t_target, TARGET_OBJECT_MEMORY_MAP, NULL);
if (text)
- {
- struct cleanup *back_to = make_cleanup (xfree, text);
-
- result = parse_memory_map (text);
- do_cleanups (back_to);
- }
+ result = parse_memory_map (text.get ());
return result;
}
static void
-packet_command (char *args, int from_tty)
+packet_command (const char *args, int from_tty)
{
struct remote_state *rs = get_remote_state ();
#define SAMPLE_THREAD 0x05060708 /* Truncated 64 bit threadid. */
static void
-threadset_test_cmd (char *cmd, int tty)
+threadset_test_cmd (const char *cmd, int tty)
{
int sample_thread = SAMPLE_THREAD;
static void
-threadalive_test (char *cmd, int tty)
+threadalive_test (const char *cmd, int tty)
{
int sample_thread = SAMPLE_THREAD;
int pid = ptid_get_pid (inferior_ptid);
}
static void
-threadlist_test_cmd (char *cmd, int tty)
+threadlist_test_cmd (const char *cmd, int tty)
{
int startflag = 1;
threadref nextthread;
}
static void
-threadinfo_test_cmd (char *cmd, int tty)
+threadinfo_test_cmd (const char *cmd, int tty)
{
int athread = SAMPLE_THREAD;
threadref thread;
}
static void
-threadlist_update_test_cmd (char *cmd, int tty)
+threadlist_update_test_cmd (const char *cmd, int tty)
{
printf_filtered ("Remote Threadlist update test\n");
remote_threadlist_iterator (thread_display_step, 0, CRAZY_MAX_THREADS);
/* Convert a thread ID to a string. Returns the string in a static
buffer. */
-static char *
+static const char *
remote_pid_to_str (struct target_ops *ops, ptid_t ptid)
{
static char buf[64];
decrease *LEFT. Otherwise raise an error. */
static void
-remote_buffer_add_string (char **buffer, int *left, char *string)
+remote_buffer_add_string (char **buffer, int *left, const char *string)
{
int len = strlen (string);
{
struct cleanup *back_to, *close_cleanup;
int retcode, fd, remote_errno, bytes, io_size;
- FILE *file;
gdb_byte *buffer;
int bytes_in_buffer;
int saw_eof;
if (!rs->remote_desc)
error (_("command can only be used with remote target"));
- file = gdb_fopen_cloexec (local_file, "rb");
+ gdb_file_up file = gdb_fopen_cloexec (local_file, "rb");
if (file == NULL)
perror_with_name (local_file);
- back_to = make_cleanup_fclose (file);
fd = remote_hostio_open (find_target_at (process_stratum), NULL,
remote_file, (FILEIO_O_WRONLY | FILEIO_O_CREAT
remote packet limit, so we'll transfer slightly fewer. */
io_size = get_remote_packet_size ();
buffer = (gdb_byte *) xmalloc (io_size);
- make_cleanup (xfree, buffer);
+ back_to = make_cleanup (xfree, buffer);
close_cleanup = make_cleanup (remote_hostio_close_cleanup, &fd);
{
bytes = fread (buffer + bytes_in_buffer, 1,
io_size - bytes_in_buffer,
- file);
+ file.get ());
if (bytes == 0)
{
- if (ferror (file))
+ if (ferror (file.get ()))
error (_("Error reading %s."), local_file);
else
{
{
struct cleanup *back_to, *close_cleanup;
int fd, remote_errno, bytes, io_size;
- FILE *file;
gdb_byte *buffer;
ULONGEST offset;
struct remote_state *rs = get_remote_state ();
if (fd == -1)
remote_hostio_error (remote_errno);
- file = gdb_fopen_cloexec (local_file, "wb");
+ gdb_file_up file = gdb_fopen_cloexec (local_file, "wb");
if (file == NULL)
perror_with_name (local_file);
- back_to = make_cleanup_fclose (file);
/* Send up to this many bytes at once. They won't all fit in the
remote packet limit, so we'll transfer slightly fewer. */
io_size = get_remote_packet_size ();
buffer = (gdb_byte *) xmalloc (io_size);
- make_cleanup (xfree, buffer);
+ back_to = make_cleanup (xfree, buffer);
close_cleanup = make_cleanup (remote_hostio_close_cleanup, &fd);
offset += bytes;
- bytes = fwrite (buffer, 1, bytes, file);
+ bytes = fwrite (buffer, 1, bytes, file.get ());
if (bytes == 0)
perror_with_name (local_file);
}
}
static void
-remote_put_command (char *args, int from_tty)
+remote_put_command (const char *args, int from_tty)
{
- struct cleanup *back_to;
- char **argv;
-
if (args == NULL)
error_no_arg (_("file to put"));
- argv = gdb_buildargv (args);
- back_to = make_cleanup_freeargv (argv);
+ gdb_argv argv (args);
if (argv[0] == NULL || argv[1] == NULL || argv[2] != NULL)
error (_("Invalid parameters to remote put"));
remote_file_put (argv[0], argv[1], from_tty);
-
- do_cleanups (back_to);
}
static void
-remote_get_command (char *args, int from_tty)
+remote_get_command (const char *args, int from_tty)
{
- struct cleanup *back_to;
- char **argv;
-
if (args == NULL)
error_no_arg (_("file to get"));
- argv = gdb_buildargv (args);
- back_to = make_cleanup_freeargv (argv);
+ gdb_argv argv (args);
if (argv[0] == NULL || argv[1] == NULL || argv[2] != NULL)
error (_("Invalid parameters to remote get"));
remote_file_get (argv[0], argv[1], from_tty);
-
- do_cleanups (back_to);
}
static void
-remote_delete_command (char *args, int from_tty)
+remote_delete_command (const char *args, int from_tty)
{
- struct cleanup *back_to;
- char **argv;
-
if (args == NULL)
error_no_arg (_("file to delete"));
- argv = gdb_buildargv (args);
- back_to = make_cleanup_freeargv (argv);
+ gdb_argv argv (args);
if (argv[0] == NULL || argv[1] != NULL)
error (_("Invalid parameters to remote delete"));
remote_file_delete (argv[0], from_tty);
-
- do_cleanups (back_to);
}
static void
-remote_command (char *args, int from_tty)
+remote_command (const char *args, int from_tty)
{
help_list (remote_cmdlist, "remote ", all_commands, gdb_stdout);
}
static void
remote_trace_init (struct target_ops *self)
{
+ struct remote_state *rs = get_remote_state ();
+
putpkt ("QTinit");
- remote_get_noisy_reply (&target_buf, &target_buf_size);
- if (strcmp (target_buf, "OK") != 0)
+ remote_get_noisy_reply ();
+ if (strcmp (rs->buf, "OK") != 0)
error (_("Target does not support this command."));
}
-static void free_actions_list (char **actions_list);
-static void free_actions_list_cleanup_wrapper (void *);
-static void
-free_actions_list_cleanup_wrapper (void *al)
-{
- free_actions_list ((char **) al);
-}
-
-static void
-free_actions_list (char **actions_list)
-{
- int ndx;
-
- if (actions_list == 0)
- return;
-
- for (ndx = 0; actions_list[ndx]; ndx++)
- xfree (actions_list[ndx]);
-
- xfree (actions_list);
-}
-
/* Recursive routine to walk through command list including loops, and
download packets for each command. */
rs->buf + strlen (rs->buf),
rs->buf_size - strlen (rs->buf));
putpkt (rs->buf);
- remote_get_noisy_reply (&target_buf, &target_buf_size);
- if (strcmp (target_buf, "OK"))
+ remote_get_noisy_reply ();
+ if (strcmp (rs->buf, "OK"))
warning (_("Target does not support source download."));
if (cmd->control_type == while_control
rs->buf + strlen (rs->buf),
rs->buf_size - strlen (rs->buf));
putpkt (rs->buf);
- remote_get_noisy_reply (&target_buf, &target_buf_size);
- if (strcmp (target_buf, "OK"))
+ remote_get_noisy_reply ();
+ if (strcmp (rs->buf, "OK"))
warning (_("Target does not support source download."));
}
}
CORE_ADDR tpaddr;
char addrbuf[40];
char buf[BUF_SIZE];
- char **tdp_actions;
- char **stepping_actions;
- int ndx;
- struct cleanup *old_chain = NULL;
- struct agent_expr *aexpr;
- struct cleanup *aexpr_chain = NULL;
+ std::vector<std::string> tdp_actions;
+ std::vector<std::string> stepping_actions;
char *pkt;
struct breakpoint *b = loc->owner;
struct tracepoint *t = (struct tracepoint *) b;
+ struct remote_state *rs = get_remote_state ();
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,
- stepping_actions);
tpaddr = loc->address;
sprintf_vma (addrbuf, tpaddr);
capabilities at definition time. */
if (remote_supports_cond_tracepoints ())
{
- aexpr = gen_eval_for_expr (tpaddr, loc->cond);
- aexpr_chain = make_cleanup_free_agent_expr (aexpr);
+ agent_expr_up aexpr = gen_eval_for_expr (tpaddr, loc->cond.get ());
xsnprintf (buf + strlen (buf), BUF_SIZE - strlen (buf), ":X%x,",
aexpr->len);
pkt = buf + strlen (buf);
- for (ndx = 0; ndx < aexpr->len; ++ndx)
+ for (int ndx = 0; ndx < aexpr->len; ++ndx)
pkt = pack_hex_byte (pkt, aexpr->buf[ndx]);
*pkt = '\0';
- do_cleanups (aexpr_chain);
}
else
warning (_("Target does not support conditional tracepoints, "
if (b->commands || *default_collect)
strcat (buf, "-");
putpkt (buf);
- remote_get_noisy_reply (&target_buf, &target_buf_size);
- if (strcmp (target_buf, "OK"))
+ remote_get_noisy_reply ();
+ if (strcmp (rs->buf, "OK"))
error (_("Target does not support tracepoints."));
/* do_single_steps (t); */
- if (tdp_actions)
- {
- for (ndx = 0; tdp_actions[ndx]; ndx++)
- {
- QUIT; /* Allow user to bail out with ^C. */
- xsnprintf (buf, BUF_SIZE, "QTDP:-%x:%s:%s%c",
- b->number, addrbuf, /* address */
- tdp_actions[ndx],
- ((tdp_actions[ndx + 1] || stepping_actions)
- ? '-' : 0));
- putpkt (buf);
- remote_get_noisy_reply (&target_buf,
- &target_buf_size);
- if (strcmp (target_buf, "OK"))
- error (_("Error on target while setting tracepoints."));
- }
- }
- if (stepping_actions)
+ for (auto action_it = tdp_actions.begin ();
+ action_it != tdp_actions.end (); action_it++)
{
- for (ndx = 0; stepping_actions[ndx]; ndx++)
- {
- QUIT; /* Allow user to bail out with ^C. */
- xsnprintf (buf, BUF_SIZE, "QTDP:-%x:%s:%s%s%s",
- b->number, addrbuf, /* address */
- ((ndx == 0) ? "S" : ""),
- stepping_actions[ndx],
- (stepping_actions[ndx + 1] ? "-" : ""));
- putpkt (buf);
- remote_get_noisy_reply (&target_buf,
- &target_buf_size);
- if (strcmp (target_buf, "OK"))
- error (_("Error on target while setting tracepoints."));
- }
+ QUIT; /* Allow user to bail out with ^C. */
+
+ bool has_more = (action_it != tdp_actions.end ()
+ || !stepping_actions.empty ());
+
+ xsnprintf (buf, BUF_SIZE, "QTDP:-%x:%s:%s%c",
+ b->number, addrbuf, /* address */
+ action_it->c_str (),
+ has_more ? '-' : 0);
+ putpkt (buf);
+ remote_get_noisy_reply ();
+ if (strcmp (rs->buf, "OK"))
+ error (_("Error on target while setting tracepoints."));
}
+ for (auto action_it = stepping_actions.begin ();
+ action_it != stepping_actions.end (); action_it++)
+ {
+ QUIT; /* Allow user to bail out with ^C. */
+
+ bool is_first = action_it == stepping_actions.begin ();
+ bool has_more = action_it != stepping_actions.end ();
+
+ xsnprintf (buf, BUF_SIZE, "QTDP:-%x:%s:%s%s%s",
+ b->number, addrbuf, /* address */
+ is_first ? "S" : "",
+ action_it->c_str (),
+ has_more ? "-" : "");
+ putpkt (buf);
+ remote_get_noisy_reply ();
+ if (strcmp (rs->buf, "OK"))
+ error (_("Error on target while setting tracepoints."));
+ }
+
if (packet_support (PACKET_TracepointSource) == PACKET_ENABLE)
{
if (b->location != NULL)
{
strcpy (buf, "QTDPsrc:");
encode_source_string (b->number, loc->address, "at",
- event_location_to_string (b->location),
+ event_location_to_string (b->location.get ()),
buf + strlen (buf), 2048 - strlen (buf));
putpkt (buf);
- remote_get_noisy_reply (&target_buf, &target_buf_size);
- if (strcmp (target_buf, "OK"))
+ remote_get_noisy_reply ();
+ if (strcmp (rs->buf, "OK"))
warning (_("Target does not support source download."));
}
if (b->cond_string)
"cond", b->cond_string, buf + strlen (buf),
2048 - strlen (buf));
putpkt (buf);
- remote_get_noisy_reply (&target_buf, &target_buf_size);
- if (strcmp (target_buf, "OK"))
+ remote_get_noisy_reply ();
+ if (strcmp (rs->buf, "OK"))
warning (_("Target does not support source download."));
}
remote_download_command_source (b->number, loc->address,
breakpoint_commands (b));
}
-
- do_cleanups (old_chain);
}
static int
p += 2 * bin2hex ((gdb_byte *) (tsv->name), p, strlen (tsv->name));
*p++ = '\0';
putpkt (rs->buf);
- remote_get_noisy_reply (&target_buf, &target_buf_size);
- if (*target_buf == '\0')
+ remote_get_noisy_reply ();
+ if (*rs->buf == '\0')
error (_("Target does not support this command."));
- if (strcmp (target_buf, "OK") != 0)
+ if (strcmp (rs->buf, "OK") != 0)
error (_("Error on target while downloading trace state variable."));
}
xsnprintf (rs->buf, get_remote_packet_size (), "QTEnable:%x:%s",
location->owner->number, addr_buf);
putpkt (rs->buf);
- remote_get_noisy_reply (&rs->buf, &rs->buf_size);
+ remote_get_noisy_reply ();
if (*rs->buf == '\0')
error (_("Target does not support enabling tracepoints while a trace run is ongoing."));
if (strcmp (rs->buf, "OK") != 0)
xsnprintf (rs->buf, get_remote_packet_size (), "QTDisable:%x:%s",
location->owner->number, addr_buf);
putpkt (rs->buf);
- remote_get_noisy_reply (&rs->buf, &rs->buf_size);
+ remote_get_noisy_reply ();
if (*rs->buf == '\0')
error (_("Target does not support disabling tracepoints while a trace run is ongoing."));
if (strcmp (rs->buf, "OK") != 0)
if (!exec_bfd)
return; /* No information to give. */
- strcpy (target_buf, "QTro");
- offset = strlen (target_buf);
+ struct remote_state *rs = get_remote_state ();
+
+ strcpy (rs->buf, "QTro");
+ offset = strlen (rs->buf);
for (s = exec_bfd->sections; s; s = s->next)
{
char tmp1[40], tmp2[40];
sprintf_vma (tmp1, vma);
sprintf_vma (tmp2, vma + size);
sec_length = 1 + strlen (tmp1) + 1 + strlen (tmp2);
- if (offset + sec_length + 1 > target_buf_size)
+ if (offset + sec_length + 1 > rs->buf_size)
{
if (packet_support (PACKET_qXfer_traceframe_info) != PACKET_ENABLE)
warning (_("\
Too many sections for read-only sections definition packet."));
break;
}
- xsnprintf (target_buf + offset, target_buf_size - offset, ":%s,%s",
+ xsnprintf (rs->buf + offset, rs->buf_size - offset, ":%s,%s",
tmp1, tmp2);
offset += sec_length;
}
if (anysecs)
{
- putpkt (target_buf);
- getpkt (&target_buf, &target_buf_size, 0);
+ putpkt (rs->buf);
+ getpkt (&rs->buf, &rs->buf_size, 0);
}
}
static void
remote_trace_start (struct target_ops *self)
{
+ struct remote_state *rs = get_remote_state ();
+
putpkt ("QTStart");
- remote_get_noisy_reply (&target_buf, &target_buf_size);
- if (*target_buf == '\0')
+ remote_get_noisy_reply ();
+ if (*rs->buf == '\0')
error (_("Target does not support this command."));
- if (strcmp (target_buf, "OK") != 0)
- error (_("Bogus reply from target: %s"), target_buf);
+ if (strcmp (rs->buf, "OK") != 0)
+ error (_("Bogus reply from target: %s"), rs->buf);
}
static int
/* FIXME we need to get register block size some other way. */
extern int trace_regblock_size;
enum packet_result result;
+ struct remote_state *rs = get_remote_state ();
if (packet_support (PACKET_qTStatus) == PACKET_DISABLE)
return -1;
- trace_regblock_size = get_remote_arch_state ()->sizeof_g_packet;
+ trace_regblock_size
+ = get_remote_arch_state (target_gdbarch ())->sizeof_g_packet;
putpkt ("qTStatus");
TRY
{
- p = remote_get_noisy_reply (&target_buf, &target_buf_size);
+ p = remote_get_noisy_reply ();
}
CATCH (ex, RETURN_MASK_ERROR)
{
ts->filename = NULL;
if (*p++ != 'T')
- error (_("Bogus trace status reply from target: %s"), target_buf);
+ error (_("Bogus trace status reply from target: %s"), rs->buf);
/* Function 'parse_trace_status' sets default value of each field of
'ts' at first, so we don't have to do it here. */
if (tp)
{
- tp->base.hit_count = 0;
+ tp->hit_count = 0;
tp->traceframe_usage = 0;
- for (loc = tp->base.loc; loc; loc = loc->next)
+ for (loc = tp->loc; loc; loc = loc->next)
{
/* If the tracepoint was never downloaded, don't go asking for
any status. */
xsnprintf (rs->buf, size, "qTP:%x:%s", tp->number_on_target,
phex_nz (loc->address, 0));
putpkt (rs->buf);
- reply = remote_get_noisy_reply (&target_buf, &target_buf_size);
+ reply = remote_get_noisy_reply ();
if (reply && *reply)
{
if (*reply == 'V')
xsnprintf (rs->buf, size, "qTP:%x:%s", utp->number,
phex_nz (utp->addr, 0));
putpkt (rs->buf);
- reply = remote_get_noisy_reply (&target_buf, &target_buf_size);
+ reply = remote_get_noisy_reply ();
if (reply && *reply)
{
if (*reply == 'V')
static void
remote_trace_stop (struct target_ops *self)
{
+ struct remote_state *rs = get_remote_state ();
+
putpkt ("QTStop");
- remote_get_noisy_reply (&target_buf, &target_buf_size);
- if (*target_buf == '\0')
+ remote_get_noisy_reply ();
+ if (*rs->buf == '\0')
error (_("Target does not support this command."));
- if (strcmp (target_buf, "OK") != 0)
- error (_("Bogus reply from target: %s"), target_buf);
+ if (strcmp (rs->buf, "OK") != 0)
+ error (_("Bogus reply from target: %s"), rs->buf);
}
static int
}
putpkt (rs->buf);
- reply = remote_get_noisy_reply (&(rs->buf), &rs->buf_size);
+ reply = remote_get_noisy_reply ();
if (*reply == '\0')
error (_("Target does not support this command."));
xsnprintf (rs->buf, get_remote_packet_size (), "qTV:%x", tsvnum);
putpkt (rs->buf);
- reply = remote_get_noisy_reply (&target_buf, &target_buf_size);
+ reply = remote_get_noisy_reply ();
if (reply && *reply)
{
if (*reply == 'V')
p += 2 * bin2hex ((gdb_byte *) filename, p, strlen (filename));
*p++ = '\0';
putpkt (rs->buf);
- reply = remote_get_noisy_reply (&target_buf, &target_buf_size);
+ reply = remote_get_noisy_reply ();
if (*reply == '\0')
error (_("Target does not support this command."));
if (strcmp (reply, "OK") != 0)
*p++ = '\0';
putpkt (rs->buf);
- reply = remote_get_noisy_reply (&target_buf, &target_buf_size);
+ reply = remote_get_noisy_reply ();
if (reply && *reply)
{
/* 'l' by itself means we're at the end of the buffer and
what was returned in the packet; if the target is
unexpectedly generous and gives us a bigger reply than we
asked for, we don't want to crash. */
- rslt = hex2bin (target_buf, buf, len);
+ rslt = hex2bin (reply, buf, len);
return rslt;
}
xsnprintf (rs->buf, get_remote_packet_size (), "QTDisconnected:%x", val);
putpkt (rs->buf);
- reply = remote_get_noisy_reply (&target_buf, &target_buf_size);
+ reply = remote_get_noisy_reply ();
if (*reply == '\0')
error (_("Target does not support this command."));
if (strcmp (reply, "OK") != 0)
xsnprintf (rs->buf, get_remote_packet_size (), "QTBuffer:circular:%x", val);
putpkt (rs->buf);
- reply = remote_get_noisy_reply (&target_buf, &target_buf_size);
+ reply = remote_get_noisy_reply ();
if (*reply == '\0')
error (_("Target does not support this command."));
if (strcmp (reply, "OK") != 0)
error (_("Bogus reply from target: %s"), reply);
}
-static struct traceframe_info *
+static traceframe_info_up
remote_traceframe_info (struct target_ops *self)
{
- char *text;
-
- text = target_read_stralloc (¤t_target,
- TARGET_OBJECT_TRACEFRAME_INFO, NULL);
+ gdb::unique_xmalloc_ptr<char> text
+ = target_read_stralloc (¤t_target, TARGET_OBJECT_TRACEFRAME_INFO,
+ NULL);
if (text != NULL)
- {
- struct traceframe_info *info;
- struct cleanup *back_to = make_cleanup (xfree, text);
-
- info = parse_traceframe_info (text);
- do_cleanups (back_to);
- return info;
- }
+ return parse_traceframe_info (text.get ());
return NULL;
}
xsnprintf (rs->buf, get_remote_packet_size (), "qTMinFTPILen");
putpkt (rs->buf);
- reply = remote_get_noisy_reply (&target_buf, &target_buf_size);
+ reply = remote_get_noisy_reply ();
if (*reply == '\0')
return -1;
else
buf += hexnumstr (buf, (ULONGEST) val);
putpkt (rs->buf);
- remote_get_noisy_reply (&rs->buf, &rs->buf_size);
+ remote_get_noisy_reply ();
result = packet_ok (rs->buf,
&remote_protocol_packets[PACKET_QTBuffer_size]);
*buf = '\0';
putpkt (rs->buf);
- reply = remote_get_noisy_reply (&target_buf, &target_buf_size);
+ reply = remote_get_noisy_reply ();
if (*reply == '\0')
return 0;
static void
btrace_read_config (struct btrace_config *conf)
{
- char *xml;
-
- xml = target_read_stralloc (¤t_target,
- TARGET_OBJECT_BTRACE_CONF, "");
+ gdb::unique_xmalloc_ptr<char> xml
+ = target_read_stralloc (¤t_target, TARGET_OBJECT_BTRACE_CONF, "");
if (xml != NULL)
- {
- struct cleanup *cleanup;
-
- cleanup = make_cleanup (xfree, xml);
- parse_xml_btrace_conf (conf, xml);
- do_cleanups (cleanup);
- }
+ parse_xml_btrace_conf (conf, xml.get ());
}
/* Maybe reopen target btrace. */
remote_btrace_maybe_reopen (void)
{
struct remote_state *rs = get_remote_state ();
- struct cleanup *cleanup;
struct thread_info *tp;
int btrace_target_pushed = 0;
int warned = 0;
- cleanup = make_cleanup_restore_current_thread ();
+ scoped_restore_current_thread restore_thread;
+
ALL_NON_EXITED_THREADS (tp)
{
set_general_thread (tp->ptid);
tp->btrace.target->ptid = tp->ptid;
tp->btrace.target->conf = rs->btrace_config;
}
- do_cleanups (cleanup);
}
/* Enable branch tracing. */
enum btrace_read_type type)
{
struct packet_config *packet = &remote_protocol_packets[PACKET_qXfer_btrace];
- struct cleanup *cleanup;
const char *annex;
- char *xml;
if (packet_config_support (packet) != PACKET_ENABLE)
error (_("Target does not support branch tracing."));
(unsigned int) type);
}
- xml = target_read_stralloc (¤t_target,
- TARGET_OBJECT_BTRACE, annex);
+ gdb::unique_xmalloc_ptr<char> xml
+ = target_read_stralloc (¤t_target, TARGET_OBJECT_BTRACE, annex);
if (xml == NULL)
return BTRACE_ERR_UNKNOWN;
- cleanup = make_cleanup (xfree, xml);
- parse_xml_btrace (btrace, xml);
- do_cleanups (cleanup);
+ parse_xml_btrace (btrace, xml.get ());
return BTRACE_ERR_NONE;
}
static char *
remote_pid_to_exec_file (struct target_ops *self, int pid)
{
- static char *filename = NULL;
+ static gdb::unique_xmalloc_ptr<char> filename;
struct inferior *inf;
char *annex = NULL;
if (packet_support (PACKET_qXfer_exec_file) != PACKET_ENABLE)
return NULL;
- if (filename != NULL)
- xfree (filename);
-
inf = find_inferior_pid (pid);
if (inf == NULL)
internal_error (__FILE__, __LINE__,
filename = target_read_stralloc (¤t_target,
TARGET_OBJECT_EXEC_FILE, annex);
- return filename;
+ return filename.get ();
}
/* Implement the to_can_do_single_step target_ops method. */
return rs->last_resume_exec_dir;
}
+/* Return pointer to the thread_info struct which corresponds to
+ THREAD_HANDLE (having length HANDLE_LEN). */
+
+static struct thread_info *
+remote_thread_handle_to_thread_info (struct target_ops *ops,
+ const gdb_byte *thread_handle,
+ int handle_len,
+ struct inferior *inf)
+{
+ struct thread_info *tp;
+
+ ALL_NON_EXITED_THREADS (tp)
+ {
+ struct private_thread_info *priv = get_private_info_thread (tp);
+
+ if (tp->inf == inf && priv != NULL)
+ {
+ if (handle_len != priv->thread_handle->size ())
+ error (_("Thread handle size mismatch: %d vs %zu (from remote)"),
+ handle_len, priv->thread_handle->size ());
+ if (memcmp (thread_handle, priv->thread_handle->data (),
+ handle_len) == 0)
+ return tp;
+ }
+ }
+
+ return NULL;
+}
+
static void
init_remote_ops (void)
{
remote_ops.to_detach = remote_detach;
remote_ops.to_disconnect = remote_disconnect;
remote_ops.to_resume = remote_resume;
+ remote_ops.to_commit_resume = remote_commit_resume;
remote_ops.to_wait = remote_wait;
remote_ops.to_fetch_registers = remote_fetch_registers;
remote_ops.to_store_registers = remote_store_registers;
remote_ops.to_insert_exec_catchpoint = remote_insert_exec_catchpoint;
remote_ops.to_remove_exec_catchpoint = remote_remove_exec_catchpoint;
remote_ops.to_execution_direction = remote_execution_direction;
+ remote_ops.to_thread_handle_to_thread_info =
+ remote_thread_handle_to_thread_info;
}
/* Set up the extended remote vector by making a copy of the standard
{
struct remote_state *rs = get_remote_state ();
+ /* We don't go async if the user has explicitly prevented it with the
+ "maint set target-async" command. */
if (!target_async_permitted)
- /* We only enable async when the user specifically asks for it. */
return 0;
/* We're async whenever the serial device is. */
}
static void
-set_remote_cmd (char *args, int from_tty)
+set_remote_cmd (const char *args, int from_tty)
{
help_list (remote_set_cmdlist, "set remote ", all_commands, gdb_stdout);
}
static void
-show_remote_cmd (char *args, int from_tty)
+show_remote_cmd (const char *args, int from_tty)
{
/* We can't just use cmd_show_list here, because we want to skip
the redundant "show remote Z-packet" and the legacy aliases. */
- struct cleanup *showlist_chain;
struct cmd_list_element *list = remote_show_cmdlist;
struct ui_out *uiout = current_uiout;
- showlist_chain = make_cleanup_ui_out_tuple_begin_end (uiout, "showlist");
+ ui_out_emit_tuple tuple_emitter (uiout, "showlist");
for (; list != NULL; list = list->next)
if (strcmp (list->name, "Z-packet") == 0)
continue;
continue;
else
{
- struct cleanup *option_chain
- = make_cleanup_ui_out_tuple_begin_end (uiout, "option");
+ ui_out_emit_tuple option_emitter (uiout, "option");
- ui_out_field_string (uiout, "name", list->name);
- ui_out_text (uiout, ": ");
+ uiout->field_string ("name", list->name);
+ uiout->text (": ");
if (list->type == show_cmd)
do_show_command (NULL, from_tty, list);
else
cmd_func (list, NULL, from_tty);
- /* Close the tuple. */
- do_cleanups (option_chain);
}
-
- /* Close the tuple. */
- do_cleanups (showlist_chain);
}
/* The "set/show range-stepping" set hook. */
static void
-set_range_stepping (char *ignore_args, int from_tty,
+set_range_stepping (const char *ignore_args, int from_tty,
struct cmd_list_element *c)
{
struct remote_state *rs = get_remote_state ();
add_packet_config_cmd (&remote_protocol_packets[PACKET_QProgramSignals],
"QProgramSignals", "program-signals", 0);
+ add_packet_config_cmd (&remote_protocol_packets[PACKET_QSetWorkingDir],
+ "QSetWorkingDir", "set-working-dir", 0);
+
+ add_packet_config_cmd (&remote_protocol_packets[PACKET_QStartupWithShell],
+ "QStartupWithShell", "startup-with-shell", 0);
+
+ add_packet_config_cmd (&remote_protocol_packets
+ [PACKET_QEnvironmentHexEncoded],
+ "QEnvironmentHexEncoded", "environment-hex-encoded",
+ 0);
+
+ add_packet_config_cmd (&remote_protocol_packets[PACKET_QEnvironmentReset],
+ "QEnvironmentReset", "environment-reset",
+ 0);
+
+ add_packet_config_cmd (&remote_protocol_packets[PACKET_QEnvironmentUnset],
+ "QEnvironmentUnset", "environment-unset",
+ 0);
+
add_packet_config_cmd (&remote_protocol_packets[PACKET_qSymbol],
"qSymbol", "symbol-lookup", 0);
magic_null_ptid = ptid_build (42000, -1, 1);
not_sent_ptid = ptid_build (42000, -2, 1);
any_thread_ptid = ptid_build (42000, 0, 1);
-
- target_buf_size = 2048;
- target_buf = (char *) xmalloc (target_buf_size);
}
-