@@ -23251,6 +23251,18 @@ If you specify the program to debug on the command line, then the
resume using commands like @kbd{step} and @kbd{continue} as with
@code{target remote} mode.
+When GDBserver is run locally using stdio, for example, with
+@w{@kbd{target remote | gdbserver - @var{inferior}}}, the inferior's
+@code{stdin} is closed, which means the inferior can't read any
+input.
+
+If GDBserver supports the default inferior file descriptors feature
+(@pxref{default inferior file descriptors}), it will start the
+inferior connected to the same terminal as @value{GDBN}, which
+enables the inferior to read from @code{stdin} and write to
+@code{stdout} and @code{stderr}, in the same way native targets do.
+
+
@anchor{Attaching in Types of Remote Connections}
@item Attaching
@strong{With target remote mode:} The @value{GDBN} command @code{attach} is
@@ -43114,6 +43126,36 @@ for success (@pxref{Stop Reply Packets})
@cindex @samp{vStopped} packet
@xref{Notification Packets}.
+@anchor{default inferior file descriptors}
+@cindex @samp{vDefaultInferiorFd} packet
+@item vDefaultInferiorFd;@var{fd0};@var{fd1};@var{fd2}
+@itemx vDefaultInferiorFd
+vDefaultInferiorFd packet contains the file descriptors of the same @code{stdin}/
+@code{stdout}/@code{stderr} @value{GDBN} is connected to. If GDBserver is run
+locally, it will accept the packet and will use the file descriptors sent by @value{GDBN}
+to start the inferior connected to the same @code{stdin}/@code{stdout}/@code{stderr}
+@value{GDBN} is connected to. This allows the inferior run under the local GDBserver
+to read from the @code{stdin} and write to @code{stdout}/@code{stderr}.
+This makes a remote target (which is run locally) to behave similarly to the native target.
+
+When this feature it not used, inferior is started with its @code{stdin} closed and its
+@code{stdout} is redirected to @code{stderr} @value{GDBN} is connected to.
+
+This packet is not probed by default; the remote stub must request it,
+by supplying an appropriate @samp{qSupported} response (@pxref{qSupported}).
+
+This packet is also available in extended mode (@pxref{extended mode}).
+This feature does not support @code{set inferior-tty} command.
+At the time of writing this feature only works on Linux.
+
+Reply:
+@table @samp
+@item OK
+for success
+@item E.errtext
+for an error
+@end table
+
@item X @var{addr},@var{length}:@var{XX@dots{}}
@anchor{X packet}
@cindex @samp{X} packet
@@ -305,6 +305,10 @@ enum {
packets and the tag violation stop replies. */
PACKET_memory_tagging_feature,
+ /* Support for connecting inferior to the same terminal as
+ GDB when running GDBserver locally. */
+ PACKET_vDefaultInferiorFd,
+
PACKET_MAX
};
@@ -726,6 +730,11 @@ struct remote_features
bool remote_memory_tagging_p () const
{ return packet_support (PACKET_memory_tagging_feature) == PACKET_ENABLE; }
+ /* Returns true if connecting inferior to the same terminal as GDB is
+ supported, false otherwise. */
+ bool remote_fd_switch_p () const
+ { return packet_support (PACKET_vDefaultInferiorFd) == PACKET_ENABLE; }
+
/* Reset all packets back to "unknown support". Called when opening a
new connection to a remote target. */
void reset_all_packet_configs_support ();
@@ -5016,6 +5025,18 @@ remote_target::start_remote_1 (int from_tty, int extended_p)
which later probes to skip. */
remote_query_supported ();
+ if (m_features.packet_support (PACKET_vDefaultInferiorFd) != PACKET_DISABLE
+ && rs->remote_desc->fds[0] != -1 && rs->remote_desc->fds[1] != -1
+ && rs->remote_desc->fds[2] != -1)
+ {
+ xsnprintf (rs->buf.data(), rs->buf.size (), "vDefaultInferiorFd;%d;%d;%d",
+ rs->remote_desc->fds[0], rs->remote_desc->fds[1],
+ rs->remote_desc->fds[2]);
+
+ putpkt (rs->buf);
+ getpkt (&rs->buf, 0);
+ }
+
/* Check vCont support and set the remote state's vCont_action_support
attribute. */
remote_vcont_probe ();
@@ -5723,6 +5744,7 @@ static const struct protocol_feature remote_protocol_features[] = {
{ "no-resumed", PACKET_DISABLE, remote_supported_packet, PACKET_no_resumed },
{ "memory-tagging", PACKET_DISABLE, remote_supported_packet,
PACKET_memory_tagging_feature },
+ { "vDefaultInferiorFd", PACKET_DISABLE, remote_supported_packet, PACKET_vDefaultInferiorFd },
};
static char *remote_support_xml;
@@ -5834,6 +5856,10 @@ remote_target::remote_query_supported ()
!= AUTO_BOOLEAN_FALSE)
remote_query_supported_append (&q, "memory-tagging+");
+ if (m_features.packet_set_cmd_state (PACKET_vDefaultInferiorFd)
+ != AUTO_BOOLEAN_FALSE)
+ remote_query_supported_append (&q, "vDefaultInferiorFd+");
+
/* Keep this one last to work around a gdbserver <= 7.10 bug in
the qSupported:xmlRegisters=i386 handling. */
if (remote_support_xml != NULL
@@ -15990,6 +16016,8 @@ Show the maximum size of the address (in bits) in a memory packet."), NULL,
add_packet_config_cmd (PACKET_memory_tagging_feature,
"memory-tagging-feature", "memory-tagging-feature", 0);
+ add_packet_config_cmd (PACKET_vDefaultInferiorFd, "vDefaultInferiorFd", "vDefaultInferiorFd", 0);
+
/* Assert that we've registered "set remote foo-packet" commands
for all packet configs. */
{
@@ -6199,6 +6199,12 @@ linux_process_target::low_supports_catch_syscall ()
return false;
}
+bool
+linux_process_target::supports_default_fds ()
+{
+ return true;
+}
+
CORE_ADDR
linux_process_target::read_pc (regcache *regcache)
{
@@ -322,6 +322,8 @@ class linux_process_target : public process_stratum_target
bool supports_catch_syscall () override;
+ bool supports_default_fds () override;
+
/* Return the information to access registers. This has public
visibility because proc-service uses it. */
virtual const regs_info *get_regs_info () = 0;
@@ -81,6 +81,12 @@ static bool extended_protocol;
static bool response_needed;
static bool exit_requested;
+/* To be able to connect the inferior to GDB's stdin/out/err,
+ when GDBserver is run locally, we need to wait with starting
+ the inferior to have time to recieve the vDefaultInferiorFd
+ packet. Set to true if need to postpone starting the inferior. */
+static bool deferred_inferior_startup = false;
+
/* --once: Exit after the first connection has closed. */
bool run_once;
@@ -171,6 +177,34 @@ get_client_state ()
return cs;
}
+int multi_mode = 0;
+
+/* To be able to connect the inferior to GDB's stdin/out/err,
+ when GDBserver is run locally, we need to wait with starting
+ the inferior to have time to recieve the vDefaultInferiorFd
+ packet.
+
+ Can only be called when deferred_inferior_startup is true.
+ Starts the inferior and throws an error if startup fails.
+ If startup is successful then deferred_inferior_startup is
+ reset to false. Throw an error on failure. */
+static void
+do_deferred_startup ()
+{
+ gdb_assert (deferred_inferior_startup);
+ client_state &cs = get_client_state ();
+ target_create_inferior (program_path.get (), program_args);
+
+ if (current_thread != nullptr)
+ current_process ()->dlls_changed = false;
+
+ if ((cs.last_status.kind () == TARGET_WAITKIND_EXITED
+ || cs.last_status.kind () == TARGET_WAITKIND_SIGNALLED)
+ && !multi_mode)
+ error ("No program to debug");
+
+ deferred_inferior_startup = false;
+}
/* Put a stop reply to the stop reply queue. */
@@ -2501,6 +2535,45 @@ supported_btrace_packets (char *buf)
strcat (buf, ";qXfer:btrace-conf:read+");
}
+/* Parse a vDefaultInferiorFd packet from pkt
+ and save the received file descriptors into
+ fds. Return true on success, false otherwise.
+ Set the file descriptors to -1 on failure. */
+static bool
+parse_vdefaultinf (const char *pkt, int *fds)
+{
+ char *end;
+ int ret = true;
+ errno = 0;
+
+ if (*pkt != '\0')
+ {
+ fds[0] = (int) strtoul (pkt, &end, 10);
+ if ((pkt == end) || (*end != ';'))
+ ret = false;
+ pkt = end + 1;
+ fds[1] = (int) strtoul (pkt, &end, 10);
+ if ((pkt == end) || (*end != ';'))
+ ret = false;
+ pkt = end + 1;
+ fds[2] = (int) strtoul (pkt, &end, 10);
+ if ((pkt == end) || (*end != '\0'))
+ ret = false;
+ if (errno != 0)
+ ret = false;
+ }
+ else
+ ret = false;
+ if (!ret)
+ {
+ fds[0] = -1;
+ fds[1] = -1;
+ fds[2] = -1;
+ }
+
+ return ret;
+}
+
/* Handle all of the extended 'q' packets. */
static void
@@ -2711,6 +2784,8 @@ handle_query (char *own_buf, int packet_len, int *new_packet_len_p)
if (target_supports_memory_tagging ())
cs.memory_tagging_feature = true;
}
+ else if (feature == "vDefaultInferiorFd+")
+ cs.vDefaultInferiorFd_supported = 1;
else
{
/* Move the unknown features all together. */
@@ -2840,6 +2915,18 @@ handle_query (char *own_buf, int packet_len, int *new_packet_len_p)
if (target_supports_memory_tagging ())
strcat (own_buf, ";memory-tagging+");
+ if (cs.vDefaultInferiorFd_supported)
+ {
+ /* If GDB didn't advertise vDefaultInferiorFd then we don't mention
+ vDefaultInferiorFd in the reply. If GDB did mention vDefaultInferiorFd
+ then we only claim support if we are started as an stdio target. */
+ if (remote_connection_is_stdio ()
+ && target_supports_default_fds ())
+ strcat (own_buf, ";vDefaultInferiorFd+");
+ else
+ strcat (own_buf, ";vDefaultInferiorFd-");
+ }
+
/* Reinitialize components as needed for the new connection. */
hostio_handle_new_gdb_connection ();
target_handle_new_gdb_connection ();
@@ -3543,6 +3630,19 @@ handle_v_requests (char *own_buf, int packet_len, int *new_packet_len)
return;
}
+ if (startswith (own_buf, "vDefaultInferiorFd;"))
+ {
+ if (!parse_vdefaultinf (own_buf + 19, cs.fds))
+ {
+ strcpy (own_buf, "E.invalid vDefaultInferiorFd packet");
+ return;
+ }
+
+ cs.vDefaultInferiorFd_accepted = true;
+ write_ok (own_buf);
+ return;
+ }
+
if (startswith (own_buf, "vKill;"))
{
if (!target_running ())
@@ -4038,7 +4138,6 @@ captured_main (int argc, char *argv[])
char *arg_end;
const char *port = NULL;
char **next_arg = &argv[1];
- volatile int multi_mode = 0;
volatile int attach = 0;
int was_running;
bool selftest = false;
@@ -4307,8 +4406,27 @@ captured_main (int argc, char *argv[])
for (i = 1; i < n; i++)
program_args.push_back (xstrdup (next_arg[i]));
- /* Wait till we are at first instruction in program. */
- target_create_inferior (program_path.get (), program_args);
+ if (remote_connection_is_stdio ())
+ {
+ /* Debugger might want to set the default inferior
+ in/out/err file descriptors, in which case we need to
+ defer starting the inferior until this information
+ arrives. */
+ deferred_inferior_startup = true;
+ multi_mode = 1;
+
+ /* Only used when reporting the first stop to GDB. This
+ should be replaced when we start the inferior, but lets
+ be on the safe side and set this now just so we carry
+ around a sane state. */
+ cs.last_status.set_exited (0);
+ cs.last_ptid = minus_one_ptid;
+ }
+ else
+ {
+ /* Wait till we are at first instruction in program. */
+ target_create_inferior (program_path.get (), program_args);
+ }
/* We are now (hopefully) stopped at the first instruction of
the target process. This assumes that the target process was
@@ -4358,6 +4476,7 @@ captured_main (int argc, char *argv[])
cs.hwbreak_feature = 0;
cs.vCont_supported = 0;
cs.memory_tagging_feature = false;
+ cs.vDefaultInferiorFd_supported = false;
remote_open (port);
@@ -4547,6 +4666,16 @@ process_serial_event (void)
response_needed = true;
char ch = cs.own_buf[0];
+ if (deferred_inferior_startup)
+ {
+ /* Actually start the inferior if not a qSupported or
+ vDefaultInferiorFd packet. vDefaultInferiorFd is
+ only accepted after qSupported and before any other
+ request. */
+ if (!startswith(cs.own_buf, "qSupported")
+ && !startswith(cs.own_buf, "vDefaultInferiorFd"))
+ do_deferred_startup ();
+ }
switch (ch)
{
case 'q':
@@ -192,6 +192,18 @@ struct client_state
/* If true, memory tagging features are supported. */
bool memory_tagging_feature = false;
+ /* If true, connecting the inferior to the terminal's
+ stdin/out/err when running GDBserver locally is supported. */
+ bool vDefaultInferiorFd_supported = false;
+
+ /* If true, GDBserver accepted file descriptors sent by GDB
+ and connecting the inferior to the same terminal as GDB
+ when running GDBserver locally is then supported. */
+ bool vDefaultInferiorFd_accepted = false;
+
+ /* File descriptors pointing to terminal's stdin/out/err
+ sent by GDB to GDBserver. */
+ int fds[3];
};
client_state &get_client_state ();
@@ -840,6 +840,12 @@ process_stratum_target::supports_catch_syscall ()
return false;
}
+bool
+process_stratum_target::supports_default_fds ()
+{
+ return false;
+}
+
int
process_stratum_target::get_ipa_tdesc_idx ()
{
@@ -497,6 +497,9 @@ class process_stratum_target
/* Return true if the target supports catch syscall. */
virtual bool supports_catch_syscall ();
+ /* Return true if the target supports vDefaultInferiorFd. */
+ virtual bool supports_default_fds ();
+
/* Return tdesc index for IPA. */
virtual int get_ipa_tdesc_idx ();
@@ -578,6 +581,9 @@ int kill_inferior (process_info *proc);
#define target_supports_catch_syscall() \
the_target->supports_catch_syscall ()
+#define target_supports_default_fds() \
+ the_target->supports_default_fds ()
+
#define target_get_ipa_tdesc_idx() \
the_target->get_ipa_tdesc_idx ()