diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo
index e98c15242bc..8ea8d96f73c 100644
--- a/gdb/doc/gdb.texinfo
+++ b/gdb/doc/gdb.texinfo
@@ -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
diff --git a/gdb/remote.c b/gdb/remote.c
index 72f14e28f54..d90e071f4fb 100644
--- a/gdb/remote.c
+++ b/gdb/remote.c
@@ -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.  */
   {
diff --git a/gdbserver/linux-low.cc b/gdbserver/linux-low.cc
index 444eebc6bbe..dc3d2629fdb 100644
--- a/gdbserver/linux-low.cc
+++ b/gdbserver/linux-low.cc
@@ -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)
 {
diff --git a/gdbserver/linux-low.h b/gdbserver/linux-low.h
index d34d2738238..dfbd079e223 100644
--- a/gdbserver/linux-low.h
+++ b/gdbserver/linux-low.h
@@ -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;
diff --git a/gdbserver/server.cc b/gdbserver/server.cc
index 74c7763d777..f9ce02a8594 100644
--- a/gdbserver/server.cc
+++ b/gdbserver/server.cc
@@ -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':
diff --git a/gdbserver/server.h b/gdbserver/server.h
index 0074818c6df..dacc5cb5d6f 100644
--- a/gdbserver/server.h
+++ b/gdbserver/server.h
@@ -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 ();
diff --git a/gdbserver/target.cc b/gdbserver/target.cc
index 23b699d33bb..f19edb67dc5 100644
--- a/gdbserver/target.cc
+++ b/gdbserver/target.cc
@@ -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 ()
 {
diff --git a/gdbserver/target.h b/gdbserver/target.h
index 3643b9110da..01d2882a7e1 100644
--- a/gdbserver/target.h
+++ b/gdbserver/target.h
@@ -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 ()
 
