/* Remote target communications for serial-line targets in custom GDB protocol
- Copyright (C) 1988-2014 Free Software Foundation, Inc.
+ Copyright (C) 1988-2015 Free Software Foundation, Inc.
This file is part of GDB.
#include "infrun.h"
#include "bfd.h"
#include "symfile.h"
-#include "exceptions.h"
#include "target.h"
/*#include "terminal.h" */
#include "gdbcmd.h"
static void remote_close (struct target_ops *self);
+struct remote_state;
+
+static int remote_vkill (int pid, struct remote_state *rs);
+
static void remote_mourn (struct target_ops *ops);
static void extended_remote_restart (void);
static void extended_remote_mourn (struct target_ops *);
-static void remote_mourn_1 (struct target_ops *);
-
static void remote_send (char **buf, long *sizeof_buf_p);
static int readchar (int timeout);
static int remote_is_async_p (struct target_ops *);
-static void remote_async (struct target_ops *ops,
- void (*callback) (enum inferior_event_type event_type,
- void *context),
- void *context);
+static void remote_async (struct target_ops *ops, int enable);
static void sync_remote_interrupt_twice (int signo);
static ptid_t remote_current_thread (ptid_t oldptid);
-static void remote_find_new_threads (void);
-
static int putpkt_binary (const char *buf, int cnt);
static void check_binary_download (CORE_ADDR addr);
static void remote_set_permissions (struct target_ops *self);
-struct remote_state;
static int remote_get_trace_status (struct target_ops *self,
struct trace_status *ts);
static void discard_pending_stop_replies_in_queue (struct remote_state *);
static int peek_stop_reply (ptid_t ptid);
+struct threads_listing_context;
+static void remove_new_fork_children (struct threads_listing_context *);
+
static void remote_async_inferior_event_handler (gdb_client_data);
static void remote_terminal_ours (struct target_ops *self);
static int remote_can_run_breakpoint_commands (struct target_ops *self);
+static void remote_btrace_reset (void);
+
/* For "remote". */
static struct cmd_list_element *remote_cmdlist;
int use_threadinfo_query;
int use_threadextra_query;
- void (*async_client_callback) (enum inferior_event_type event_type,
- void *context);
- void *async_client_context;
-
/* This is set to the data address of the access causing the target
to stop for a watchpoint. */
CORE_ADDR remote_watch_data_address;
- /* This is non-zero if target stopped for a watchpoint. */
- int remote_stopped_by_watchpoint_p;
+ /* Whether the target stopped for a breakpoint/watchpoint. */
+ enum target_stop_reason stop_reason;
threadref echo_nextthread;
threadref nextthread;
/* The state of remote notification. */
struct remote_notif_state *notif_state;
+
+ /* The branch trace configuration. */
+ struct btrace_config btrace_config;
+
+ /* The argument to the last "vFile:setfs:" packet we sent, used
+ to avoid sending repeated unnecessary "vFile:setfs:" packets.
+ Initialized to -1 to indicate that no "vFile:setfs:" packet
+ has yet been sent. */
+ int fs_pid;
};
/* Private data that we'll store in (struct thread_info)->private. */
result->buf = xmalloc (result->buf_size);
result->remote_traceframe_number = -1;
result->last_sent_signal = GDB_SIGNAL_0;
+ result->fs_pid = -1;
return result;
}
buf = *buf_p;
if (buf[0] == 'E')
trace_error (buf);
- else if (strncmp (buf, "qRelocInsn:", strlen ("qRelocInsn:")) == 0)
+ else if (startswith (buf, "qRelocInsn:"))
{
ULONGEST ul;
CORE_ADDR from, to, org_to;
char *p, *pp;
int adjusted_size = 0;
- volatile struct gdb_exception ex;
+ int relocated = 0;
p = buf + strlen ("qRelocInsn:");
pp = unpack_varlen_hex (p, &ul);
org_to = to;
- TRY_CATCH (ex, RETURN_MASK_ALL)
+ TRY
{
gdbarch_relocate_instruction (target_gdbarch (), &to, from);
+ relocated = 1;
+ }
+ CATCH (ex, RETURN_MASK_ALL)
+ {
+ if (ex.error == MEMORY_ERROR)
+ {
+ /* Propagate memory errors silently back to the
+ target. The stub may have limited the range of
+ addresses we can write to, for example. */
+ }
+ else
+ {
+ /* Something unexpectedly bad happened. Be verbose
+ so we can tell what, and propagate the error back
+ to the stub, so it doesn't get stuck waiting for
+ a response. */
+ exception_fprintf (gdb_stderr, ex,
+ _("warning: relocating instruction: "));
+ }
+ putpkt ("E01");
}
- if (ex.reason >= 0)
+ END_CATCH
+
+ if (relocated)
{
adjusted_size = to - org_to;
xsnprintf (buf, *sizeof_buf, "qRelocInsn:%x", adjusted_size);
putpkt (buf);
}
- else if (ex.reason < 0 && ex.error == MEMORY_ERROR)
- {
- /* Propagate memory errors silently back to the target.
- The stub may have limited the range of addresses we
- can write to, for example. */
- putpkt ("E01");
- }
- else
- {
- /* Something unexpectedly bad happened. Be verbose so
- we can tell what, and propagate the error back to the
- stub, so it doesn't get stuck waiting for a
- response. */
- exception_fprintf (gdb_stderr, ex,
- _("warning: relocating instruction: "));
- putpkt ("E01");
- }
}
else if (buf[0] == 'O' && buf[1] != 'K')
remote_console_output (buf + 1); /* 'O' message from stub */
PACKET_Z2,
PACKET_Z3,
PACKET_Z4,
+ PACKET_vFile_setfs,
PACKET_vFile_open,
PACKET_vFile_pread,
PACKET_vFile_pwrite,
PACKET_vFile_close,
PACKET_vFile_unlink,
PACKET_vFile_readlink,
+ PACKET_vFile_fstat,
PACKET_qXfer_auxv,
PACKET_qXfer_features,
+ PACKET_qXfer_exec_file,
PACKET_qXfer_libraries,
PACKET_qXfer_libraries_svr4,
PACKET_qXfer_memory_map,
/* Support for qXfer:libraries-svr4:read with a non-empty annex. */
PACKET_augmented_libraries_svr4_read_feature,
+ /* Support for the qXfer:btrace-conf:read packet. */
+ PACKET_qXfer_btrace_conf,
+
+ /* Support for the Qbtrace-conf:bts:size packet. */
+ PACKET_Qbtrace_conf_bts_size,
+
+ /* Support for swbreak+ feature. */
+ PACKET_swbreak_feature,
+
+ /* Support for hwbreak+ feature. */
+ PACKET_hwbreak_feature,
+
+ /* Support for fork events. */
+ PACKET_fork_event_feature,
+
+ /* Support for vfork events. */
+ PACKET_vfork_event_feature,
+
PACKET_MAX
};
static struct packet_config remote_protocol_packets[PACKET_MAX];
+/* Returns the packet's corresponding "set remote foo-packet" command
+ state. See struct packet_config for more details. */
+
+static enum auto_boolean
+packet_set_cmd_state (int packet)
+{
+ return remote_protocol_packets[packet].detect;
+}
+
/* Returns whether a given packet or feature is supported. This takes
into account the state of the corresponding "set remote foo-packet"
command, which may be used to bypass auto-detection. */
return packet_support (PACKET_multiprocess_feature) == PACKET_ENABLE;
}
+/* Returns true if fork events are supported. */
+
+static int
+remote_fork_event_p (struct remote_state *rs)
+{
+ return packet_support (PACKET_fork_event_feature) == PACKET_ENABLE;
+}
+
+/* Returns true if vfork events are supported. */
+
+static int
+remote_vfork_event_p (struct remote_state *rs)
+{
+ return packet_support (PACKET_vfork_event_feature) == PACKET_ENABLE;
+}
+
+/* Insert fork catchpoint target routine. If fork events are enabled
+ then return success, nothing more to do. */
+
+static int
+remote_insert_fork_catchpoint (struct target_ops *ops, int pid)
+{
+ struct remote_state *rs = get_remote_state ();
+
+ return !remote_fork_event_p (rs);
+}
+
+/* Remove fork catchpoint target routine. Nothing to do, just
+ return success. */
+
+static int
+remote_remove_fork_catchpoint (struct target_ops *ops, int pid)
+{
+ return 0;
+}
+
+/* Insert vfork catchpoint target routine. If vfork events are enabled
+ then return success, nothing more to do. */
+
+static int
+remote_insert_vfork_catchpoint (struct target_ops *ops, int pid)
+{
+ struct remote_state *rs = get_remote_state ();
+
+ return !remote_vfork_event_p (rs);
+}
+
+/* Remove vfork catchpoint target routine. Nothing to do, just
+ return success. */
+
+static int
+remote_remove_vfork_catchpoint (struct target_ops *ops, int pid)
+{
+ return 0;
+}
+
/* Tokens for use by the asynchronous signal handlers for SIGINT. */
static struct async_signal_handler *async_sigint_remote_twice_token;
static struct async_signal_handler *async_sigint_remote_token;
inferior. If ATTACHED is 1, then we had just attached to this
inferior. If it is 0, then we just created this inferior. If it
is -1, then try querying the remote stub to find out if it had
- attached to the inferior or not. */
+ attached to the inferior or not. If TRY_OPEN_EXEC is true then
+ attempt to open this inferior's executable as the main executable
+ if no main executable is open already. */
static struct inferior *
-remote_add_inferior (int fake_pid_p, int pid, int attached)
+remote_add_inferior (int fake_pid_p, int pid, int attached,
+ int try_open_exec)
{
struct inferior *inf;
inf->attach_flag = attached;
inf->fake_pid_p = fake_pid_p;
+ /* 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);
+
return inf;
}
int fake_pid_p = !remote_multi_process_p (rs);
inf = remote_add_inferior (fake_pid_p,
- ptid_get_pid (currthread), -1);
+ ptid_get_pid (currthread), -1, 1);
}
/* This is really a new thread. Add it. */
gdb_assert (info);
- if (!info->private)
+ if (!info->priv)
{
- info->private = xmalloc (sizeof (*(info->private)));
+ info->priv = xmalloc (sizeof (*(info->priv)));
info->private_dtor = free_private_thread_info;
- info->private->core = -1;
- info->private->extra = 0;
+ info->priv->core = -1;
+ info->priv->extra = 0;
}
- return info->private;
+ return info->priv;
}
/* Call this function as a result of
}
\f
-/* Return nonzero if the thread PTID is still alive on the remote
- system. */
+/* Return nonzero if this is the main thread that we made up ourselves
+ to model non-threaded targets as single-threaded. */
static int
-remote_thread_alive (struct target_ops *ops, ptid_t ptid)
+remote_thread_always_alive (struct target_ops *ops, ptid_t ptid)
{
struct remote_state *rs = get_remote_state ();
char *p, *endp;
multi-threading. */
return 1;
+ return 0;
+}
+
+/* Return nonzero if the thread PTID is still alive on the remote
+ system. */
+
+static int
+remote_thread_alive (struct target_ops *ops, ptid_t ptid)
+{
+ struct remote_state *rs = get_remote_state ();
+ char *p, *endp;
+
+ /* Check if this is a thread that we made up ourselves to model
+ non-threaded targets as single-threaded. */
+ if (remote_thread_always_alive (ops, ptid))
+ return 1;
+
p = rs->buf;
endp = rs->buf + get_remote_packet_size ();
return resultcount;
}
+/* Fetch the next batch of threads from the remote. Returns -1 if the
+ qL packet is not supported, 0 on error and 1 on success. */
+
static int
remote_get_threadlist (int startflag, threadref *nextthread, int result_limit,
int *done, int *result_count, threadref *threadlist)
pack_threadlist_request (rs->buf, startflag, result_limit, nextthread);
putpkt (rs->buf);
getpkt (&rs->buf, &rs->buf_size, 0);
-
if (*rs->buf == '\0')
- return 0;
- else
- *result_count =
- parse_threadlist_response (rs->buf + 2, result_limit,
- &rs->echo_nextthread, threadlist, done);
+ {
+ /* Packet not supported. */
+ return -1;
+ }
+
+ *result_count =
+ parse_threadlist_response (rs->buf + 2, result_limit,
+ &rs->echo_nextthread, threadlist, done);
if (!threadmatch (&rs->echo_nextthread, nextthread))
{
return result;
}
-/* This is the interface between remote and threads, remotes upper
- interface. */
-
-/* remote_find_new_threads retrieves the thread list and for each
- thread in the list, looks up the thread in GDB's internal list,
- adding the thread if it does not already exist. This involves
- getting partial thread lists from the remote target so, polling the
- quit_flag is required. */
-
+/* Fetch the list of remote threads, with the qL packet, and call
+ STEPFUNCTION for each thread found. Stops iterating and returns 1
+ if STEPFUNCTION returns true. Stops iterating and returns 0 if the
+ STEPFUNCTION returns false. If the packet is not supported,
+ returns -1. */
static int
remote_threadlist_iterator (rmt_thread_action stepfunction, void *context,
warning (_("Remote fetch threadlist -infinite loop-."));
break;
}
- if (!remote_get_threadlist (startflag, &rs->nextthread,
- MAXTHREADLISTRESULTS,
- &done, &result_count, rs->resultthreadlist))
- {
- result = 0;
- break;
- }
+ result = remote_get_threadlist (startflag, &rs->nextthread,
+ MAXTHREADLISTRESULTS,
+ &done, &result_count,
+ rs->resultthreadlist);
+ if (result <= 0)
+ break;
/* Clear for later iterations. */
startflag = 0;
/* Setup to resume next batch of thread references, set nextthread. */
&rs->resultthreadlist[result_count - 1]);
i = 0;
while (result_count--)
- if (!(result = (*stepfunction) (&rs->resultthreadlist[i++], context)))
- break;
+ {
+ if (!(*stepfunction) (&rs->resultthreadlist[i++], context))
+ {
+ result = 0;
+ break;
+ }
+ }
}
return result;
}
+/* A thread found on the remote target. */
+
+typedef struct thread_item
+{
+ /* The thread's PTID. */
+ ptid_t ptid;
+
+ /* The thread's extra info. May be NULL. */
+ char *extra;
+
+ /* The core the thread was running on. -1 if not known. */
+ int core;
+} thread_item_t;
+DEF_VEC_O(thread_item_t);
+
+/* Context passed around to the various methods listing remote
+ threads. As new threads are found, they're added to the ITEMS
+ vector. */
+
+struct threads_listing_context
+{
+ /* The threads found on the remote target. */
+ VEC (thread_item_t) *items;
+};
+
+/* Discard the contents of the constructed thread listing context. */
+
+static void
+clear_threads_listing_context (void *p)
+{
+ struct threads_listing_context *context = p;
+ int i;
+ struct thread_item *item;
+
+ for (i = 0; VEC_iterate (thread_item_t, context->items, i, item); ++i)
+ xfree (item->extra);
+
+ VEC_free (thread_item_t, context->items);
+}
+
+/* Remove the thread specified as the related_pid field of WS
+ from the CONTEXT list. */
+
+static void
+threads_listing_context_remove (struct target_waitstatus *ws,
+ struct threads_listing_context *context)
+{
+ struct thread_item *item;
+ int i;
+ ptid_t child_ptid = ws->value.related_pid;
+
+ for (i = 0; VEC_iterate (thread_item_t, context->items, i, item); ++i)
+ {
+ if (ptid_equal (item->ptid, child_ptid))
+ {
+ VEC_ordered_remove (thread_item_t, context->items, i);
+ break;
+ }
+ }
+}
+
static int
-remote_newthread_step (threadref *ref, void *context)
+remote_newthread_step (threadref *ref, void *data)
{
+ struct threads_listing_context *context = data;
+ struct thread_item item;
int pid = ptid_get_pid (inferior_ptid);
- ptid_t ptid = ptid_build (pid, threadref_to_int (ref), 0);
- if (!in_thread_list (ptid))
- add_thread (ptid);
+ item.ptid = ptid_build (pid, threadref_to_int (ref), 0);
+ item.core = -1;
+ item.extra = NULL;
+
+ VEC_safe_push (thread_item_t, context->items, &item);
+
return 1; /* continue iterator */
}
return oldpid;
}
-/* Find new threads for info threads command.
- * Original version, using John Metzler's thread protocol.
- */
+/* List remote threads using the deprecated qL packet. */
-static void
-remote_find_new_threads (void)
+static int
+remote_get_threads_with_ql (struct target_ops *ops,
+ struct threads_listing_context *context)
{
- remote_threadlist_iterator (remote_newthread_step, 0,
- CRAZY_MAX_THREADS);
+ if (remote_threadlist_iterator (remote_newthread_step, context,
+ CRAZY_MAX_THREADS) >= 0)
+ return 1;
+
+ return 0;
}
#if defined(HAVE_LIBEXPAT)
-typedef struct thread_item
-{
- ptid_t ptid;
- char *extra;
- int core;
-} thread_item_t;
-DEF_VEC_O(thread_item_t);
-
-struct threads_parsing_context
-{
- VEC (thread_item_t) *items;
-};
-
static void
start_thread (struct gdb_xml_parser *parser,
const struct gdb_xml_element *element,
void *user_data, VEC(gdb_xml_value_s) *attributes)
{
- struct threads_parsing_context *data = user_data;
+ struct threads_listing_context *data = user_data;
struct thread_item item;
char *id;
const struct gdb_xml_element *element,
void *user_data, const char *body_text)
{
- struct threads_parsing_context *data = user_data;
+ struct threads_listing_context *data = user_data;
if (body_text && *body_text)
VEC_last (thread_item_t, data->items)->extra = xstrdup (body_text);
{ NULL, NULL, NULL, GDB_XML_EF_NONE, NULL, NULL }
};
-/* Discard the contents of the constructed thread info context. */
-
-static void
-clear_threads_parsing_context (void *p)
-{
- struct threads_parsing_context *context = p;
- int i;
- struct thread_item *item;
-
- for (i = 0; VEC_iterate (thread_item_t, context->items, i, item); ++i)
- xfree (item->extra);
-
- VEC_free (thread_item_t, context->items);
-}
-
#endif
-/*
- * Find all threads for info threads command.
- * Uses new thread protocol contributed by Cisco.
- * Falls back and attempts to use the older method (above)
- * if the target doesn't respond to the new method.
- */
+/* List remote threads using qXfer:threads:read. */
-static void
-remote_threads_info (struct target_ops *ops)
+static int
+remote_get_threads_with_qxfer (struct target_ops *ops,
+ struct threads_listing_context *context)
{
- struct remote_state *rs = get_remote_state ();
- char *bufp;
- ptid_t new_thread;
-
- if (rs->remote_desc == 0) /* paranoia */
- error (_("Command can only be used when connected to the remote target."));
-
#if defined(HAVE_LIBEXPAT)
if (packet_support (PACKET_qXfer_threads) == PACKET_ENABLE)
{
- char *xml = target_read_stralloc (¤t_target,
- TARGET_OBJECT_THREADS, NULL);
-
+ char *xml = target_read_stralloc (ops, TARGET_OBJECT_THREADS, NULL);
struct cleanup *back_to = make_cleanup (xfree, xml);
- if (xml && *xml)
+ if (xml != NULL && *xml != '\0')
{
- struct threads_parsing_context context;
-
- context.items = NULL;
- make_cleanup (clear_threads_parsing_context, &context);
-
- if (gdb_xml_parse_quick (_("threads"), "threads.dtd",
- threads_elements, xml, &context) == 0)
- {
- int i;
- struct thread_item *item;
-
- for (i = 0;
- VEC_iterate (thread_item_t, context.items, i, item);
- ++i)
- {
- if (!ptid_equal (item->ptid, null_ptid))
- {
- struct private_thread_info *info;
- /* In non-stop mode, we assume new found threads
- are running until proven otherwise with a
- stop reply. In all-stop, we can only get
- here if all threads are stopped. */
- int running = non_stop ? 1 : 0;
-
- remote_notice_new_inferior (item->ptid, running);
-
- info = demand_private_info (item->ptid);
- info->core = item->core;
- info->extra = item->extra;
- item->extra = NULL;
- }
- }
- }
+ gdb_xml_parse_quick (_("threads"), "threads.dtd",
+ threads_elements, xml, context);
}
do_cleanups (back_to);
- return;
+ return 1;
}
#endif
+ return 0;
+}
+
+/* List remote threads using qfThreadInfo/qsThreadInfo. */
+
+static int
+remote_get_threads_with_qthreadinfo (struct target_ops *ops,
+ struct threads_listing_context *context)
+{
+ struct remote_state *rs = get_remote_state ();
+
if (rs->use_threadinfo_query)
{
+ char *bufp;
+
putpkt ("qfThreadInfo");
getpkt (&rs->buf, &rs->buf_size, 0);
bufp = rs->buf;
if (bufp[0] != '\0') /* q packet recognized */
{
- struct cleanup *old_chain;
- char *saved_reply;
-
- /* remote_notice_new_inferior (in the loop below) may make
- new RSP calls, which clobber rs->buf. Work with a
- copy. */
- bufp = saved_reply = xstrdup (rs->buf);
- old_chain = make_cleanup (free_current_contents, &saved_reply);
-
while (*bufp++ == 'm') /* reply contains one or more TID */
{
do
{
- new_thread = read_ptid (bufp, &bufp);
- if (!ptid_equal (new_thread, null_ptid))
- {
- /* In non-stop mode, we assume new found threads
- are running until proven otherwise with a
- stop reply. In all-stop, we can only get
- here if all threads are stopped. */
- int running = non_stop ? 1 : 0;
+ struct thread_item item;
- remote_notice_new_inferior (new_thread, running);
- }
+ item.ptid = read_ptid (bufp, &bufp);
+ item.core = -1;
+ item.extra = NULL;
+
+ VEC_safe_push (thread_item_t, context->items, &item);
}
while (*bufp++ == ','); /* comma-separated list */
- free_current_contents (&saved_reply);
putpkt ("qsThreadInfo");
getpkt (&rs->buf, &rs->buf_size, 0);
- bufp = saved_reply = xstrdup (rs->buf);
+ bufp = rs->buf;
}
+ return 1;
+ }
+ else
+ {
+ /* Packet not recognized. */
+ rs->use_threadinfo_query = 0;
+ }
+ }
+
+ return 0;
+}
+
+/* Implement the to_update_thread_list function for the remote
+ targets. */
+
+static void
+remote_update_thread_list (struct target_ops *ops)
+{
+ struct remote_state *rs = get_remote_state ();
+ struct threads_listing_context context;
+ struct cleanup *old_chain;
+ int got_list = 0;
+
+ context.items = NULL;
+ old_chain = make_cleanup (clear_threads_listing_context, &context);
+
+ /* We have a few different mechanisms to fetch the thread list. Try
+ them all, starting with the most preferred one first, falling
+ back to older methods. */
+ if (remote_get_threads_with_qxfer (ops, &context)
+ || remote_get_threads_with_qthreadinfo (ops, &context)
+ || remote_get_threads_with_ql (ops, &context))
+ {
+ int i;
+ struct thread_item *item;
+ struct thread_info *tp, *tmp;
+
+ got_list = 1;
+
+ if (VEC_empty (thread_item_t, context.items)
+ && remote_thread_always_alive (ops, inferior_ptid))
+ {
+ /* Some targets don't really support threads, but still
+ reply an (empty) thread list in response to the thread
+ listing packets, instead of replying "packet not
+ supported". Exit early so we don't delete the main
+ thread. */
do_cleanups (old_chain);
- return; /* done */
+ return;
+ }
+
+ /* CONTEXT now holds the current thread list on the remote
+ target end. Delete GDB-side threads no longer found on the
+ target. */
+ ALL_THREADS_SAFE (tp, tmp)
+ {
+ for (i = 0;
+ VEC_iterate (thread_item_t, context.items, i, item);
+ ++i)
+ {
+ if (ptid_equal (item->ptid, tp->ptid))
+ break;
+ }
+
+ if (i == VEC_length (thread_item_t, context.items))
+ {
+ /* Not found. */
+ delete_thread (tp->ptid);
+ }
+ }
+
+ /* Remove any unreported fork child threads from CONTEXT so
+ that we don't interfere with follow fork, which is where
+ creation of such threads is handled. */
+ remove_new_fork_children (&context);
+
+ /* And now add threads we don't know about yet to our list. */
+ for (i = 0;
+ VEC_iterate (thread_item_t, context.items, i, item);
+ ++i)
+ {
+ if (!ptid_equal (item->ptid, null_ptid))
+ {
+ struct private_thread_info *info;
+ /* In non-stop mode, we assume new found threads are
+ running until proven otherwise with a stop reply. In
+ all-stop, we can only get here if all threads are
+ stopped. */
+ int running = non_stop ? 1 : 0;
+
+ remote_notice_new_inferior (item->ptid, running);
+
+ info = demand_private_info (item->ptid);
+ info->core = item->core;
+ info->extra = item->extra;
+ item->extra = NULL;
+ }
}
}
- /* Only qfThreadInfo is supported in non-stop mode. */
- if (non_stop)
- return;
+ if (!got_list)
+ {
+ /* If no thread listing method is supported, then query whether
+ each known thread is alive, one by one, with the T packet.
+ If the target doesn't support threads at all, then this is a
+ no-op. See remote_thread_alive. */
+ prune_threads ();
+ }
- /* Else fall back to old method based on jmetzler protocol. */
- rs->use_threadinfo_query = 0;
- remote_find_new_threads ();
- return;
+ do_cleanups (old_chain);
}
/*
{
struct thread_info *info = find_thread_ptid (tp->ptid);
- if (info && info->private)
- return info->private->extra;
+ if (info && info->priv)
+ return info->priv->extra;
else
return NULL;
}
ptr = buf;
lose = 0;
- if (strncmp (ptr, "Text=", 5) == 0)
+ if (startswith (ptr, "Text="))
{
ptr += 5;
/* Don't use strtol, could lose on big values. */
while (*ptr && *ptr != ';')
text_addr = (text_addr << 4) + fromhex (*ptr++);
- if (strncmp (ptr, ";Data=", 6) == 0)
+ if (startswith (ptr, ";Data="))
{
ptr += 6;
while (*ptr && *ptr != ';')
else
lose = 1;
- if (!lose && strncmp (ptr, ";Bss=", 5) == 0)
+ if (!lose && startswith (ptr, ";Bss="))
{
ptr += 5;
while (*ptr && *ptr != ';')
else
lose = 1;
}
- else if (strncmp (ptr, "TextSeg=", 8) == 0)
+ else if (startswith (ptr, "TextSeg="))
{
ptr += 8;
/* Don't use strtol, could lose on big values. */
text_addr = (text_addr << 4) + fromhex (*ptr++);
num_segments = 1;
- if (strncmp (ptr, ";DataSeg=", 9) == 0)
+ if (startswith (ptr, ";DataSeg="))
{
ptr += 9;
while (*ptr && *ptr != ';')
fake_pid_p = 1;
}
- remote_add_inferior (fake_pid_p, ptid_get_pid (inferior_ptid), -1);
+ remote_add_inferior (fake_pid_p, ptid_get_pid (inferior_ptid), -1, 1);
/* Add the main thread. */
add_thread_silent (inferior_ptid);
controlling. We default to adding them in the running state.
The '?' query below will then tell us about which threads are
stopped. */
- remote_threads_info (target);
+ remote_update_thread_list (target);
}
else if (packet_support (PACKET_QNonStop) == PACKET_ENABLE)
{
}
/* Fetch thread list. */
- target_find_new_threads ();
+ target_update_thread_list ();
/* Let the stub know that we want it to return the thread. */
set_continue_thread (minus_one_ptid);
}
if (target_can_async_p ())
- target_async (inferior_event_handler, 0);
+ target_async (1);
if (thread_count () == 0)
{
packet_ok (rs->buf, &remote_protocol_packets[PACKET_qSymbol]);
reply = rs->buf;
- while (strncmp (reply, "qSymbol:", 8) == 0)
+ while (startswith (reply, "qSymbol:"))
{
struct bound_minimal_symbol sym;
of in ser-tcp.c, because it is the remote protocol assuming that the
serial connection is reliable and not the serial connection promising
to be. */
- if (!udp_warning && strncmp (name, "udp:", 4) == 0)
+ if (!udp_warning && startswith (name, "udp:"))
{
warning (_("The remote protocol may be unreliable over UDP.\n"
"Some events may be lost, rendering further debugging "
{ "PacketSize", PACKET_DISABLE, remote_packet_size, -1 },
{ "qXfer:auxv:read", PACKET_DISABLE, remote_supported_packet,
PACKET_qXfer_auxv },
+ { "qXfer:exec-file:read", PACKET_DISABLE, remote_supported_packet,
+ PACKET_qXfer_exec_file },
{ "qXfer:features:read", PACKET_DISABLE, remote_supported_packet,
PACKET_qXfer_features },
{ "qXfer:libraries:read", PACKET_DISABLE, remote_supported_packet,
{ "Qbtrace:off", PACKET_DISABLE, remote_supported_packet, PACKET_Qbtrace_off },
{ "Qbtrace:bts", PACKET_DISABLE, remote_supported_packet, PACKET_Qbtrace_bts },
{ "qXfer:btrace:read", PACKET_DISABLE, remote_supported_packet,
- PACKET_qXfer_btrace }
+ PACKET_qXfer_btrace },
+ { "qXfer:btrace-conf:read", PACKET_DISABLE, remote_supported_packet,
+ PACKET_qXfer_btrace_conf },
+ { "Qbtrace-conf:bts:size", PACKET_DISABLE, remote_supported_packet,
+ PACKET_Qbtrace_conf_bts_size },
+ { "swbreak", PACKET_DISABLE, remote_supported_packet, PACKET_swbreak_feature },
+ { "hwbreak", PACKET_DISABLE, remote_supported_packet, PACKET_hwbreak_feature },
+ { "fork-events", PACKET_DISABLE, remote_supported_packet,
+ PACKET_fork_event_feature },
+ { "vfork-events", PACKET_DISABLE, remote_supported_packet,
+ PACKET_vfork_event_feature },
};
static char *remote_support_xml;
q = remote_query_supported_append (q, "multiprocess+");
+ if (packet_set_cmd_state (PACKET_swbreak_feature) != AUTO_BOOLEAN_FALSE)
+ q = remote_query_supported_append (q, "swbreak+");
+ if (packet_set_cmd_state (PACKET_hwbreak_feature) != AUTO_BOOLEAN_FALSE)
+ q = remote_query_supported_append (q, "hwbreak+");
+
if (remote_support_xml)
q = remote_query_supported_append (q, remote_support_xml);
q = remote_query_supported_append (q, "qRelocInsn+");
+ if (rs->extended)
+ {
+ if (packet_set_cmd_state (PACKET_fork_event_feature)
+ != AUTO_BOOLEAN_FALSE)
+ q = remote_query_supported_append (q, "fork-events+");
+ if (packet_set_cmd_state (PACKET_vfork_event_feature)
+ != AUTO_BOOLEAN_FALSE)
+ q = remote_query_supported_append (q, "vfork-events+");
+ }
+
q = reconcat (q, "qSupported:", q, (char *) NULL);
putpkt (q);
}
}
+ serial_setparity (rs->remote_desc, serial_parity);
serial_raw (rs->remote_desc);
/* If there is something sitting in the buffer we might take it as a
all the ``target ....'' commands to share a common callback
function. See cli-dump.c. */
{
- volatile struct gdb_exception ex;
- TRY_CATCH (ex, RETURN_MASK_ALL)
+ TRY
{
remote_start_remote (from_tty, target, extended_p);
}
- if (ex.reason < 0)
+ CATCH (ex, RETURN_MASK_ALL)
{
/* Pop the partially set up target - unless something else did
already before throwing the exception. */
wait_forever_enabled_p = 1;
throw_exception (ex);
}
+ END_CATCH
}
+ remote_btrace_reset ();
+
if (target_async_permitted)
wait_forever_enabled_p = 1;
}
-/* This takes a program previously attached to and detaches it. After
- this is done, GDB can be used to debug some other program. We
- better not have left any breakpoints in the target program or it'll
- die when it hits one. */
+/* Detach the specified process. */
+
+static void
+remote_detach_pid (int pid)
+{
+ struct remote_state *rs = get_remote_state ();
+
+ if (remote_multi_process_p (rs))
+ xsnprintf (rs->buf, get_remote_packet_size (), "D;%x", pid);
+ else
+ strcpy (rs->buf, "D");
+
+ putpkt (rs->buf);
+ getpkt (&rs->buf, &rs->buf_size, 0);
+
+ if (rs->buf[0] == 'O' && rs->buf[1] == 'K')
+ ;
+ else if (rs->buf[0] == '\0')
+ error (_("Remote doesn't know how to detach"));
+ else
+ error (_("Can't detach process."));
+}
+
+/* This detaches a program to which we previously attached, using
+ inferior_ptid to identify the process. After this is done, GDB
+ can be used to debug some other program. We better not have left
+ any breakpoints in the target program or it'll die when it hits
+ one. */
static void
-remote_detach_1 (const char *args, int from_tty, int extended)
+remote_detach_1 (const char *args, int from_tty)
{
int pid = ptid_get_pid (inferior_ptid);
struct remote_state *rs = get_remote_state ();
+ struct thread_info *tp = find_thread_ptid (inferior_ptid);
+ int is_fork_parent;
if (args)
error (_("Argument given to \"detach\" when remotely debugging."));
}
/* Tell the remote target to detach. */
- if (remote_multi_process_p (rs))
- xsnprintf (rs->buf, get_remote_packet_size (), "D;%x", pid);
- else
- strcpy (rs->buf, "D");
-
- putpkt (rs->buf);
- getpkt (&rs->buf, &rs->buf_size, 0);
-
- if (rs->buf[0] == 'O' && rs->buf[1] == 'K')
- ;
- else if (rs->buf[0] == '\0')
- error (_("Remote doesn't know how to detach"));
- else
- error (_("Can't detach process."));
+ remote_detach_pid (pid);
- if (from_tty && !extended)
+ if (from_tty && !rs->extended)
puts_filtered (_("Ending remote debugging.\n"));
- target_mourn_inferior ();
+ /* Check to see if we are detaching a fork parent. Note that if we
+ are detaching a fork child, tp == NULL. */
+ is_fork_parent = (tp != NULL
+ && tp->pending_follow.kind == TARGET_WAITKIND_FORKED);
+
+ /* 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 ();
+ else
+ {
+ inferior_ptid = null_ptid;
+ detach_inferior (pid);
+ }
}
static void
remote_detach (struct target_ops *ops, const char *args, int from_tty)
{
- remote_detach_1 (args, from_tty, 0);
+ remote_detach_1 (args, from_tty);
}
static void
extended_remote_detach (struct target_ops *ops, const char *args, int from_tty)
{
- remote_detach_1 (args, from_tty, 1);
+ remote_detach_1 (args, from_tty);
+}
+
+/* Target follow-fork function for remote targets. On entry, and
+ at return, the current inferior is the fork parent.
+
+ Note that although this is currently only used for extended-remote,
+ it is named remote_follow_fork in anticipation of using it for the
+ remote target as well. */
+
+static int
+remote_follow_fork (struct target_ops *ops, int follow_child,
+ int detach_fork)
+{
+ struct remote_state *rs = get_remote_state ();
+ enum target_waitkind kind = inferior_thread ()->pending_follow.kind;
+
+ if ((kind == TARGET_WAITKIND_FORKED && remote_fork_event_p (rs))
+ || (kind == TARGET_WAITKIND_VFORKED && remote_vfork_event_p (rs)))
+ {
+ /* When following the parent and detaching the child, we detach
+ the child here. For the case of following the child and
+ detaching the parent, the detach is done in the target-
+ independent follow fork code in infrun.c. We can't use
+ target_detach when detaching an unfollowed child because
+ the client side doesn't know anything about the child. */
+ if (detach_fork && !follow_child)
+ {
+ /* Detach the fork child. */
+ ptid_t child_ptid;
+ pid_t child_pid;
+
+ child_ptid = inferior_thread ()->pending_follow.value.related_pid;
+ child_pid = ptid_get_pid (child_ptid);
+
+ remote_detach_pid (child_pid);
+ detach_inferior (child_pid);
+ }
+ }
+ return 0;
}
/* Same as remote_detach, but don't send the "D" packet; just disconnect. */
error (_("Argument given to \"disconnect\" when remotely debugging."));
/* Make sure we unpush even the extended remote targets; mourn
- won't do it. So call remote_mourn_1 directly instead of
+ won't do it. So call remote_mourn directly instead of
target_mourn_inferior. */
- remote_mourn_1 (target);
+ remote_mourn (target);
if (from_tty)
puts_filtered ("Ending remote debugging.\n");
be chatty about it. */
static void
-extended_remote_attach_1 (struct target_ops *target, const char *args,
- int from_tty)
+extended_remote_attach (struct target_ops *target, const char *args,
+ int from_tty)
{
struct remote_state *rs = get_remote_state ();
int pid;
target_pid_to_str (pid_to_ptid (pid)));
}
- set_current_inferior (remote_add_inferior (0, pid, 1));
+ set_current_inferior (remote_add_inferior (0, pid, 1, 0));
inferior_ptid = pid_to_ptid (pid);
struct thread_info *thread;
/* Get list of threads. */
- remote_threads_info (target);
+ remote_update_thread_list (target);
thread = first_thread_of_process (pid);
if (thread)
push_stop_reply ((struct stop_reply *) reply);
- target_async (inferior_event_handler, 0);
+ target_async (1);
}
else
{
gdb_assert (wait_status == NULL);
}
-static void
-extended_remote_attach (struct target_ops *ops, const char *args, int from_tty)
-{
- extended_remote_attach_1 (ops, args, from_tty);
-}
-
/* Implementation of the to_post_attach method. */
static void
buf = rs->buf;
/* Make sure that the features we assume are supported. */
- if (strncmp (buf, "vCont", 5) == 0)
+ if (startswith (buf, "vCont"))
{
char *p = &buf[5];
int support_s, support_S, support_c, support_C;
into infcmd.c in order to allow inferior function calls to work
NOT asynchronously. */
if (target_can_async_p ())
- target_async (inferior_event_handler, 0);
+ target_async (1);
/* We've just told the target to resume. The remote server will
wait for the inferior to stop, and then send a stop reply. In
{
target_terminal_ours ();
- if (target_can_async_p ())
+ if (target_is_async_p ())
{
signal (SIGINT, handle_sigint);
quit ();
fetch them is avoided). */
VEC(cached_reg_t) *regcache;
- int stopped_by_watchpoint_p;
+ enum target_stop_reason stop_reason;
+
CORE_ADDR watch_data_address;
int core;
struct stop_reply *output;
};
+/* Determine if THREAD 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. */
+
+static int
+is_pending_fork_parent (struct target_waitstatus *ws, int event_pid,
+ ptid_t thread_ptid)
+{
+ if (ws->kind == TARGET_WAITKIND_FORKED
+ || ws->kind == TARGET_WAITKIND_VFORKED)
+ {
+ if (event_pid == -1 || event_pid == ptid_get_pid (thread_ptid))
+ return 1;
+ }
+
+ return 0;
+}
+
+/* Check whether EVENT is a fork event, and if it is, remove the
+ fork child from the context list passed in DATA. */
+
+static int
+remove_child_of_pending_fork (QUEUE (stop_reply_p) *q,
+ QUEUE_ITER (stop_reply_p) *iter,
+ stop_reply_p event,
+ void *data)
+{
+ struct queue_iter_param *param = data;
+ struct threads_listing_context *context = param->input;
+
+ if (event->ws.kind == TARGET_WAITKIND_FORKED
+ || event->ws.kind == TARGET_WAITKIND_VFORKED)
+ {
+ threads_listing_context_remove (&event->ws, context);
+ }
+
+ return 1;
+}
+
+/* If CONTEXT contains any fork child threads that have not been
+ reported yet, remove them from the CONTEXT list. If such a
+ thread exists it is because we are stopped at a fork catchpoint
+ and have not yet called follow_fork, which will set up the
+ host-side data structures for the new process. */
+
+static void
+remove_new_fork_children (struct threads_listing_context *context)
+{
+ struct thread_info * thread;
+ int pid = -1;
+ struct notif_client *notif = ¬if_client_stop;
+ struct queue_iter_param param;
+
+ /* 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 = &thread->pending_follow;
+
+ if (is_pending_fork_parent (ws, pid, thread->ptid))
+ {
+ threads_listing_context_remove (ws, context);
+ }
+ }
+
+ /* Check for any pending fork events (not reported or processed yet)
+ in process PID and remove those fork child threads from the
+ CONTEXT list as well. */
+ remote_notif_get_pending_events (notif);
+ param.input = context;
+ param.output = NULL;
+ QUEUE_iterate (stop_reply_p, stop_reply_queue,
+ remove_child_of_pending_fork, ¶m);
+}
+
/* Remove stop replies in the queue if its pid is equal to the given
inferior's pid. */
stop_reply_match_ptid_and_ws, &ptid);
}
+/* Skip PACKET until the next semi-colon (or end of string). */
+
+static char *
+skip_to_semicolon (char *p)
+{
+ while (*p != '\0' && *p != ';')
+ p++;
+ return p;
+}
+
/* Parse the stop reply in BUF. Either the function succeeds, and the
result is stored in EVENT, or throws an error. */
event->rs = get_remote_state ();
event->ws.kind = TARGET_WAITKIND_IGNORE;
event->ws.value.integer = 0;
- event->stopped_by_watchpoint_p = 0;
+ event->stop_reason = TARGET_STOPPED_BY_NO_REASON;
event->regcache = NULL;
event->core = -1;
while (*p)
{
char *p1;
- char *p_temp;
int fieldsize;
- LONGEST pnum = 0;
- /* If the packet contains a register number, save it in
- pnum and set p1 to point to the character following it.
- Otherwise p1 points to p. */
+ p1 = strchr (p, ':');
+ if (p1 == NULL)
+ error (_("Malformed packet(a) (missing colon): %s\n\
+Packet: '%s'\n"),
+ p, buf);
+ if (p == p1)
+ error (_("Malformed packet(a) (missing register number): %s\n\
+Packet: '%s'\n"),
+ p, buf);
- /* If this packet is an awatch packet, don't parse the 'a'
- as a register number. */
+ /* Some "registers" are actually extended stop information.
+ Note if you're adding a new entry here: GDB 7.9 and
+ earlier assume that all register "numbers" that start
+ with an hex digit are real register numbers. Make sure
+ the server only sends such a packet if it knows the
+ client understands it. */
- if (strncmp (p, "awatch", strlen("awatch")) != 0
- && strncmp (p, "core", strlen ("core") != 0))
+ if (strncmp (p, "thread", p1 - p) == 0)
+ event->ptid = read_ptid (++p1, &p);
+ else if ((strncmp (p, "watch", p1 - p) == 0)
+ || (strncmp (p, "rwatch", p1 - p) == 0)
+ || (strncmp (p, "awatch", p1 - p) == 0))
{
- /* Read the ``P'' register number. */
- pnum = strtol (p, &p_temp, 16);
- p1 = p_temp;
+ event->stop_reason = TARGET_STOPPED_BY_WATCHPOINT;
+ p = unpack_varlen_hex (++p1, &addr);
+ event->watch_data_address = (CORE_ADDR) addr;
}
- else
- p1 = p;
-
- if (p1 == p) /* No register number present here. */
+ else if (strncmp (p, "swbreak", p1 - p) == 0)
{
- p1 = strchr (p, ':');
- if (p1 == NULL)
- error (_("Malformed packet(a) (missing colon): %s\n\
-Packet: '%s'\n"),
- p, buf);
- if (strncmp (p, "thread", p1 - p) == 0)
- event->ptid = read_ptid (++p1, &p);
- else if ((strncmp (p, "watch", p1 - p) == 0)
- || (strncmp (p, "rwatch", p1 - p) == 0)
- || (strncmp (p, "awatch", p1 - p) == 0))
- {
- event->stopped_by_watchpoint_p = 1;
- p = unpack_varlen_hex (++p1, &addr);
- event->watch_data_address = (CORE_ADDR) addr;
- }
- else if (strncmp (p, "library", p1 - p) == 0)
- {
- p1++;
- p_temp = p1;
- while (*p_temp && *p_temp != ';')
- p_temp++;
+ event->stop_reason = TARGET_STOPPED_BY_SW_BREAKPOINT;
- event->ws.kind = TARGET_WAITKIND_LOADED;
- p = p_temp;
- }
- else if (strncmp (p, "replaylog", p1 - p) == 0)
- {
- event->ws.kind = TARGET_WAITKIND_NO_HISTORY;
- /* p1 will indicate "begin" or "end", but it makes
- no difference for now, so ignore it. */
- p_temp = strchr (p1 + 1, ';');
- if (p_temp)
- p = p_temp;
- }
- else if (strncmp (p, "core", p1 - p) == 0)
- {
- ULONGEST c;
+ /* Make sure the stub doesn't forget to indicate support
+ with qSupported. */
+ if (packet_support (PACKET_swbreak_feature) != PACKET_ENABLE)
+ error (_("Unexpected swbreak stop reason"));
- p = unpack_varlen_hex (++p1, &c);
- event->core = c;
- }
- else
- {
- /* Silently skip unknown optional info. */
- p_temp = strchr (p1 + 1, ';');
- if (p_temp)
- p = p_temp;
- }
+ /* The value part is documented as "must be empty",
+ though we ignore it, in case we ever decide to make
+ use of it in a backward compatible way. */
+ p = skip_to_semicolon (p1 + 1);
}
- else
+ else if (strncmp (p, "hwbreak", p1 - p) == 0)
{
- struct packet_reg *reg = packet_reg_from_pnum (rsa, pnum);
- cached_reg_t cached_reg;
+ event->stop_reason = TARGET_STOPPED_BY_HW_BREAKPOINT;
- p = p1;
+ /* Make sure the stub doesn't forget to indicate support
+ with qSupported. */
+ if (packet_support (PACKET_hwbreak_feature) != PACKET_ENABLE)
+ error (_("Unexpected hwbreak stop reason"));
- if (*p != ':')
- error (_("Malformed packet(b) (missing colon): %s\n\
-Packet: '%s'\n"),
- p, buf);
- ++p;
+ /* See above. */
+ p = skip_to_semicolon (p1 + 1);
+ }
+ else if (strncmp (p, "library", p1 - p) == 0)
+ {
+ event->ws.kind = TARGET_WAITKIND_LOADED;
+ p = skip_to_semicolon (p1 + 1);
+ }
+ else if (strncmp (p, "replaylog", p1 - p) == 0)
+ {
+ event->ws.kind = TARGET_WAITKIND_NO_HISTORY;
+ /* p1 will indicate "begin" or "end", but it makes
+ no difference for now, so ignore it. */
+ p = skip_to_semicolon (p1 + 1);
+ }
+ else if (strncmp (p, "core", p1 - p) == 0)
+ {
+ ULONGEST c;
+
+ p = unpack_varlen_hex (++p1, &c);
+ event->core = c;
+ }
+ else if (strncmp (p, "fork", p1 - p) == 0)
+ {
+ event->ws.value.related_pid = read_ptid (++p1, &p);
+ event->ws.kind = TARGET_WAITKIND_FORKED;
+ }
+ else if (strncmp (p, "vfork", p1 - p) == 0)
+ {
+ event->ws.value.related_pid = read_ptid (++p1, &p);
+ event->ws.kind = TARGET_WAITKIND_VFORKED;
+ }
+ else if (strncmp (p, "vforkdone", p1 - p) == 0)
+ {
+ event->ws.kind = TARGET_WAITKIND_VFORK_DONE;
+ p = skip_to_semicolon (p1 + 1);
+ }
+ else
+ {
+ ULONGEST pnum;
+ char *p_temp;
+
+ /* Maybe a real ``P'' register number. */
+ p_temp = unpack_varlen_hex (p, &pnum);
+ /* If the first invalid character is the colon, we got a
+ register number. Otherwise, it's an unknown stop
+ reason. */
+ if (p_temp == p1)
+ {
+ struct packet_reg *reg = packet_reg_from_pnum (rsa, pnum);
+ cached_reg_t cached_reg;
- if (reg == NULL)
- error (_("Remote sent bad register number %s: %s\n\
+ if (reg == NULL)
+ error (_("Remote sent bad register number %s: %s\n\
Packet: '%s'\n"),
- hex_string (pnum), p, buf);
+ hex_string (pnum), p, buf);
- cached_reg.num = reg->regnum;
+ cached_reg.num = reg->regnum;
- fieldsize = hex2bin (p, cached_reg.data,
- register_size (target_gdbarch (),
- reg->regnum));
- p += 2 * fieldsize;
- if (fieldsize < register_size (target_gdbarch (),
- reg->regnum))
- warning (_("Remote reply is too short: %s"), buf);
+ p = p1 + 1;
+ fieldsize = hex2bin (p, cached_reg.data,
+ register_size (target_gdbarch (),
+ reg->regnum));
+ p += 2 * fieldsize;
+ if (fieldsize < register_size (target_gdbarch (),
+ reg->regnum))
+ warning (_("Remote reply is too short: %s"), buf);
- VEC_safe_push (cached_reg_t, event->regcache, &cached_reg);
+ VEC_safe_push (cached_reg_t, event->regcache, &cached_reg);
+ }
+ else
+ {
+ /* Not a number. Silently skip unknown optional
+ info. */
+ p = skip_to_semicolon (p1 + 1);
+ }
}
if (*p != ';')
{
p++;
- if (p == '\0')
+ if (*p == '\0')
;
- else if (strncmp (p,
- "process:", sizeof ("process:") - 1) == 0)
+ else if (startswith (p, "process:"))
{
ULONGEST upid;
VEC_free (cached_reg_t, stop_reply->regcache);
}
- rs->remote_stopped_by_watchpoint_p = stop_reply->stopped_by_watchpoint_p;
+ rs->stop_reason = stop_reply->stop_reason;
rs->remote_watch_data_address = stop_reply->watch_data_address;
remote_notice_new_inferior (ptid, 0);
buf = rs->buf;
- rs->remote_stopped_by_watchpoint_p = 0;
+ rs->stop_reason = TARGET_STOPPED_BY_NO_REASON;
/* We got something. */
rs->waiting_for_stop_reply = 0;
else
event_ptid = remote_wait_as (ptid, status, options);
- if (target_can_async_p ())
+ if (target_is_async_p ())
{
/* If there are are events left in the queue tell the event loop
to return here. */
}
}
+/* Helper function to resize the payload in order to try to get a good
+ alignment. We try to write an amount of data such that the next write will
+ start on an address aligned on REMOTE_ALIGN_WRITES. */
+
+static int
+align_for_efficient_write (int todo, CORE_ADDR memaddr)
+{
+ return ((memaddr + todo) & ~(REMOTE_ALIGN_WRITES - 1)) - memaddr;
+}
+
/* Write memory data directly to the remote machine.
This does not inform the data cache; the data cache uses this.
HEADER is the starting part of the packet.
MEMADDR is the address in the remote memory space.
MYADDR is the address of the buffer in our space.
- LEN is the number of bytes.
+ LEN_UNITS is the number of addressable units to write.
+ UNIT_SIZE is the length in bytes of an addressable unit.
PACKET_FORMAT should be either 'X' or 'M', and indicates if we
should send data as binary ('X'), or hex-encoded ('M').
The function creates packet of the form
<HEADER><ADDRESS>,<LENGTH>:<DATA>
- where encoding of <DATA> is termined by PACKET_FORMAT.
+ where encoding of <DATA> is terminated by PACKET_FORMAT.
If USE_LENGTH is 0, then the <LENGTH> field and the preceding comma
are omitted.
Return the transferred status, error or OK (an
- 'enum target_xfer_status' value). Save the number of bytes
- transferred in *XFERED_LEN. Only transfer a single packet. */
+ 'enum target_xfer_status' value). Save the number of addressable units
+ transferred in *XFERED_LEN_UNITS. Only transfer a single packet.
+
+ On a platform with an addressable memory size of 2 bytes (UNIT_SIZE == 2), an
+ exchange between gdb and the stub could look like (?? in place of the
+ checksum):
+
+ -> $m1000,4#??
+ <- aaaabbbbccccdddd
+
+ -> $M1000,3:eeeeffffeeee#??
+ <- OK
+
+ -> $m1000,4#??
+ <- eeeeffffeeeedddd */
static enum target_xfer_status
remote_write_bytes_aux (const char *header, CORE_ADDR memaddr,
- const gdb_byte *myaddr, ULONGEST len,
- ULONGEST *xfered_len, char packet_format,
- int use_length)
+ const gdb_byte *myaddr, ULONGEST len_units,
+ int unit_size, ULONGEST *xfered_len_units,
+ char packet_format, int use_length)
{
struct remote_state *rs = get_remote_state ();
char *p;
char *plen = NULL;
int plenlen = 0;
- int todo;
- int nr_bytes;
- int payload_size;
- int payload_length;
- int header_length;
+ int todo_units;
+ int units_written;
+ int payload_capacity_bytes;
+ int payload_length_bytes;
if (packet_format != 'X' && packet_format != 'M')
internal_error (__FILE__, __LINE__,
_("remote_write_bytes_aux: bad packet format"));
- if (len == 0)
+ if (len_units == 0)
return TARGET_XFER_EOF;
- payload_size = get_memory_write_packet_size ();
+ payload_capacity_bytes = get_memory_write_packet_size ();
/* The packet buffer will be large enough for the payload;
get_memory_packet_size ensures this. */
/* Compute the size of the actual payload by subtracting out the
packet header and footer overhead: "$M<memaddr>,<len>:...#nn". */
- payload_size -= strlen ("$,:#NN");
+ payload_capacity_bytes -= strlen ("$,:#NN");
if (!use_length)
/* The comma won't be used. */
- payload_size += 1;
- header_length = strlen (header);
- payload_size -= header_length;
- payload_size -= hexnumlen (memaddr);
+ payload_capacity_bytes += 1;
+ payload_capacity_bytes -= strlen (header);
+ payload_capacity_bytes -= hexnumlen (memaddr);
/* Construct the packet excluding the data: "<header><memaddr>,<len>:". */
if (packet_format == 'X')
{
/* Best guess at number of bytes that will fit. */
- todo = min (len, payload_size);
+ todo_units = min (len_units, payload_capacity_bytes / unit_size);
if (use_length)
- payload_size -= hexnumlen (todo);
- todo = min (todo, payload_size);
+ payload_capacity_bytes -= hexnumlen (todo_units);
+ todo_units = min (todo_units, payload_capacity_bytes / unit_size);
}
else
{
- /* Num bytes that will fit. */
- todo = min (len, payload_size / 2);
+ /* Number of bytes that will fit. */
+ todo_units = min (len_units, (payload_capacity_bytes / unit_size) / 2);
if (use_length)
- payload_size -= hexnumlen (todo);
- todo = min (todo, payload_size / 2);
+ payload_capacity_bytes -= hexnumlen (todo_units);
+ todo_units = min (todo_units, (payload_capacity_bytes / unit_size) / 2);
}
- if (todo <= 0)
+ if (todo_units <= 0)
internal_error (__FILE__, __LINE__,
_("minimum packet size too small to write data"));
/* If we already need another packet, then try to align the end
of this packet to a useful boundary. */
- if (todo > 2 * REMOTE_ALIGN_WRITES && todo < len)
- todo = ((memaddr + todo) & ~(REMOTE_ALIGN_WRITES - 1)) - memaddr;
+ if (todo_units > 2 * REMOTE_ALIGN_WRITES && todo_units < len_units)
+ todo_units = align_for_efficient_write (todo_units, memaddr);
/* Append "<memaddr>". */
memaddr = remote_address_masked (memaddr);
/* Append ",". */
*p++ = ',';
- /* Append <len>. Retain the location/size of <len>. It may need to
- be adjusted once the packet body has been created. */
+ /* Append the length and retain its location and size. It may need to be
+ adjusted once the packet body has been created. */
plen = p;
- plenlen = hexnumstr (p, (ULONGEST) todo);
+ plenlen = hexnumstr (p, (ULONGEST) todo_units);
p += plenlen;
}
/* Binary mode. Send target system values byte by byte, in
increasing byte addresses. Only escape certain critical
characters. */
- payload_length = remote_escape_output (myaddr, todo, (gdb_byte *) p,
- &nr_bytes, payload_size);
+ payload_length_bytes =
+ remote_escape_output (myaddr, todo_units, unit_size, (gdb_byte *) p,
+ &units_written, payload_capacity_bytes);
- /* If not all TODO bytes fit, then we'll need another packet. Make
+ /* If not all TODO units fit, then we'll need another packet. Make
a second try to keep the end of the packet aligned. Don't do
this if the packet is tiny. */
- if (nr_bytes < todo && nr_bytes > 2 * REMOTE_ALIGN_WRITES)
+ if (units_written < todo_units && units_written > 2 * REMOTE_ALIGN_WRITES)
{
- int new_nr_bytes;
-
- new_nr_bytes = (((memaddr + nr_bytes) & ~(REMOTE_ALIGN_WRITES - 1))
- - memaddr);
- if (new_nr_bytes != nr_bytes)
- payload_length = remote_escape_output (myaddr, new_nr_bytes,
- (gdb_byte *) p, &nr_bytes,
- payload_size);
+ int new_todo_units;
+
+ new_todo_units = align_for_efficient_write (units_written, memaddr);
+
+ if (new_todo_units != units_written)
+ payload_length_bytes =
+ remote_escape_output (myaddr, new_todo_units, unit_size,
+ (gdb_byte *) p, &units_written,
+ payload_capacity_bytes);
}
- p += payload_length;
- if (use_length && nr_bytes < todo)
+ p += payload_length_bytes;
+ if (use_length && units_written < todo_units)
{
/* Escape chars have filled up the buffer prematurely,
- and we have actually sent fewer bytes than planned.
+ and we have actually sent fewer units than planned.
Fix-up the length field of the packet. Use the same
number of characters as before. */
- plen += hexnumnstr (plen, (ULONGEST) nr_bytes, plenlen);
+ plen += hexnumnstr (plen, (ULONGEST) units_written,
+ plenlen);
*plen = ':'; /* overwrite \0 from hexnumnstr() */
}
}
/* Normal mode: Send target system values byte by byte, in
increasing byte addresses. Each byte is encoded as a two hex
value. */
- nr_bytes = bin2hex (myaddr, p, todo);
- p += 2 * nr_bytes;
+ p += 2 * bin2hex (myaddr, p, todo_units * unit_size);
+ units_written = todo_units;
}
putpkt_binary (rs->buf, (int) (p - rs->buf));
if (rs->buf[0] == 'E')
return TARGET_XFER_E_IO;
- /* Return NR_BYTES, not TODO, in case escape chars caused us to send
- fewer bytes than we'd planned. */
- *xfered_len = (ULONGEST) nr_bytes;
+ /* 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;
}
static enum target_xfer_status
remote_write_bytes (CORE_ADDR memaddr, const gdb_byte *myaddr, ULONGEST len,
- ULONGEST *xfered_len)
+ int unit_size, ULONGEST *xfered_len)
{
char *packet_format = 0;
}
return remote_write_bytes_aux (packet_format,
- memaddr, myaddr, len, xfered_len,
+ memaddr, myaddr, len, unit_size, xfered_len,
packet_format[0], 1);
}
This does not use the data cache; the data cache uses this.
MEMADDR is the address in the remote memory space.
MYADDR is the address of the buffer in our space.
- LEN is the number of bytes.
+ LEN_UNITS is the number of addressable memory units to read..
+ UNIT_SIZE is the length in bytes of an addressable unit.
Return the transferred status, error or OK (an
'enum target_xfer_status' value). Save the number of bytes
- transferred in *XFERED_LEN. */
+ transferred in *XFERED_LEN_UNITS.
+
+ See the comment of remote_write_bytes_aux for an example of
+ memory read/write exchange between gdb and the stub. */
static enum target_xfer_status
-remote_read_bytes_1 (CORE_ADDR memaddr, gdb_byte *myaddr, ULONGEST len,
- ULONGEST *xfered_len)
+remote_read_bytes_1 (CORE_ADDR memaddr, gdb_byte *myaddr, ULONGEST len_units,
+ int unit_size, ULONGEST *xfered_len_units)
{
struct remote_state *rs = get_remote_state ();
- int max_buf_size; /* Max size of packet output buffer. */
+ int buf_size_bytes; /* Max size of packet output buffer. */
char *p;
- int todo;
- int i;
+ int todo_units;
+ int decoded_bytes;
- max_buf_size = get_memory_read_packet_size ();
+ buf_size_bytes = get_memory_read_packet_size ();
/* The packet buffer will be large enough for the payload;
get_memory_packet_size ensures this. */
- /* Number if bytes that will fit. */
- todo = min (len, max_buf_size / 2);
+ /* Number of units that will fit. */
+ todo_units = min (len_units, (buf_size_bytes / unit_size) / 2);
/* Construct "m"<memaddr>","<len>". */
memaddr = remote_address_masked (memaddr);
*p++ = 'm';
p += hexnumstr (p, (ULONGEST) memaddr);
*p++ = ',';
- p += hexnumstr (p, (ULONGEST) todo);
+ p += hexnumstr (p, (ULONGEST) todo_units);
*p = '\0';
putpkt (rs->buf);
getpkt (&rs->buf, &rs->buf_size, 0);
/* Reply describes memory byte by byte, each byte encoded as two hex
characters. */
p = rs->buf;
- i = hex2bin (p, myaddr, todo);
+ decoded_bytes = hex2bin (p, myaddr, todo_units * unit_size);
/* Return what we have. Let higher layers handle partial reads. */
- *xfered_len = (ULONGEST) i;
+ *xfered_len_units = (ULONGEST) (decoded_bytes / unit_size);
return TARGET_XFER_OK;
}
static enum target_xfer_status
remote_xfer_live_readonly_partial (struct target_ops *ops, gdb_byte *readbuf,
ULONGEST memaddr, ULONGEST len,
- ULONGEST *xfered_len)
+ int unit_size, ULONGEST *xfered_len)
{
struct target_section *secp;
struct target_section_table *table;
if (memend <= p->endaddr)
{
/* Entire transfer is within this section. */
- return remote_read_bytes_1 (memaddr, readbuf, len,
+ return remote_read_bytes_1 (memaddr, readbuf, len, unit_size,
xfered_len);
}
else if (memaddr >= p->endaddr)
{
/* This section overlaps the transfer. Just do half. */
len = p->endaddr - memaddr;
- return remote_read_bytes_1 (memaddr, readbuf, len,
+ return remote_read_bytes_1 (memaddr, readbuf, len, unit_size,
xfered_len);
}
}
static enum target_xfer_status
remote_read_bytes (struct target_ops *ops, CORE_ADDR memaddr,
- gdb_byte *myaddr, ULONGEST len, ULONGEST *xfered_len)
+ gdb_byte *myaddr, ULONGEST len, int unit_size,
+ ULONGEST *xfered_len)
{
if (len == 0)
return TARGET_XFER_EOF;
/* This goes through the topmost target again. */
res = remote_xfer_live_readonly_partial (ops, myaddr, memaddr,
- len, xfered_len);
+ len, unit_size, xfered_len);
if (res == TARGET_XFER_OK)
return TARGET_XFER_OK;
else
}
}
- return remote_read_bytes_1 (memaddr, myaddr, len, xfered_len);
+ return remote_read_bytes_1 (memaddr, myaddr, len, unit_size, xfered_len);
}
\f
FORMAT and the remaining arguments, then gets the reply. Returns
whether the packet was a success, a failure, or unknown. */
+static enum packet_result remote_send_printf (const char *format, ...)
+ ATTRIBUTE_PRINTF (1, 2);
+
static enum packet_result
remote_send_printf (const char *format, ...)
{
&saved_remote_timeout);
remote_timeout = remote_flash_timeout;
- ret = remote_write_bytes_aux ("vFlashWrite:", address, data, length,
+ ret = remote_write_bytes_aux ("vFlashWrite:", address, data, length, 1,
xfered_len,'X', 0);
do_cleanups (back_to);
case it's not possible to issue a command while the target is
running. This is not a problem in non-stop mode, because in that
case, the stub is always ready to process serial input. */
- if (!non_stop && target_can_async_p () && rs->waiting_for_stop_reply)
+ if (!non_stop && target_is_async_p () && rs->waiting_for_stop_reply)
{
error (_("Cannot execute this command while the target is running.\n"
"Use the \"interrupt\" command to stop the target\n"
is_notif);
}
+/* Check whether EVENT is a fork event for the process specified
+ by the pid passed in DATA, and if it is, kill the fork child. */
+
+static int
+kill_child_of_pending_fork (QUEUE (stop_reply_p) *q,
+ QUEUE_ITER (stop_reply_p) *iter,
+ stop_reply_p event,
+ void *data)
+{
+ struct queue_iter_param *param = data;
+ int parent_pid = *(int *) param->input;
+
+ if (is_pending_fork_parent (&event->ws, parent_pid, event->ptid))
+ {
+ struct remote_state *rs = get_remote_state ();
+ int child_pid = ptid_get_pid (event->ws.value.related_pid);
+ int res;
+
+ res = remote_vkill (child_pid, rs);
+ if (res != 0)
+ error (_("Can't kill fork child process %d"), child_pid);
+ }
+
+ return 1;
+}
+
+/* Kill any new fork children of process PID that haven't been
+ processed by follow_fork. */
+
+static void
+kill_new_fork_children (int pid, struct remote_state *rs)
+{
+ struct thread_info *thread;
+ struct notif_client *notif = ¬if_client_stop;
+ struct queue_iter_param param;
+
+ /* Kill the fork child threads of any threads in process PID
+ that are stopped at a fork event. */
+ ALL_NON_EXITED_THREADS (thread)
+ {
+ struct target_waitstatus *ws = &thread->pending_follow;
+
+ if (is_pending_fork_parent (ws, pid, thread->ptid))
+ {
+ struct remote_state *rs = get_remote_state ();
+ int child_pid = ptid_get_pid (ws->value.related_pid);
+ int res;
+
+ res = remote_vkill (child_pid, rs);
+ if (res != 0)
+ error (_("Can't kill fork child process %d"), child_pid);
+ }
+ }
+
+ /* Check for any pending fork events (not reported or processed yet)
+ in process PID and kill those fork child threads as well. */
+ remote_notif_get_pending_events (notif);
+ param.input = &pid;
+ param.output = NULL;
+ QUEUE_iterate (stop_reply_p, stop_reply_queue,
+ kill_child_of_pending_fork, ¶m);
+}
+
\f
static void
remote_kill (struct target_ops *ops)
{
- volatile struct gdb_exception ex;
/* Catch errors so the user can quit from gdb even when we
aren't on speaking terms with the remote system. */
- TRY_CATCH (ex, RETURN_MASK_ERROR)
+ TRY
{
putpkt ("k");
}
- if (ex.reason < 0)
+ CATCH (ex, RETURN_MASK_ERROR)
{
if (ex.error == TARGET_CLOSE_ERROR)
{
user or higher layers decide what to do. */
throw_exception (ex);
}
+ END_CATCH
/* We've killed the remote end, we get to mourn it. Since this is
target remote, single-process, mourning the inferior also
int pid = ptid_get_pid (inferior_ptid);
struct remote_state *rs = get_remote_state ();
+ /* If we're stopped while forking and we haven't followed yet, kill the
+ child task. We need to do this before killing the parent task
+ because if this is a vfork then the parent will be sleeping. */
+ kill_new_fork_children (pid, rs);
+
res = remote_vkill (pid, rs);
if (res == -1 && !(rs->extended && remote_multi_process_p (rs)))
{
}
static void
-remote_mourn (struct target_ops *ops)
-{
- remote_mourn_1 (ops);
-}
-
-/* Worker function for remote_mourn. */
-static void
-remote_mourn_1 (struct target_ops *target)
+remote_mourn (struct target_ops *target)
{
unpush_target (target);
}
static void
-extended_remote_mourn_1 (struct target_ops *target)
+extended_remote_mourn (struct target_ops *target)
{
struct remote_state *rs = get_remote_state ();
say "kill" again. */
inferior_ptid = magic_null_ptid;
}
- }
- }
-}
-
-static void
-extended_remote_mourn (struct target_ops *ops)
-{
- extended_remote_mourn_1 (ops);
+ }
+ }
}
static int
/* If running asynchronously, register the target file descriptor
with the event loop. */
if (target_can_async_p ())
- target_async (inferior_event_handler, 0);
+ target_async (1);
/* Disable address space randomization if requested (and supported). */
if (extended_remote_supports_disable_randomization (ops))
if (packet_support (PACKET_Z0) != PACKET_DISABLE)
{
- CORE_ADDR addr = bp_tgt->placed_address;
+ CORE_ADDR addr = bp_tgt->reqstd_address;
struct remote_state *rs;
char *p, *endbuf;
int bpsize;
return -1;
}
+/* The to_stopped_by_sw_breakpoint method of target remote. */
+
+static int
+remote_stopped_by_sw_breakpoint (struct target_ops *ops)
+{
+ struct remote_state *rs = get_remote_state ();
+
+ return rs->stop_reason == TARGET_STOPPED_BY_SW_BREAKPOINT;
+}
+
+/* The to_supports_stopped_by_sw_breakpoint method of target
+ remote. */
+
+static int
+remote_supports_stopped_by_sw_breakpoint (struct target_ops *ops)
+{
+ struct remote_state *rs = get_remote_state ();
+
+ return (packet_support (PACKET_swbreak_feature) == PACKET_ENABLE);
+}
+
+/* The to_stopped_by_hw_breakpoint method of target remote. */
+
+static int
+remote_stopped_by_hw_breakpoint (struct target_ops *ops)
+{
+ struct remote_state *rs = get_remote_state ();
+
+ return rs->stop_reason == TARGET_STOPPED_BY_HW_BREAKPOINT;
+}
+
+/* The to_supports_stopped_by_hw_breakpoint method of target
+ remote. */
+
+static int
+remote_supports_stopped_by_hw_breakpoint (struct target_ops *ops)
+{
+ struct remote_state *rs = get_remote_state ();
+
+ return (packet_support (PACKET_hwbreak_feature) == PACKET_ENABLE);
+}
+
static int
remote_stopped_by_watchpoint (struct target_ops *ops)
{
struct remote_state *rs = get_remote_state ();
- return rs->remote_stopped_by_watchpoint_p;
+ return rs->stop_reason == TARGET_STOPPED_BY_WATCHPOINT;
}
static int
remote_insert_hw_breakpoint (struct target_ops *self, struct gdbarch *gdbarch,
struct bp_target_info *bp_tgt)
{
- CORE_ADDR addr;
+ CORE_ADDR addr = bp_tgt->reqstd_address;
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, &bp_tgt->placed_address, &bp_tgt->placed_size);
+ gdbarch_remote_breakpoint_from_pc (gdbarch, &addr, &bpsize);
if (packet_support (PACKET_Z1) == PACKET_DISABLE)
return -1;
*(p++) = '1';
*(p++) = ',';
- addr = remote_address_masked (bp_tgt->placed_address);
+ addr = remote_address_masked (addr);
p += hexnumstr (p, (ULONGEST) addr);
- xsnprintf (p, endbuf - p, ",%x", bp_tgt->placed_size);
+ xsnprintf (p, endbuf - p, ",%x", bpsize);
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__,
/* Escape as much data as fits into rs->buf. */
buf_len = remote_escape_output
- (writebuf, len, (gdb_byte *) rs->buf + i, &max_size, max_size);
+ (writebuf, len, 1, (gdb_byte *) rs->buf + i, &max_size, max_size);
if (putpkt_binary (rs->buf, i + buf_len) < 0
|| getpkt_sane (&rs->buf, &rs->buf_size, 0) < 0
int i;
char *p2;
char query_type;
+ int unit_size = gdbarch_addressable_memory_unit_size (target_gdbarch ());
set_remote_traceframe ();
set_general_thread (inferior_ptid);
return TARGET_XFER_EOF;
if (writebuf != NULL)
- return remote_write_bytes (offset, writebuf, len, xfered_len);
+ return remote_write_bytes (offset, writebuf, len, unit_size,
+ xfered_len);
else
- return remote_read_bytes (ops, offset, readbuf, len, xfered_len);
+ return remote_read_bytes (ops, offset, readbuf, len, unit_size,
+ xfered_len);
}
/* Handle SPU memory using qxfer packets. */
xfered_len,
&remote_protocol_packets[PACKET_qXfer_btrace]);
+ case TARGET_OBJECT_BTRACE_CONF:
+ return remote_read_qxfer (ops, "btrace-conf", annex, readbuf, offset,
+ len, xfered_len,
+ &remote_protocol_packets[PACKET_qXfer_btrace_conf]);
+
+ case TARGET_OBJECT_EXEC_FILE:
+ return remote_read_qxfer (ops, "exec-file", annex, readbuf, offset,
+ len, xfered_len,
+ &remote_protocol_packets[PACKET_qXfer_exec_file]);
+
default:
return TARGET_XFER_E_IO;
}
/* Escape as much data as fits into rs->buf. */
escaped_pattern_len =
- remote_escape_output (pattern, pattern_len, (gdb_byte *) rs->buf + i,
+ remote_escape_output (pattern, pattern_len, 1, (gdb_byte *) rs->buf + i,
&used_pattern_len, max_size);
/* Bail if the pattern is too large. */
if (ptid_equal (magic_null_ptid, ptid))
xsnprintf (buf, sizeof buf, "Thread <main>");
else if (rs->extended && remote_multi_process_p (rs))
- xsnprintf (buf, sizeof buf, "Thread %d.%ld",
- ptid_get_pid (ptid), ptid_get_lwp (ptid));
+ if (ptid_get_lwp (ptid) == 0)
+ return normal_pid_to_str (ptid);
+ else
+ xsnprintf (buf, sizeof buf, "Thread %d.%ld",
+ ptid_get_pid (ptid), ptid_get_lwp (ptid));
else
xsnprintf (buf, sizeof buf, "Thread %ld",
ptid_get_lwp (ptid));
return ret;
}
-/* Open FILENAME on the remote target, using FLAGS and MODE. Return a
- remote file descriptor, or -1 if an error occurs (and set
- *REMOTE_ERRNO). */
+/* Set the filesystem remote_hostio functions that take FILENAME
+ arguments will use. Return 0 on success, or -1 if an error
+ occurs (and set *REMOTE_ERRNO). */
+
+static int
+remote_hostio_set_filesystem (struct inferior *inf, int *remote_errno)
+{
+ struct remote_state *rs = get_remote_state ();
+ int required_pid = (inf == NULL || inf->fake_pid_p) ? 0 : inf->pid;
+ char *p = rs->buf;
+ int left = get_remote_packet_size () - 1;
+ char arg[9];
+ int ret;
+
+ if (packet_support (PACKET_vFile_setfs) == PACKET_DISABLE)
+ return 0;
+
+ if (rs->fs_pid != -1 && required_pid == rs->fs_pid)
+ return 0;
+
+ remote_buffer_add_string (&p, &left, "vFile:setfs:");
+
+ xsnprintf (arg, sizeof (arg), "%x", required_pid);
+ remote_buffer_add_string (&p, &left, arg);
+
+ ret = remote_hostio_send_command (p - rs->buf, PACKET_vFile_setfs,
+ remote_errno, NULL, NULL);
+
+ if (packet_support (PACKET_vFile_setfs) == PACKET_DISABLE)
+ return 0;
+
+ if (ret == 0)
+ rs->fs_pid = required_pid;
+
+ return ret;
+}
+
+/* Implementation of to_fileio_open. */
static int
remote_hostio_open (struct target_ops *self,
- const char *filename, int flags, int mode,
- int *remote_errno)
+ struct inferior *inf, const char *filename,
+ int flags, int mode, int *remote_errno)
{
struct remote_state *rs = get_remote_state ();
char *p = rs->buf;
int left = get_remote_packet_size () - 1;
+ if (remote_hostio_set_filesystem (inf, remote_errno) != 0)
+ return -1;
+
remote_buffer_add_string (&p, &left, "vFile:open:");
remote_buffer_add_bytes (&p, &left, (const gdb_byte *) filename,
remote_errno, NULL, NULL);
}
-/* Write up to LEN bytes from WRITE_BUF to FD on the remote target.
- Return the number of bytes written, or -1 if an error occurs (and
- set *REMOTE_ERRNO). */
+/* Implementation of to_fileio_pwrite. */
static int
remote_hostio_pwrite (struct target_ops *self,
remote_buffer_add_int (&p, &left, offset);
remote_buffer_add_string (&p, &left, ",");
- p += remote_escape_output (write_buf, len, (gdb_byte *) p, &out_len,
+ p += remote_escape_output (write_buf, len, 1, (gdb_byte *) p, &out_len,
get_remote_packet_size () - (p - rs->buf));
return remote_hostio_send_command (p - rs->buf, PACKET_vFile_pwrite,
remote_errno, NULL, NULL);
}
-/* Read up to LEN bytes FD on the remote target into READ_BUF
- Return the number of bytes read, or -1 if an error occurs (and
- set *REMOTE_ERRNO). */
+/* Implementation of to_fileio_pread. */
static int
remote_hostio_pread (struct target_ops *self,
return ret;
}
-/* Close FD on the remote target. Return 0, or -1 if an error occurs
- (and set *REMOTE_ERRNO). */
+/* Implementation of to_fileio_close. */
static int
remote_hostio_close (struct target_ops *self, int fd, int *remote_errno)
remote_errno, NULL, NULL);
}
-/* Unlink FILENAME on the remote target. Return 0, or -1 if an error
- occurs (and set *REMOTE_ERRNO). */
+/* Implementation of to_fileio_unlink. */
static int
remote_hostio_unlink (struct target_ops *self,
- const char *filename, int *remote_errno)
+ struct inferior *inf, const char *filename,
+ int *remote_errno)
{
struct remote_state *rs = get_remote_state ();
char *p = rs->buf;
int left = get_remote_packet_size () - 1;
+ if (remote_hostio_set_filesystem (inf, remote_errno) != 0)
+ return -1;
+
remote_buffer_add_string (&p, &left, "vFile:unlink:");
remote_buffer_add_bytes (&p, &left, (const gdb_byte *) filename,
remote_errno, NULL, NULL);
}
-/* Read value of symbolic link FILENAME on the remote target. Return
- a null-terminated string allocated via xmalloc, or NULL if an error
- occurs (and set *REMOTE_ERRNO). */
+/* Implementation of to_fileio_readlink. */
static char *
remote_hostio_readlink (struct target_ops *self,
- const char *filename, int *remote_errno)
+ struct inferior *inf, const char *filename,
+ int *remote_errno)
{
struct remote_state *rs = get_remote_state ();
char *p = rs->buf;
int read_len;
char *ret;
+ if (remote_hostio_set_filesystem (inf, remote_errno) != 0)
+ return NULL;
+
remote_buffer_add_string (&p, &left, "vFile:readlink:");
remote_buffer_add_bytes (&p, &left, (const gdb_byte *) filename,
return ret;
}
+/* Implementation of to_fileio_fstat. */
+
+static int
+remote_hostio_fstat (struct target_ops *self,
+ int fd, struct stat *st,
+ int *remote_errno)
+{
+ struct remote_state *rs = get_remote_state ();
+ char *p = rs->buf;
+ int left = get_remote_packet_size ();
+ int attachment_len, ret;
+ char *attachment;
+ struct fio_stat fst;
+ int read_len;
+
+ remote_buffer_add_string (&p, &left, "vFile:fstat:");
+
+ remote_buffer_add_int (&p, &left, fd);
+
+ ret = remote_hostio_send_command (p - rs->buf, PACKET_vFile_fstat,
+ remote_errno, &attachment,
+ &attachment_len);
+ if (ret < 0)
+ {
+ if (*remote_errno != FILEIO_ENOSYS)
+ return ret;
+
+ /* Strictly we should return -1, ENOSYS here, but when
+ "set sysroot remote:" was implemented in August 2008
+ BFD's need for a stat function was sidestepped with
+ this hack. This was not remedied until March 2015
+ so we retain the previous behavior to avoid breaking
+ compatibility.
+
+ Note that the memset is a March 2015 addition; older
+ GDBs set st_size *and nothing else* so the structure
+ would have garbage in all other fields. This might
+ break something but retaining the previous behavior
+ here would be just too wrong. */
+
+ memset (st, 0, sizeof (struct stat));
+ st->st_size = INT_MAX;
+ return 0;
+ }
+
+ read_len = remote_unescape_input ((gdb_byte *) attachment, attachment_len,
+ (gdb_byte *) &fst, sizeof (fst));
+
+ if (read_len != ret)
+ error (_("vFile:fstat returned %d, but %d bytes."), ret, read_len);
+
+ if (read_len != sizeof (fst))
+ error (_("vFile:fstat returned %d bytes, but expecting %d."),
+ read_len, (int) sizeof (fst));
+
+ remote_fileio_to_host_stat (&fst, st);
+
+ return 0;
+}
+
+/* Implementation of to_filesystem_is_local. */
+
+static int
+remote_filesystem_is_local (struct target_ops *self)
+{
+ /* Valgrind GDB presents itself as a remote target but works
+ on the local filesystem: it does not implement remote get
+ and users are not expected to set a sysroot. To handle
+ this case we treat the remote filesystem as local if the
+ sysroot is exactly TARGET_SYSROOT_PREFIX and if the stub
+ does not support vFile:open. */
+ if (gdb_sysroot != NULL
+ && strcmp (gdb_sysroot, TARGET_SYSROOT_PREFIX) == 0)
+ {
+ enum packet_support ps = packet_support (PACKET_vFile_open);
+
+ if (ps == PACKET_SUPPORT_UNKNOWN)
+ {
+ int fd, remote_errno;
+
+ /* Try opening a file to probe support. The supplied
+ filename is irrelevant, we only care about whether
+ the stub recognizes the packet or not. */
+ fd = remote_hostio_open (self, NULL, "just probing",
+ FILEIO_O_RDONLY, 0700,
+ &remote_errno);
+
+ if (fd >= 0)
+ remote_hostio_close (self, fd, &remote_errno);
+
+ ps = packet_support (PACKET_vFile_open);
+ }
+
+ if (ps == PACKET_DISABLE)
+ {
+ static int warning_issued = 0;
+
+ if (!warning_issued)
+ {
+ warning (_("remote target does not support file"
+ " transfer, attempting to access files"
+ " from local filesystem."));
+ warning_issued = 1;
+ }
+
+ return 1;
+ }
+ }
+
+ return 0;
+}
+
static int
remote_fileio_errno_to_host (int errnum)
{
remote_hostio_close (find_target_at (process_stratum), fd, &remote_errno);
}
-
-static void *
-remote_bfd_iovec_open (struct bfd *abfd, void *open_closure)
-{
- const char *filename = bfd_get_filename (abfd);
- int fd, remote_errno;
- int *stream;
-
- gdb_assert (remote_filename_p (filename));
-
- fd = remote_hostio_open (find_target_at (process_stratum),
- filename + 7, FILEIO_O_RDONLY, 0, &remote_errno);
- if (fd == -1)
- {
- errno = remote_fileio_errno_to_host (remote_errno);
- bfd_set_error (bfd_error_system_call);
- return NULL;
- }
-
- stream = xmalloc (sizeof (int));
- *stream = fd;
- return stream;
-}
-
-static int
-remote_bfd_iovec_close (struct bfd *abfd, void *stream)
-{
- int fd = *(int *)stream;
- int remote_errno;
-
- xfree (stream);
-
- /* Ignore errors on close; these may happen if the remote
- connection was already torn down. */
- remote_hostio_close (find_target_at (process_stratum), fd, &remote_errno);
-
- /* Zero means success. */
- return 0;
-}
-
-static file_ptr
-remote_bfd_iovec_pread (struct bfd *abfd, void *stream, void *buf,
- file_ptr nbytes, file_ptr offset)
-{
- int fd = *(int *)stream;
- int remote_errno;
- file_ptr pos, bytes;
-
- pos = 0;
- while (nbytes > pos)
- {
- bytes = remote_hostio_pread (find_target_at (process_stratum),
- fd, (gdb_byte *) buf + pos, nbytes - pos,
- offset + pos, &remote_errno);
- if (bytes == 0)
- /* Success, but no bytes, means end-of-file. */
- break;
- if (bytes == -1)
- {
- errno = remote_fileio_errno_to_host (remote_errno);
- bfd_set_error (bfd_error_system_call);
- return -1;
- }
-
- pos += bytes;
- }
-
- return pos;
-}
-
-static int
-remote_bfd_iovec_stat (struct bfd *abfd, void *stream, struct stat *sb)
-{
- /* FIXME: We should probably implement remote_hostio_stat. */
- sb->st_size = INT_MAX;
- return 0;
-}
-
-int
-remote_filename_p (const char *filename)
-{
- return strncmp (filename,
- REMOTE_SYSROOT_PREFIX,
- sizeof (REMOTE_SYSROOT_PREFIX) - 1) == 0;
-}
-
-bfd *
-remote_bfd_open (const char *remote_file, const char *target)
-{
- bfd *abfd = gdb_bfd_openr_iovec (remote_file, target,
- remote_bfd_iovec_open, NULL,
- remote_bfd_iovec_pread,
- remote_bfd_iovec_close,
- remote_bfd_iovec_stat);
-
- return abfd;
-}
-
void
remote_file_put (const char *local_file, const char *remote_file, int from_tty)
{
perror_with_name (local_file);
back_to = make_cleanup_fclose (file);
- fd = remote_hostio_open (find_target_at (process_stratum),
+ fd = remote_hostio_open (find_target_at (process_stratum), NULL,
remote_file, (FILEIO_O_WRONLY | FILEIO_O_CREAT
| FILEIO_O_TRUNC),
0700, &remote_errno);
if (!rs->remote_desc)
error (_("command can only be used with remote target"));
- fd = remote_hostio_open (find_target_at (process_stratum),
+ fd = remote_hostio_open (find_target_at (process_stratum), NULL,
remote_file, FILEIO_O_RDONLY, 0, &remote_errno);
if (fd == -1)
remote_hostio_error (remote_errno);
error (_("command can only be used with remote target"));
retcode = remote_hostio_unlink (find_target_at (process_stratum),
- remote_file, &remote_errno);
+ NULL, remote_file, &remote_errno);
if (retcode == -1)
remote_hostio_error (remote_errno);
char *p = NULL;
/* FIXME we need to get register block size some other way. */
extern int trace_regblock_size;
- volatile struct gdb_exception ex;
enum packet_result result;
if (packet_support (PACKET_qTStatus) == PACKET_DISABLE)
putpkt ("qTStatus");
- TRY_CATCH (ex, RETURN_MASK_ERROR)
+ TRY
{
p = remote_get_noisy_reply (&target_buf, &target_buf_size);
}
- if (ex.reason < 0)
+ CATCH (ex, RETURN_MASK_ERROR)
{
if (ex.error != TARGET_CLOSE_ERROR)
{
}
throw_exception (ex);
}
+ END_CATCH
result = packet_ok (p, &remote_protocol_packets[PACKET_qTStatus]);
{
struct thread_info *info = find_thread_ptid (ptid);
- if (info && info->private)
- return info->private->core;
+ if (info && info->priv)
+ return info->priv->core;
return -1;
}
{
/* The ptid of the traced thread. */
ptid_t ptid;
+
+ /* The obtained branch trace configuration. */
+ struct btrace_config conf;
};
+/* Reset our idea of our target's btrace configuration. */
+
+static void
+remote_btrace_reset (void)
+{
+ struct remote_state *rs = get_remote_state ();
+
+ memset (&rs->btrace_config, 0, sizeof (rs->btrace_config));
+}
+
/* Check whether the target supports branch tracing. */
static int
-remote_supports_btrace (struct target_ops *self)
+remote_supports_btrace (struct target_ops *self, enum btrace_format format)
{
if (packet_support (PACKET_Qbtrace_off) != PACKET_ENABLE)
return 0;
- if (packet_support (PACKET_Qbtrace_bts) != PACKET_ENABLE)
- return 0;
if (packet_support (PACKET_qXfer_btrace) != PACKET_ENABLE)
return 0;
- return 1;
+ switch (format)
+ {
+ case BTRACE_FORMAT_NONE:
+ return 0;
+
+ case BTRACE_FORMAT_BTS:
+ return (packet_support (PACKET_Qbtrace_bts) == PACKET_ENABLE);
+ }
+
+ internal_error (__FILE__, __LINE__, _("Unknown branch trace format"));
+}
+
+/* Synchronize the configuration with the target. */
+
+static void
+btrace_sync_conf (const struct btrace_config *conf)
+{
+ struct packet_config *packet;
+ struct remote_state *rs;
+ char *buf, *pos, *endbuf;
+
+ rs = get_remote_state ();
+ buf = rs->buf;
+ endbuf = buf + get_remote_packet_size ();
+
+ packet = &remote_protocol_packets[PACKET_Qbtrace_conf_bts_size];
+ if (packet_config_support (packet) == PACKET_ENABLE
+ && conf->bts.size != rs->btrace_config.bts.size)
+ {
+ pos = buf;
+ pos += xsnprintf (pos, endbuf - pos, "%s=0x%x", packet->name,
+ conf->bts.size);
+
+ putpkt (buf);
+ getpkt (&buf, &rs->buf_size, 0);
+
+ if (packet_ok (buf, packet) == PACKET_ERROR)
+ {
+ if (buf[0] == 'E' && buf[1] == '.')
+ error (_("Failed to configure the BTS buffer size: %s"), buf + 2);
+ else
+ error (_("Failed to configure the BTS buffer size."));
+ }
+
+ rs->btrace_config.bts.size = conf->bts.size;
+ }
+}
+
+/* Read the current thread's btrace configuration from the target and
+ store it into CONF. */
+
+static void
+btrace_read_config (struct btrace_config *conf)
+{
+ char *xml;
+
+ 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);
+ }
}
/* Enable branch tracing. */
static struct btrace_target_info *
-remote_enable_btrace (struct target_ops *self, ptid_t ptid)
+remote_enable_btrace (struct target_ops *self, ptid_t ptid,
+ const struct btrace_config *conf)
{
struct btrace_target_info *tinfo = NULL;
struct packet_config *packet = &remote_protocol_packets[PACKET_Qbtrace_bts];
if (packet_config_support (packet) != PACKET_ENABLE)
error (_("Target does not support branch tracing."));
+ btrace_sync_conf (conf);
+
set_general_thread (ptid);
buf += xsnprintf (buf, endbuf - buf, "%s", packet->name);
tinfo = xzalloc (sizeof (*tinfo));
tinfo->ptid = ptid;
+ /* If we fail to read the configuration, we lose some information, but the
+ tracing itself is not impacted. */
+ TRY
+ {
+ btrace_read_config (&tinfo->conf);
+ }
+ CATCH (err, RETURN_MASK_ERROR)
+ {
+ if (err.message != NULL)
+ warning ("%s", err.message);
+ }
+ END_CATCH
+
return tinfo;
}
static enum btrace_error
remote_read_btrace (struct target_ops *self,
- VEC (btrace_block_s) **btrace,
+ struct btrace_data *btrace,
struct btrace_target_info *tinfo,
enum btrace_read_type type)
{
return BTRACE_ERR_UNKNOWN;
cleanup = make_cleanup (xfree, xml);
- *btrace = parse_xml_btrace (xml);
+ parse_xml_btrace (btrace, xml);
do_cleanups (cleanup);
return BTRACE_ERR_NONE;
}
+static const struct btrace_config *
+remote_btrace_conf (struct target_ops *self,
+ const struct btrace_target_info *tinfo)
+{
+ return &tinfo->conf;
+}
+
static int
remote_augmented_libraries_svr4_read (struct target_ops *self)
{
generic_load (name, from_tty);
}
+/* Accepts an integer PID; returns a string representing a file that
+ can be opened on the remote side to get the symbols for the child
+ process. Returns NULL if the operation is not supported. */
+
+static char *
+remote_pid_to_exec_file (struct target_ops *self, int pid)
+{
+ static char *filename = NULL;
+ 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__,
+ _("not currently attached to process %d"), pid);
+
+ if (!inf->fake_pid_p)
+ {
+ const int annex_size = 9;
+
+ annex = alloca (annex_size);
+ xsnprintf (annex, annex_size, "%x", pid);
+ }
+
+ filename = target_read_stralloc (¤t_target,
+ TARGET_OBJECT_EXEC_FILE, annex);
+
+ return filename;
+}
+
static void
init_remote_ops (void)
{
remote_ops.to_files_info = remote_files_info;
remote_ops.to_insert_breakpoint = remote_insert_breakpoint;
remote_ops.to_remove_breakpoint = remote_remove_breakpoint;
+ remote_ops.to_stopped_by_sw_breakpoint = remote_stopped_by_sw_breakpoint;
+ remote_ops.to_supports_stopped_by_sw_breakpoint = remote_supports_stopped_by_sw_breakpoint;
+ remote_ops.to_stopped_by_hw_breakpoint = remote_stopped_by_hw_breakpoint;
+ remote_ops.to_supports_stopped_by_hw_breakpoint = remote_supports_stopped_by_hw_breakpoint;
remote_ops.to_stopped_by_watchpoint = remote_stopped_by_watchpoint;
remote_ops.to_stopped_data_address = remote_stopped_data_address;
remote_ops.to_watchpoint_addr_within_range =
remote_ops.to_pass_signals = remote_pass_signals;
remote_ops.to_program_signals = remote_program_signals;
remote_ops.to_thread_alive = remote_thread_alive;
- remote_ops.to_find_new_threads = remote_threads_info;
+ remote_ops.to_update_thread_list = remote_update_thread_list;
remote_ops.to_pid_to_str = remote_pid_to_str;
remote_ops.to_extra_thread_info = remote_threads_extra_info;
remote_ops.to_get_ada_task_ptid = remote_get_ada_task_ptid;
remote_ops.to_stop = remote_stop;
remote_ops.to_xfer_partial = remote_xfer_partial;
remote_ops.to_rcmd = remote_rcmd;
+ remote_ops.to_pid_to_exec_file = remote_pid_to_exec_file;
remote_ops.to_log_command = serial_log_command;
remote_ops.to_get_thread_local_address = remote_get_thread_local_address;
remote_ops.to_stratum = process_stratum;
remote_ops.to_supports_multi_process = remote_supports_multi_process;
remote_ops.to_supports_disable_randomization
= remote_supports_disable_randomization;
+ remote_ops.to_filesystem_is_local = remote_filesystem_is_local;
remote_ops.to_fileio_open = remote_hostio_open;
remote_ops.to_fileio_pwrite = remote_hostio_pwrite;
remote_ops.to_fileio_pread = remote_hostio_pread;
+ remote_ops.to_fileio_fstat = remote_hostio_fstat;
remote_ops.to_fileio_close = remote_hostio_close;
remote_ops.to_fileio_unlink = remote_hostio_unlink;
remote_ops.to_fileio_readlink = remote_hostio_readlink;
remote_ops.to_disable_btrace = remote_disable_btrace;
remote_ops.to_teardown_btrace = remote_teardown_btrace;
remote_ops.to_read_btrace = remote_read_btrace;
+ remote_ops.to_btrace_conf = remote_btrace_conf;
remote_ops.to_augmented_libraries_svr4_read =
remote_augmented_libraries_svr4_read;
}
extended_remote_ops.to_kill = extended_remote_kill;
extended_remote_ops.to_supports_disable_randomization
= extended_remote_supports_disable_randomization;
+ extended_remote_ops.to_follow_fork = remote_follow_fork;
+ extended_remote_ops.to_insert_fork_catchpoint
+ = remote_insert_fork_catchpoint;
+ extended_remote_ops.to_remove_fork_catchpoint
+ = remote_remove_fork_catchpoint;
+ extended_remote_ops.to_insert_vfork_catchpoint
+ = remote_insert_vfork_catchpoint;
+ extended_remote_ops.to_remove_vfork_catchpoint
+ = remote_remove_vfork_catchpoint;
}
static int
/* Don't propogate error information up to the client. Instead let
the client find out about the error by querying the target. */
- rs->async_client_callback (INF_REG_EVENT, rs->async_client_context);
+ inferior_event_handler (INF_REG_EVENT, NULL);
}
static void
}
static void
-remote_async (struct target_ops *ops,
- void (*callback) (enum inferior_event_type event_type,
- void *context),
- void *context)
+remote_async (struct target_ops *ops, int enable)
{
struct remote_state *rs = get_remote_state ();
- if (callback != NULL)
+ if (enable)
{
serial_async (rs->remote_desc, remote_async_serial_handler, rs);
- rs->async_client_callback = callback;
- rs->async_client_context = context;
+
+ /* If there are pending events in the stop reply queue tell the
+ event loop to process them. */
+ if (!QUEUE_is_empty (stop_reply_p, stop_reply_queue))
+ mark_async_event_handler (remote_async_inferior_event_token);
}
else
- serial_async (rs->remote_desc, NULL, NULL);
+ {
+ serial_async (rs->remote_desc, NULL, NULL);
+ clear_async_event_handler (remote_async_inferior_event_token);
+ }
}
static void
add_packet_config_cmd (&remote_protocol_packets[PACKET_qXfer_auxv],
"qXfer:auxv:read", "read-aux-vector", 0);
+ add_packet_config_cmd (&remote_protocol_packets[PACKET_qXfer_exec_file],
+ "qXfer:exec-file:read", "pid-to-exec-file", 0);
+
add_packet_config_cmd (&remote_protocol_packets[PACKET_qXfer_features],
"qXfer:features:read", "target-features", 0);
add_packet_config_cmd (&remote_protocol_packets[PACKET_qTStatus],
"qTStatus", "trace-status", 0);
+ add_packet_config_cmd (&remote_protocol_packets[PACKET_vFile_setfs],
+ "vFile:setfs", "hostio-setfs", 0);
+
add_packet_config_cmd (&remote_protocol_packets[PACKET_vFile_open],
"vFile:open", "hostio-open", 0);
add_packet_config_cmd (&remote_protocol_packets[PACKET_vFile_readlink],
"vFile:readlink", "hostio-readlink", 0);
+ add_packet_config_cmd (&remote_protocol_packets[PACKET_vFile_fstat],
+ "vFile:fstat", "hostio-fstat", 0);
+
add_packet_config_cmd (&remote_protocol_packets[PACKET_vAttach],
"vAttach", "attach", 0);
add_packet_config_cmd (&remote_protocol_packets[PACKET_qXfer_btrace],
"qXfer:btrace", "read-btrace", 0);
- /* Assert that we've registered commands for all packet configs. */
+ add_packet_config_cmd (&remote_protocol_packets[PACKET_qXfer_btrace_conf],
+ "qXfer:btrace-conf", "read-btrace-conf", 0);
+
+ add_packet_config_cmd (&remote_protocol_packets[PACKET_Qbtrace_conf_bts_size],
+ "Qbtrace-conf:bts:size", "btrace-conf-bts-size", 0);
+
+ add_packet_config_cmd (&remote_protocol_packets[PACKET_swbreak_feature],
+ "swbreak-feature", "swbreak-feature", 0);
+
+ add_packet_config_cmd (&remote_protocol_packets[PACKET_hwbreak_feature],
+ "hwbreak-feature", "hwbreak-feature", 0);
+
+ add_packet_config_cmd (&remote_protocol_packets[PACKET_fork_event_feature],
+ "fork-event-feature", "fork-event-feature", 0);
+
+ add_packet_config_cmd (&remote_protocol_packets[PACKET_vfork_event_feature],
+ "vfork-event-feature", "vfork-event-feature", 0);
+
+ /* Assert that we've registered "set remote foo-packet" commands
+ for all packet configs. */
{
int i;