diff --git a/gdb/Makefile.in b/gdb/Makefile.in
index 13627e07e0..a3b22c1134 100644
--- a/gdb/Makefile.in
+++ b/gdb/Makefile.in
@@ -430,6 +430,7 @@ SUBDIR_UNITTESTS_SRCS = \
 	unittests/offset-type-selftests.c \
 	unittests/observable-selftests.c \
 	unittests/optional-selftests.c \
+	unittests/parse-connection-spec-selftests.c \
 	unittests/ptid-selftests.c \
 	unittests/rsp-low-selftests.c \
 	unittests/scoped_fd-selftests.c \
@@ -967,6 +968,7 @@ COMMON_SFILES = \
 	common/job-control.c \
 	common/gdb_tilde_expand.c \
 	common/gdb_vecs.c \
+	common/netstuff.c \
 	common/new-op.c \
 	common/pathstuff.c \
 	common/print-utils.c \
@@ -1448,6 +1450,7 @@ HFILES_NO_SRCDIR = \
 	common/gdb_vecs.h \
 	common/gdb_wait.h \
 	common/common-inferior.h \
+	common/netstuff.h \
 	common/host-defs.h \
 	common/pathstuff.h \
 	common/print-utils.h \
diff --git a/gdb/NEWS b/gdb/NEWS
index 2d1d161233..acb9c34fb2 100644
--- a/gdb/NEWS
+++ b/gdb/NEWS
@@ -3,6 +3,10 @@
 
 *** Changes since GDB 8.2
 
+* GDB and GDBserver now support IPv6 connections.  IPv6 addresses
+  can be passed using the '[ADDRESS]:PORT' notation, or the regular
+  'ADDRESS:PORT' method.
+
 *** Changes in GDB 8.2
 
 * The 'set disassembler-options' command now supports specifying options
diff --git a/gdb/common/netstuff.c b/gdb/common/netstuff.c
new file mode 100644
index 0000000000..c1c401ccb2
--- /dev/null
+++ b/gdb/common/netstuff.c
@@ -0,0 +1,155 @@
+/* Operations on network stuff.
+   Copyright (C) 2018 Free Software Foundation, Inc.
+
+   This file is part of GDB.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+#include "common-defs.h"
+#include "netstuff.h"
+#include <algorithm>
+
+#ifdef USE_WIN32API
+#include <winsock2.h>
+#include <wspiapi.h>
+#else
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+#include <sys/socket.h>
+#include <netinet/tcp.h>
+#endif
+
+/* See common/netstuff.h.  */
+
+scoped_free_addrinfo::~scoped_free_addrinfo ()
+{
+  freeaddrinfo (m_res);
+}
+
+/* See common/netstuff.h.  */
+
+parsed_connection_spec
+parse_connection_spec_without_prefix (std::string spec, struct addrinfo *hint)
+{
+  parsed_connection_spec ret;
+  size_t last_colon_pos = 0;
+  /* We're dealing with IPv6 if:
+
+     - ai_family is AF_INET6, or
+     - ai_family is not AF_INET, and
+       - spec[0] is '[', or
+       - the number of ':' on spec is greater than 1.  */
+  bool is_ipv6 = (hint->ai_family == AF_INET6
+		  || (hint->ai_family != AF_INET
+		      && (spec[0] == '['
+			  || std::count (spec.begin (),
+					 spec.end (), ':') > 1)));
+
+  if (is_ipv6)
+    {
+      if (spec[0] == '[')
+	{
+	  /* IPv6 addresses can be written as '[ADDR]:PORT', and we
+	     support this notation.  */
+	  size_t close_bracket_pos = spec.find_first_of (']');
+
+	  if (close_bracket_pos == std::string::npos)
+	    error (_("Missing close bracket in hostname '%s'"),
+		   spec.c_str ());
+
+	  hint->ai_family = AF_INET6;
+
+	  const char c = spec[close_bracket_pos + 1];
+
+	  if (c == '\0')
+	    last_colon_pos = std::string::npos;
+	  else if (c != ':')
+	    error (_("Invalid cruft after close bracket in '%s'"),
+		   spec.c_str ());
+
+	  /* Erase both '[' and ']'.  */
+	  spec.erase (0, 1);
+	  spec.erase (close_bracket_pos - 1, 1);
+	}
+      else if (spec.find_first_of (']') != std::string::npos)
+	error (_("Missing open bracket in hostname '%s'"),
+	       spec.c_str ());
+    }
+
+  if (last_colon_pos == 0)
+    last_colon_pos = spec.find_last_of (':');
+
+  /* The length of the hostname part.  */
+  size_t host_len;
+
+  if (last_colon_pos != std::string::npos)
+    {
+      /* The user has provided a port.  */
+      host_len = last_colon_pos;
+      ret.port_str = spec.substr (last_colon_pos + 1);
+    }
+  else
+    host_len = spec.size ();
+
+  ret.host_str = spec.substr (0, host_len);
+
+  /* Default hostname is localhost.  */
+  if (ret.host_str.empty ())
+    ret.host_str = "localhost";
+
+  return ret;
+}
+
+/* See common/netstuff.h.  */
+
+parsed_connection_spec
+parse_connection_spec (const char *spec, struct addrinfo *hint)
+{
+  /* Struct to hold the association between valid prefixes, their
+     family and socktype.  */
+  struct host_prefix
+    {
+      /* The prefix.  */
+      const char *prefix;
+
+      /* The 'ai_family'.  */
+      int family;
+
+      /* The 'ai_socktype'.  */
+      int socktype;
+    };
+  static const struct host_prefix prefixes[] =
+    {
+      { "udp:",  AF_UNSPEC, SOCK_DGRAM },
+      { "tcp:",  AF_UNSPEC, SOCK_STREAM },
+      { "udp4:", AF_INET,   SOCK_DGRAM },
+      { "tcp4:", AF_INET,   SOCK_STREAM },
+      { "udp6:", AF_INET6,  SOCK_DGRAM },
+      { "tcp6:", AF_INET6,  SOCK_STREAM },
+    };
+
+  for (const host_prefix prefix : prefixes)
+    if (startswith (spec, prefix.prefix))
+      {
+	spec += strlen (prefix.prefix);
+	hint->ai_family = prefix.family;
+	hint->ai_socktype = prefix.socktype;
+	hint->ai_protocol
+	  = hint->ai_socktype == SOCK_DGRAM ? IPPROTO_UDP : IPPROTO_TCP;
+	break;
+      }
+
+  return parse_connection_spec_without_prefix (spec, hint);
+}
diff --git a/gdb/common/netstuff.h b/gdb/common/netstuff.h
new file mode 100644
index 0000000000..17deb3fa87
--- /dev/null
+++ b/gdb/common/netstuff.h
@@ -0,0 +1,76 @@
+/* Operations on network stuff.
+   Copyright (C) 2018 Free Software Foundation, Inc.
+
+   This file is part of GDB.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+#ifndef NETSTUFF_H
+#define NETSTUFF_H
+
+#include <string>
+
+/* Like NI_MAXHOST/NI_MAXSERV, but enough for numeric forms.  */
+#define GDB_NI_MAX_ADDR 64
+#define GDB_NI_MAX_PORT 16
+
+/* Helper class to guarantee that we always call 'freeaddrinfo'.  */
+
+class scoped_free_addrinfo
+{
+public:
+  /* Default constructor.  */
+  scoped_free_addrinfo (struct addrinfo *ainfo)
+    : m_res (ainfo)
+  {
+  }
+
+  /* Destructor responsible for free'ing M_RES by calling
+     'freeaddrinfo'.  */
+  ~scoped_free_addrinfo ();
+
+  DISABLE_COPY_AND_ASSIGN (scoped_free_addrinfo);
+
+private:
+  /* The addrinfo resource.  */
+  struct addrinfo *m_res;
+};
+
+/* The struct we return after parsing the connection spec.  */
+
+struct parsed_connection_spec
+{
+  /* The hostname.  */
+  std::string host_str;
+
+  /* The port, if any.  */
+  std::string port_str;
+};
+
+
+/* Parse SPEC (which is a string in the form of "ADDR:PORT") and
+   return a 'parsed_connection_spec' structure with the proper fields
+   filled in.  Also adjust HINT accordingly.  */
+extern parsed_connection_spec
+  parse_connection_spec_without_prefix (std::string spec,
+					struct addrinfo *hint);
+
+/* Parse SPEC (which is a string in the form of
+   "[tcp[6]:|udp[6]:]ADDR:PORT") and return a 'parsed_connection_spec'
+   structure with the proper fields filled in.  Also adjust HINT
+   accordingly.  */
+extern parsed_connection_spec parse_connection_spec (const char *spec,
+						     struct addrinfo *hint);
+
+#endif /* ! NETSTUFF_H */
diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo
index 91ec219958..cd472ce5b5 100644
--- a/gdb/doc/gdb.texinfo
+++ b/gdb/doc/gdb.texinfo
@@ -20517,16 +20517,27 @@ If you're using a serial line, you may want to give @value{GDBN} the
 @code{target} command.
 
 @item target remote @code{@var{host}:@var{port}}
+@itemx target remote @code{@var{[host]}:@var{port}}
 @itemx target remote @code{tcp:@var{host}:@var{port}}
+@itemx target remote @code{tcp:@var{[host]}:@var{port}}
+@itemx target remote @code{tcp4:@var{host}:@var{port}}
+@itemx target remote @code{tcp6:@var{host}:@var{port}}
+@itemx target remote @code{tcp6:@var{[host]}:@var{port}}
 @itemx target extended-remote @code{@var{host}:@var{port}}
+@itemx target extended-remote @code{@var{[host]}:@var{port}}
 @itemx target extended-remote @code{tcp:@var{host}:@var{port}}
+@itemx target extended-remote @code{tcp:@var{[host]}:@var{port}}
+@itemx target extended-remote @code{tcp4:@var{host}:@var{port}}
+@itemx target extended-remote @code{tcp6:@var{host}:@var{port}}
+@itemx target extended-remote @code{tcp6:@var{[host]}:@var{port}}
 @cindex @acronym{TCP} port, @code{target remote}
 Debug using a @acronym{TCP} connection to @var{port} on @var{host}.
-The @var{host} may be either a host name or a numeric @acronym{IP}
-address; @var{port} must be a decimal number.  The @var{host} could be
-the target machine itself, if it is directly connected to the net, or
-it might be a terminal server which in turn has a serial line to the
-target.
+The @var{host} may be either a host name, a numeric @acronym{IPv4}
+address, or a numeric @acronym{IPv6} address (with or without the
+square brackets to separate the address from the port); @var{port}
+must be a decimal number.  The @var{host} could be the target machine
+itself, if it is directly connected to the net, or it might be a
+terminal server which in turn has a serial line to the target.
 
 For example, to connect to port 2828 on a terminal server named
 @code{manyfarms}:
@@ -20535,6 +20546,28 @@ For example, to connect to port 2828 on a terminal server named
 target remote manyfarms:2828
 @end smallexample
 
+To connect to port 2828 on a terminal server whose address is
+@code{2001:0db8:85a3:0000:0000:8a2e:0370:7334}, you can either use the
+square bracket syntax:
+
+@smallexample
+target remote [2001:0db8:85a3:0000:0000:8a2e:0370:7334]:2828
+@end smallexample
+
+@noindent
+or explicitly specify the @acronym{IPv6} protocol:
+
+@smallexample
+target remote tcp6:2001:0db8:85a3:0000:0000:8a2e:0370:7334:2828
+@end smallexample
+
+This last example may be confusing to the reader, because there is no
+visible separation between the hostname and the port number.
+Therefore, we recommend the user to provide @acronym{IPv6} addresses
+using square brackets for clarity.  However, it is important to
+mention that for @value{GDBN} there is no ambiguity: the number after
+the last colon is considered to be the port number.
+
 If your remote target is actually running on the same machine as your
 debugger session (e.g.@: a simulator for your target running on the
 same host), you can omit the hostname.  For example, to connect to
@@ -20548,7 +20581,15 @@ target remote :1234
 Note that the colon is still required here.
 
 @item target remote @code{udp:@var{host}:@var{port}}
+@itemx target remote @code{udp:@var{[host]}:@var{port}}
+@itemx target remote @code{udp4:@var{host}:@var{port}}
+@itemx target remote @code{udp6:@var{[host]}:@var{port}}
+@itemx target extended-remote @code{udp:@var{host}:@var{port}}
 @itemx target extended-remote @code{udp:@var{host}:@var{port}}
+@itemx target extended-remote @code{udp:@var{[host]}:@var{port}}
+@itemx target extended-remote @code{udp4:@var{host}:@var{port}}
+@itemx target extended-remote @code{udp6:@var{host}:@var{port}}
+@itemx target extended-remote @code{udp6:@var{[host]}:@var{port}}
 @cindex @acronym{UDP} port, @code{target remote}
 Debug using @acronym{UDP} packets to @var{port} on @var{host}.  For example, to
 connect to @acronym{UDP} port 2828 on a terminal server named @code{manyfarms}:
diff --git a/gdb/gdbserver/Makefile.in b/gdb/gdbserver/Makefile.in
index 513f286289..f2f8a084bd 100644
--- a/gdb/gdbserver/Makefile.in
+++ b/gdb/gdbserver/Makefile.in
@@ -211,6 +211,7 @@ SFILES = \
 	$(srcdir)/common/job-control.c \
 	$(srcdir)/common/gdb_tilde_expand.c \
 	$(srcdir)/common/gdb_vecs.c \
+	$(srcdir)/common/netstuff.c \
 	$(srcdir)/common/new-op.c \
 	$(srcdir)/common/pathstuff.c \
 	$(srcdir)/common/print-utils.c \
@@ -254,6 +255,7 @@ OBS = \
 	common/format.o \
 	common/gdb_tilde_expand.o \
 	common/gdb_vecs.o \
+	common/netstuff.o \
 	common/new-op.o \
 	common/pathstuff.o \
 	common/print-utils.o \
@@ -290,6 +292,7 @@ GDBREPLAY_OBS = \
 	common/common-exceptions.o \
 	common/common-utils.o \
 	common/errors.o \
+	common/netstuff.o \
 	common/print-utils.o \
 	gdbreplay.o \
 	utils.o \
diff --git a/gdb/gdbserver/gdbreplay.c b/gdb/gdbserver/gdbreplay.c
index a4bc892462..026bbfccaf 100644
--- a/gdb/gdbserver/gdbreplay.c
+++ b/gdb/gdbserver/gdbreplay.c
@@ -46,8 +46,11 @@
 
 #if USE_WIN32API
 #include <winsock2.h>
+#include <wspiapi.h>
 #endif
 
+#include "netstuff.h"
+
 #ifndef HAVE_SOCKLEN_T
 typedef int socklen_t;
 #endif
@@ -142,56 +145,108 @@ remote_close (void)
 static void
 remote_open (char *name)
 {
-  if (!strchr (name, ':'))
+  char *last_colon = strrchr (name, ':');
+
+  if (last_colon == NULL)
     {
       fprintf (stderr, "%s: Must specify tcp connection as host:addr\n", name);
       fflush (stderr);
       exit (1);
     }
-  else
-    {
+
 #ifdef USE_WIN32API
-      static int winsock_initialized;
+  static int winsock_initialized;
 #endif
-      char *port_str;
-      int port;
-      struct sockaddr_in sockaddr;
-      socklen_t tmp;
-      int tmp_desc;
+  char *port_str;
+  int tmp;
+  int tmp_desc;
+  struct addrinfo hint;
+  struct addrinfo *ainfo;
 
-      port_str = strchr (name, ':');
+  memset (&hint, 0, sizeof (hint));
+  /* Assume no prefix will be passed, therefore we should use
+     AF_UNSPEC.  */
+  hint.ai_family = AF_UNSPEC;
+  hint.ai_socktype = SOCK_STREAM;
+  hint.ai_protocol = IPPROTO_TCP;
 
-      port = atoi (port_str + 1);
+  parsed_connection_spec parsed = parse_connection_spec (name, &hint);
+
+  if (parsed.port_str.empty ())
+    error (_("Missing port on hostname '%s'"), name);
 
 #ifdef USE_WIN32API
-      if (!winsock_initialized)
-	{
-	  WSADATA wsad;
+  if (!winsock_initialized)
+    {
+      WSADATA wsad;
 
-	  WSAStartup (MAKEWORD (1, 0), &wsad);
-	  winsock_initialized = 1;
-	}
+      WSAStartup (MAKEWORD (1, 0), &wsad);
+      winsock_initialized = 1;
+    }
 #endif
 
-      tmp_desc = socket (PF_INET, SOCK_STREAM, 0);
-      if (tmp_desc == -1)
-	perror_with_name ("Can't open socket");
+  int r = getaddrinfo (parsed.host_str.c_str (), parsed.port_str.c_str (),
+		       &hint, &ainfo);
 
-      /* Allow rapid reuse of this port. */
-      tmp = 1;
-      setsockopt (tmp_desc, SOL_SOCKET, SO_REUSEADDR, (char *) &tmp,
-		  sizeof (tmp));
+  if (r != 0)
+    {
+      fprintf (stderr, "%s:%s: cannot resolve name: %s\n",
+	       parsed.host_str.c_str (), parsed.port_str.c_str (),
+	       gai_strerror (r));
+      fflush (stderr);
+      exit (1);
+    }
+
+  scoped_free_addrinfo free_ainfo (ainfo);
+
+  struct addrinfo *p;
+
+  for (p = ainfo; p != NULL; p = p->ai_next)
+    {
+      tmp_desc = socket (p->ai_family, p->ai_socktype, p->ai_protocol);
 
-      sockaddr.sin_family = PF_INET;
-      sockaddr.sin_port = htons (port);
-      sockaddr.sin_addr.s_addr = INADDR_ANY;
+      if (tmp_desc >= 0)
+	break;
+    }
+
+  if (p == NULL)
+    perror_with_name ("Cannot open socket");
 
-      if (bind (tmp_desc, (struct sockaddr *) &sockaddr, sizeof (sockaddr))
-	  || listen (tmp_desc, 1))
-	perror_with_name ("Can't bind address");
+  /* Allow rapid reuse of this port. */
+  tmp = 1;
+  setsockopt (tmp_desc, SOL_SOCKET, SO_REUSEADDR, (char *) &tmp,
+	      sizeof (tmp));
+
+  switch (p->ai_family)
+    {
+    case AF_INET:
+      ((struct sockaddr_in *) p->ai_addr)->sin_addr.s_addr = INADDR_ANY;
+      break;
+    case AF_INET6:
+      ((struct sockaddr_in6 *) p->ai_addr)->sin6_addr = in6addr_any;
+      break;
+    default:
+      fprintf (stderr, "Invalid 'ai_family' %d\n", p->ai_family);
+      exit (1);
+    }
+
+  if (bind (tmp_desc, p->ai_addr, p->ai_addrlen) != 0)
+    perror_with_name ("Can't bind address");
+
+  if (p->ai_socktype == SOCK_DGRAM)
+    remote_desc = tmp_desc;
+  else
+    {
+      struct sockaddr_storage sockaddr;
+      socklen_t sockaddrsize = sizeof (sockaddr);
+      char orig_host[GDB_NI_MAX_ADDR], orig_port[GDB_NI_MAX_PORT];
+
+      if (listen (tmp_desc, 1) != 0)
+	perror_with_name ("Can't listen on socket");
+
+      remote_desc = accept (tmp_desc, (struct sockaddr *) &sockaddr,
+			    &sockaddrsize);
 
-      tmp = sizeof (sockaddr);
-      remote_desc = accept (tmp_desc, (struct sockaddr *) &sockaddr, &tmp);
       if (remote_desc == -1)
 	perror_with_name ("Accept failed");
 
@@ -206,6 +261,16 @@ remote_open (char *name)
       setsockopt (remote_desc, IPPROTO_TCP, TCP_NODELAY,
 		  (char *) &tmp, sizeof (tmp));
 
+      if (getnameinfo ((struct sockaddr *) &sockaddr, sockaddrsize,
+		       orig_host, sizeof (orig_host),
+		       orig_port, sizeof (orig_port),
+		       NI_NUMERICHOST | NI_NUMERICSERV) == 0)
+	{
+	  fprintf (stderr, "Remote debugging from host %s, port %s\n",
+		   orig_host, orig_port);
+	  fflush (stderr);
+	}
+
 #ifndef USE_WIN32API
       close (tmp_desc);		/* No longer need this */
 
diff --git a/gdb/gdbserver/remote-utils.c b/gdb/gdbserver/remote-utils.c
index 45d5c8d451..1734c54e39 100644
--- a/gdb/gdbserver/remote-utils.c
+++ b/gdb/gdbserver/remote-utils.c
@@ -26,6 +26,8 @@
 #include "dll.h"
 #include "rsp-low.h"
 #include "gdbthread.h"
+#include "netstuff.h"
+#include "filestuff.h"
 #include <ctype.h>
 #if HAVE_SYS_IOCTL_H
 #include <sys/ioctl.h>
@@ -63,6 +65,7 @@
 
 #if USE_WIN32API
 #include <winsock2.h>
+#include <wspiapi.h>
 #endif
 
 #if __QNX__
@@ -151,19 +154,18 @@ enable_async_notification (int fd)
 static int
 handle_accept_event (int err, gdb_client_data client_data)
 {
-  struct sockaddr_in sockaddr;
-  socklen_t tmp;
+  struct sockaddr_storage sockaddr;
+  socklen_t len = sizeof (sockaddr);
 
   if (debug_threads)
     debug_printf ("handling possible accept event\n");
 
-  tmp = sizeof (sockaddr);
-  remote_desc = accept (listen_desc, (struct sockaddr *) &sockaddr, &tmp);
+  remote_desc = accept (listen_desc, (struct sockaddr *) &sockaddr, &len);
   if (remote_desc == -1)
     perror_with_name ("Accept failed");
 
   /* Enable TCP keep alive process. */
-  tmp = 1;
+  socklen_t tmp = 1;
   setsockopt (remote_desc, SOL_SOCKET, SO_KEEPALIVE,
 	      (char *) &tmp, sizeof (tmp));
 
@@ -192,8 +194,19 @@ handle_accept_event (int err, gdb_client_data client_data)
   delete_file_handler (listen_desc);
 
   /* Convert IP address to string.  */
-  fprintf (stderr, "Remote debugging from host %s\n",
-	   inet_ntoa (sockaddr.sin_addr));
+  char orig_host[GDB_NI_MAX_ADDR], orig_port[GDB_NI_MAX_PORT];
+
+  int r = getnameinfo ((struct sockaddr *) &sockaddr, len,
+		       orig_host, sizeof (orig_host),
+		       orig_port, sizeof (orig_port),
+		       NI_NUMERICHOST | NI_NUMERICSERV);
+
+  if (r != 0)
+    fprintf (stderr, _("Could not obtain remote address: %s\n"),
+	     gai_strerror (r));
+  else
+    fprintf (stderr, _("Remote debugging from host %s, port %s\n"),
+	     orig_host, orig_port);
 
   enable_async_notification (remote_desc);
 
@@ -222,10 +235,7 @@ remote_prepare (const char *name)
 #ifdef USE_WIN32API
   static int winsock_initialized;
 #endif
-  int port;
-  struct sockaddr_in sockaddr;
   socklen_t tmp;
-  char *port_end;
 
   remote_is_stdio = 0;
   if (strcmp (name, STDIO_CONNECTION_NAME) == 0)
@@ -238,17 +248,25 @@ remote_prepare (const char *name)
       return;
     }
 
-  port_str = strchr (name, ':');
-  if (port_str == NULL)
+  struct addrinfo hint;
+  struct addrinfo *ainfo;
+
+  memset (&hint, 0, sizeof (hint));
+  /* Assume no prefix will be passed, therefore we should use
+     AF_UNSPEC.  */
+  hint.ai_family = AF_UNSPEC;
+  hint.ai_socktype = SOCK_STREAM;
+  hint.ai_protocol = IPPROTO_TCP;
+
+  parsed_connection_spec parsed
+    = parse_connection_spec_without_prefix (name, &hint);
+
+  if (parsed.port_str.empty ())
     {
       cs.transport_is_reliable = 0;
       return;
     }
 
-  port = strtoul (port_str + 1, &port_end, 10);
-  if (port_str[1] == '\0' || *port_end != '\0')
-    error ("Bad port argument: %s", name);
-
 #ifdef USE_WIN32API
   if (!winsock_initialized)
     {
@@ -259,8 +277,26 @@ remote_prepare (const char *name)
     }
 #endif
 
-  listen_desc = socket (PF_INET, SOCK_STREAM, IPPROTO_TCP);
-  if (listen_desc == -1)
+  int r = getaddrinfo (parsed.host_str.c_str (), parsed.port_str.c_str (),
+		       &hint, &ainfo);
+
+  if (r != 0)
+    error (_("%s: cannot resolve name: %s"), name, gai_strerror (r));
+
+  scoped_free_addrinfo freeaddrinfo (ainfo);
+
+  struct addrinfo *iter;
+
+  for (iter = ainfo; iter != NULL; iter = iter->ai_next)
+    {
+      listen_desc = gdb_socket_cloexec (iter->ai_family, iter->ai_socktype,
+					iter->ai_protocol);
+
+      if (listen_desc >= 0)
+	break;
+    }
+
+  if (iter == NULL)
     perror_with_name ("Can't open socket");
 
   /* Allow rapid reuse of this port. */
@@ -268,14 +304,25 @@ remote_prepare (const char *name)
   setsockopt (listen_desc, SOL_SOCKET, SO_REUSEADDR, (char *) &tmp,
 	      sizeof (tmp));
 
-  sockaddr.sin_family = PF_INET;
-  sockaddr.sin_port = htons (port);
-  sockaddr.sin_addr.s_addr = INADDR_ANY;
+  switch (iter->ai_family)
+    {
+    case AF_INET:
+      ((struct sockaddr_in *) iter->ai_addr)->sin_addr.s_addr = INADDR_ANY;
+      break;
+    case AF_INET6:
+      ((struct sockaddr_in6 *) iter->ai_addr)->sin6_addr = in6addr_any;
+      break;
+    default:
+      internal_error (__FILE__, __LINE__,
+		      _("Invalid 'ai_family' %d\n"), iter->ai_family);
+    }
 
-  if (bind (listen_desc, (struct sockaddr *) &sockaddr, sizeof (sockaddr))
-      || listen (listen_desc, 1))
+  if (bind (listen_desc, iter->ai_addr, iter->ai_addrlen) != 0)
     perror_with_name ("Can't bind address");
 
+  if (listen (listen_desc, 1) != 0)
+    perror_with_name ("Can't listen on socket");
+
   cs.transport_is_reliable = 1;
 }
 
@@ -350,18 +397,24 @@ remote_open (const char *name)
 #endif /* USE_WIN32API */
   else
     {
-      int port;
-      socklen_t len;
-      struct sockaddr_in sockaddr;
-
-      len = sizeof (sockaddr);
-      if (getsockname (listen_desc,
-		       (struct sockaddr *) &sockaddr, &len) < 0
-	  || len < sizeof (sockaddr))
+      char listen_port[GDB_NI_MAX_PORT];
+      struct sockaddr_storage sockaddr;
+      socklen_t len = sizeof (sockaddr);
+
+      if (getsockname (listen_desc, (struct sockaddr *) &sockaddr, &len) < 0)
 	perror_with_name ("Can't determine port");
-      port = ntohs (sockaddr.sin_port);
 
-      fprintf (stderr, "Listening on port %d\n", port);
+      int r = getnameinfo ((struct sockaddr *) &sockaddr, len,
+			   NULL, 0,
+			   listen_port, sizeof (listen_port),
+			   NI_NUMERICSERV);
+
+      if (r != 0)
+	fprintf (stderr, _("Can't obtain port where we are listening: %s"),
+		 gai_strerror (r));
+      else
+	fprintf (stderr, _("Listening on port %s\n"), listen_port);
+
       fflush (stderr);
 
       /* Register the event loop handler.  */
diff --git a/gdb/ser-tcp.c b/gdb/ser-tcp.c
index 23ef3b04b8..fdb3afefbf 100644
--- a/gdb/ser-tcp.c
+++ b/gdb/ser-tcp.c
@@ -25,6 +25,7 @@
 #include "cli/cli-decode.h"
 #include "cli/cli-setshow.h"
 #include "filestuff.h"
+#include "netstuff.h"
 
 #include <sys/types.h>
 
@@ -39,6 +40,7 @@
 
 #ifdef USE_WIN32API
 #include <winsock2.h>
+#include <wspiapi.h>
 #ifndef ETIMEDOUT
 #define ETIMEDOUT WSAETIMEDOUT
 #endif
@@ -81,12 +83,13 @@ static unsigned int tcp_retry_limit = 15;
 
 #define POLL_INTERVAL 5
 
-/* Helper function to wait a while.  If SCB is non-null, wait on its
-   file descriptor.  Otherwise just wait on a timeout, updating *POLLS.
-   Returns -1 on timeout or interrupt, otherwise the value of select.  */
+/* Helper function to wait a while.  If SOCK is defined, wait on its
+   file descriptor.  Otherwise just wait on a timeout, updating
+   *POLLS.  Returns -1 on timeout or interrupt, otherwise the value of
+   select.  */
 
 static int
-wait_for_connect (struct serial *scb, unsigned int *polls)
+wait_for_connect (gdb::optional<int> sock, unsigned int *polls)
 {
   struct timeval t;
   int n;
@@ -120,24 +123,24 @@ wait_for_connect (struct serial *scb, unsigned int *polls)
       t.tv_usec = 0;
     }
 
-  if (scb)
+  if (sock)
     {
       fd_set rset, wset, eset;
 
       FD_ZERO (&rset);
-      FD_SET (scb->fd, &rset);
+      FD_SET (*sock, &rset);
       wset = rset;
       eset = rset;
-	  
+
       /* POSIX systems return connection success or failure by signalling
 	 wset.  Windows systems return success in wset and failure in
 	 eset.
-     
+
 	 We must call select here, rather than gdb_select, because
 	 the serial structure has not yet been initialized - the
 	 MinGW select wrapper will not know that this FD refers
 	 to a socket.  */
-      n = select (scb->fd + 1, &rset, &wset, &eset, &t);
+      n = select (*sock + 1, &rset, &wset, &eset, &t);
     }
   else
     /* Use gdb_select here, since we have no file descriptors, and on
@@ -153,80 +156,29 @@ wait_for_connect (struct serial *scb, unsigned int *polls)
   return n;
 }
 
-/* Open a tcp socket.  */
+/* Try to connect to the host represented by AINFO.  If the connection
+   succeeds, return its socket.  If we get a ECONNREFUSED error,
+   return -1.  Otherwise, return nothing.  POLLS is used when
+   'connect' returns EINPROGRESS, and we need to invoke
+   'wait_for_connect' to obtain the status.  */
 
-int
-net_open (struct serial *scb, const char *name)
+static gdb::optional<int>
+try_connect (const struct addrinfo *ainfo, unsigned int *polls)
 {
-  char hostname[100];
-  const char *port_str;
-  int n, port, tmp;
-  int use_udp;
-  struct hostent *hostent;
-  struct sockaddr_in sockaddr;
-#ifdef USE_WIN32API
-  u_long ioarg;
-#else
-  int ioarg;
-#endif
-  unsigned int polls = 0;
-
-  use_udp = 0;
-  if (startswith (name, "udp:"))
-    {
-      use_udp = 1;
-      name = name + 4;
-    }
-  else if (startswith (name, "tcp:"))
-    name = name + 4;
-
-  port_str = strchr (name, ':');
-
-  if (!port_str)
-    error (_("net_open: No colon in host name!"));  /* Shouldn't ever
-						       happen.  */
-
-  tmp = std::min (port_str - name, (ptrdiff_t) sizeof hostname - 1);
-  strncpy (hostname, name, tmp);	/* Don't want colon.  */
-  hostname[tmp] = '\000';	/* Tie off host name.  */
-  port = atoi (port_str + 1);
-
-  /* Default hostname is localhost.  */
-  if (!hostname[0])
-    strcpy (hostname, "localhost");
-
-  hostent = gethostbyname (hostname);
-  if (!hostent)
-    {
-      fprintf_unfiltered (gdb_stderr, "%s: unknown host\n", hostname);
-      errno = ENOENT;
-      return -1;
-    }
+  int sock = gdb_socket_cloexec (ainfo->ai_family, ainfo->ai_socktype,
+				 ainfo->ai_protocol);
 
-  sockaddr.sin_family = PF_INET;
-  sockaddr.sin_port = htons (port);
-  memcpy (&sockaddr.sin_addr.s_addr, hostent->h_addr,
-	  sizeof (struct in_addr));
+  if (sock < 0)
+    return {};
 
- retry:
-
-  if (use_udp)
-    scb->fd = gdb_socket_cloexec (PF_INET, SOCK_DGRAM, 0);
-  else
-    scb->fd = gdb_socket_cloexec (PF_INET, SOCK_STREAM, 0);
-
-  if (scb->fd == -1)
-    return -1;
-  
   /* Set socket nonblocking.  */
-  ioarg = 1;
-  ioctl (scb->fd, FIONBIO, &ioarg);
+  int ioarg = 1;
+
+  ioctl (sock, FIONBIO, &ioarg);
 
   /* Use Non-blocking connect.  connect() will return 0 if connected
      already.  */
-  n = connect (scb->fd, (struct sockaddr *) &sockaddr, sizeof (sockaddr));
-
-  if (n < 0)
+  if (connect (sock, ainfo->ai_addr, ainfo->ai_addrlen) < 0)
     {
 #ifdef USE_WIN32API
       int err = WSAGetLastError();
@@ -234,90 +186,202 @@ net_open (struct serial *scb, const char *name)
       int err = errno;
 #endif
 
-      /* Maybe we're waiting for the remote target to become ready to
-	 accept connections.  */
-      if (tcp_auto_retry
+      /* If we've got a "connection refused" error, just return
+	 -1.  The caller will know what to do.  */
+      if (
 #ifdef USE_WIN32API
-	  && err == WSAECONNREFUSED
+	  err == WSAECONNREFUSED
 #else
-	  && err == ECONNREFUSED
+	  err == ECONNREFUSED
 #endif
-	  && wait_for_connect (NULL, &polls) >= 0)
+	  )
 	{
-	  close (scb->fd);
-	  goto retry;
+	  close (sock);
+	  return -1;
 	}
 
       if (
 #ifdef USE_WIN32API
-	  /* Under Windows, calling "connect" with a non-blocking socket
-	     results in WSAEWOULDBLOCK, not WSAEINPROGRESS.  */
+	  /* Any other error (except EINPROGRESS) will be "swallowed"
+	     here.  We return without specifying a return value, and
+	     set errno if the caller wants to inspect what
+	     happened.  */
 	  err != WSAEWOULDBLOCK
 #else
 	  err != EINPROGRESS
 #endif
 	  )
 	{
+	  close (sock);
 	  errno = err;
-	  net_close (scb);
-	  return -1;
+	  return {};
 	}
 
       /* Looks like we need to wait for the connect.  */
-      do 
-	{
-	  n = wait_for_connect (scb, &polls);
-	} 
+      int n;
+
+      do
+	n = wait_for_connect (sock, polls);
       while (n == 0);
+
       if (n < 0)
 	{
-	  net_close (scb);
+	  /* A negative value here means that we either timed out or
+	     got interrupted by the user.  Just return.  */
+	  close (sock);
 	  return -1;
 	}
     }
 
   /* Got something.  Is it an error?  */
-  {
-    int res, err;
-    socklen_t len;
-
-    len = sizeof (err);
-    /* On Windows, the fourth parameter to getsockopt is a "char *";
-       on UNIX systems it is generally "void *".  The cast to "char *"
-       is OK everywhere, since in C++ any data pointer type can be
-       implicitly converted to "void *".  */
-    res = getsockopt (scb->fd, SOL_SOCKET, SO_ERROR, (char *) &err, &len);
-    if (res < 0 || err)
-      {
-	/* Maybe the target still isn't ready to accept the connection.  */
-	if (tcp_auto_retry
+  int err;
+  socklen_t len = sizeof (err);
+
+  /* On Windows, the fourth parameter to getsockopt is a "char *";
+     on UNIX systems it is generally "void *".  The cast to "char *"
+     is OK everywhere, since in C++ any data pointer type can be
+     implicitly converted to "void *".  */
+  int ret = getsockopt (sock, SOL_SOCKET, SO_ERROR, (char *) &err, &len);
+
+  if (ret < 0)
+    {
+      close (sock);
+      errno = ret;
+      return {};
+    }
+  else if (ret == 0 && err != 0)
+    {
+      close (sock);
+      errno = err;
+
+      /* Check if the connection was refused.  */
+      if (
 #ifdef USE_WIN32API
-	    && err == WSAECONNREFUSED
+	  err == WSAECONNREFUSED
 #else
-	    && err == ECONNREFUSED
+	  err == ECONNREFUSED
 #endif
-	    && wait_for_connect (NULL, &polls) >= 0)
-	  {
-	    close (scb->fd);
-	    goto retry;
-	  }
-	if (err)
-	  errno = err;
-	net_close (scb);
+	  )
 	return -1;
-      }
-  } 
+      else
+	{
+	  /* If we have any other kind of error, just return nothing.  */
+	  return {};
+	}
+    }
+
+  /* The connection succeeded.  Return the socket.  */
+  return sock;
+}
+
+/* Open a tcp socket.  */
+
+int
+net_open (struct serial *scb, const char *name)
+{
+  struct addrinfo hint;
+  struct addrinfo *ainfo;
+
+  memset (&hint, 0, sizeof (hint));
+  /* Assume no prefix will be passed, therefore we should use
+     AF_UNSPEC.  */
+  hint.ai_family = AF_UNSPEC;
+  hint.ai_socktype = SOCK_STREAM;
+  hint.ai_protocol = IPPROTO_TCP;
+
+  parsed_connection_spec parsed = parse_connection_spec (name, &hint);
+
+  if (parsed.port_str.empty ())
+    error (_("Missing port on hostname '%s'"), name);
+
+  int r = getaddrinfo (parsed.host_str.c_str (),
+		       parsed.port_str.c_str (),
+		       &hint, &ainfo);
+
+  if (r != 0)
+    {
+      fprintf_unfiltered (gdb_stderr, _("%s: cannot resolve name: %s\n"),
+			  name, gai_strerror (r));
+      errno = ENOENT;
+      return -1;
+    }
+
+  scoped_free_addrinfo free_ainfo (ainfo);
+
+  /* Flag to indicate whether we've got a connection refused.  It will
+     be true if any of the connections tried was refused.  */
+  bool got_connrefused;
+  /* If a connection succeeeds, SUCCESS_AINFO will point to the
+     'struct addrinfo' that succeed.  */
+  struct addrinfo *success_ainfo = NULL;
+  unsigned int polls = 0;
+
+  /* Assume the worst.  */
+  scb->fd = -1;
+
+  do
+    {
+      got_connrefused = false;
+
+      for (struct addrinfo *iter = ainfo; iter != NULL; iter = iter->ai_next)
+	{
+	  /* Iterate over the list of possible addresses to connect
+	     to.  For each, we'll try to connect and see if it
+	     succeeds.  */
+	  gdb::optional<int> sock = try_connect (iter, &polls);
+
+	  if (sock)
+	    {
+	      if (*sock == -1)
+		{
+		  /* The special value "-1" means that there was an
+		     ECONNREFUSED while trying to connect.  */
+		  got_connrefused = true;
+		}
+	      else
+		{
+		  /* We've gotten a successful connection.  Save its
+		     'struct addrinfo', the socket, and break.  */
+		  success_ainfo = iter;
+		  scb->fd = *sock;
+		  break;
+		}
+	    }
+	}
+    }
+  /* Just retry if:
+
+     - tcp_auto_retry is true, and
+     - We haven't gotten a connection yet, and
+     - Any of our connection attempts returned with ECONNREFUSED, and
+     - wait_for_connect signals that we can keep going.  */
+  while (tcp_auto_retry
+	 && success_ainfo == NULL
+	 && got_connrefused
+	 && wait_for_connect ({}, &polls) >= 0);
+
+  if (success_ainfo == NULL)
+    {
+      net_close (scb);
+      return -1;
+    }
 
   /* Turn off nonblocking.  */
-  ioarg = 0;
+#ifdef USE_WIN32API
+  u_long ioarg = 0;
+#else
+  int ioarg = 0;
+#endif
+
   ioctl (scb->fd, FIONBIO, &ioarg);
 
-  if (use_udp == 0)
+  if (success_ainfo->ai_socktype == IPPROTO_TCP)
     {
       /* Disable Nagle algorithm.  Needed in some cases.  */
-      tmp = 1;
+      int tmp = 1;
+
       setsockopt (scb->fd, IPPROTO_TCP, TCP_NODELAY,
-		  (char *)&tmp, sizeof (tmp));
+		  (char *) &tmp, sizeof (tmp));
     }
 
 #ifdef SIGPIPE
diff --git a/gdb/testsuite/README b/gdb/testsuite/README
index 4475ac21a9..55abfb3254 100644
--- a/gdb/testsuite/README
+++ b/gdb/testsuite/README
@@ -259,6 +259,20 @@ This make (not runtest) variable is used to specify whether the
 testsuite preloads the read1.so library into expect.  Any non-empty
 value means true.  See "Race detection" below.
 
+GDB_TEST_SOCKETHOST
+
+This variable can provide the hostname/address that should be used
+when performing GDBserver-related tests.  This is useful in some
+situations, e.g., when you want to test the IPv6 connectivity of GDB
+and GDBserver, or when using a different hostname/address is needed.
+For example, to make GDB and GDBserver use IPv6-only connections, you
+can do:
+
+	make check TESTS="gdb.server/*.exp" RUNTESTFLAGS='GDB_TEST_SOCKETHOST=tcp6:[::1]'
+
+Note that only a hostname/address can be provided, without a port
+number.
+
 Race detection
 **************
 
diff --git a/gdb/testsuite/boards/native-extended-gdbserver.exp b/gdb/testsuite/boards/native-extended-gdbserver.exp
index df949994fd..482e4e3c14 100644
--- a/gdb/testsuite/boards/native-extended-gdbserver.exp
+++ b/gdb/testsuite/boards/native-extended-gdbserver.exp
@@ -24,8 +24,6 @@ load_generic_config "extended-gdbserver"
 load_board_description "gdbserver-base"
 load_board_description "local-board"
 
-set_board_info sockethost "localhost:"
-
 # We will be using the extended GDB remote protocol.
 set_board_info gdb_protocol "extended-remote"
 
diff --git a/gdb/testsuite/boards/native-gdbserver.exp b/gdb/testsuite/boards/native-gdbserver.exp
index ef9316007e..1dee3df4f1 100644
--- a/gdb/testsuite/boards/native-gdbserver.exp
+++ b/gdb/testsuite/boards/native-gdbserver.exp
@@ -30,7 +30,6 @@ set_board_info gdb,do_reload_on_run 1
 # There's no support for argument-passing (yet).
 set_board_info noargs 1
 
-set_board_info sockethost "localhost:"
 set_board_info use_gdb_stub 1
 set_board_info exit_is_reliable 1
 
diff --git a/gdb/testsuite/gdb.server/run-without-local-binary.exp b/gdb/testsuite/gdb.server/run-without-local-binary.exp
index 1665ca9912..6ba3e711d9 100644
--- a/gdb/testsuite/gdb.server/run-without-local-binary.exp
+++ b/gdb/testsuite/gdb.server/run-without-local-binary.exp
@@ -53,7 +53,7 @@ save_vars { GDBFLAGS } {
     set use_gdb_stub 0
 
     gdb_test "target ${gdbserver_protocol} ${gdbserver_gdbport}" \
-	"Remote debugging using $gdbserver_gdbport" \
+	"Remote debugging using [string_to_regexp $gdbserver_gdbport]" \
 	"connect to gdbserver"
 
     gdb_test "run" \
diff --git a/gdb/testsuite/gdb.server/server-connect.exp b/gdb/testsuite/gdb.server/server-connect.exp
new file mode 100644
index 0000000000..e8e96d2d8a
--- /dev/null
+++ b/gdb/testsuite/gdb.server/server-connect.exp
@@ -0,0 +1,111 @@
+# This testcase is part of GDB, the GNU debugger.
+#
+# Copyright 2018 Free Software Foundation, Inc.
+#
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+# Test multiple types of connection (IPv4, IPv6, TCP, UDP) and make
+# sure both gdbserver and GDB work.
+
+load_lib gdbserver-support.exp
+
+standard_testfile normal.c
+
+if {[skip_gdbserver_tests]} {
+    return 0
+}
+
+# We want to have control over where we start gdbserver.
+if { [is_remote target] } {
+    return 0
+}
+
+if { [prepare_for_testing "failed to prepare" $testfile $srcfile debug] } {
+    return -1
+}
+
+# Make sure we're disconnected, in case we're testing with an
+# extended-remote board, therefore already connected.
+gdb_test "disconnect" ".*"
+
+set target_exec [gdbserver_download_current_prog]
+
+# An array containing the test instructions for each scenario.  The
+# description of each field is as follows:
+#
+# - The connection specification to be used when starting
+#   gdbserver/GDB.  This string will be used to set the
+#   GDB_TEST_SOCKETHOST when calling gdbserver_start.
+#
+# - A flag indicating whether gdbserver should fail when we attempt to
+#   start it.  Useful when testing erroneous connection specs such as
+#   "tcp8:".
+#
+# - The prefix that should be prepended to the test messages.
+set test_params \
+    { \
+	  { "tcp4:127.0.0.1" 0 "tcp4" } \
+	  { "tcp6:::1"       0 "tcp6" } \
+	  { "tcp6:[::1]"     0 "tcp6-with-brackets" } \
+	  { "tcp:localhost"  0 "tcp" } \
+	  { "udp4:127.0.0.1" 0 "udp4" } \
+	  { "udp6:::1"       0 "udp6" } \
+	  { "udp6:[::1]"     0 "udp6-with-brackets" } \
+	  { "tcp8:123"       1 "tcp8" } \
+	  { "udp123:::"      1 "udp123" } \
+	  { "garbage:1234"   1 "garbage:1234" } \
+    }
+
+# The best way to test different types of connections is to set the
+# GDB_TEST_SOCKETHOST variable accordingly.
+save_vars { GDB_TEST_SOCKETHOST } {
+    foreach line $test_params {
+	set sockhost [lindex $line 0]
+	set gdbserver_should_fail [lindex $line 1]
+	set prefix [lindex $line 2]
+
+	with_test_prefix $prefix {
+	    set GDB_TEST_SOCKETHOST $sockhost
+	    set test "start gdbserver"
+
+	    # Try to start gdbserver.
+	    set catchres [catch {set res [gdbserver_start "" $target_exec]} errmsg]
+
+	    if { $catchres != 0 } {
+		if { $gdbserver_should_fail } {
+		    pass "$test: gdbserver failed as expected"
+		} else {
+		    fail "$test: $errmsg"
+		}
+		continue
+	    } else {
+		if { $gdbserver_should_fail } {
+		    fail "$test: gdbserver should fail but did not"
+		} else {
+		    pass "$test"
+		}
+	    }
+
+	    set gdbserver_protocol [lindex $res 0]
+	    set gdbserver_gdbport [lindex $res 1]
+	    set test "connect to gdbserver using $sockhost"
+
+	    if { [gdb_target_cmd $gdbserver_protocol $gdbserver_gdbport] == 0 } {
+		pass $test
+	    } else {
+		fail $test
+	    }
+	}
+    }
+}
diff --git a/gdb/testsuite/lib/gdbserver-support.exp b/gdb/testsuite/lib/gdbserver-support.exp
index 46e4f77922..3a939e8cda 100644
--- a/gdb/testsuite/lib/gdbserver-support.exp
+++ b/gdb/testsuite/lib/gdbserver-support.exp
@@ -211,7 +211,7 @@ proc gdbserver_default_get_remote_address { host port } {
 # Default routine to compute the "comm" argument for gdbserver.
 
 proc gdbserver_default_get_comm_port { port } {
-    return ":$port"
+    return "$port"
 }
 
 # Start a gdbserver process with initial OPTIONS and trailing ARGUMENTS.
@@ -221,6 +221,7 @@ proc gdbserver_default_get_comm_port { port } {
 
 proc gdbserver_start { options arguments } {
     global portnum
+    global GDB_TEST_SOCKETHOST
 
     # Port id -- either specified in baseboard file, or managed here.
     if [target_info exists gdb,socketport] {
@@ -231,10 +232,22 @@ proc gdbserver_start { options arguments } {
     }
 
     # Extract the local and remote host ids from the target board struct.
-    if [target_info exists sockethost] {
+    if { [info exists GDB_TEST_SOCKETHOST] } {
+	# The user is not supposed to provide a port number, just a
+	# hostname/address, therefore we add the trailing ":" here.
+	set debughost "${GDB_TEST_SOCKETHOST}:"
+	# Espace open and close square brackets.
+	set debughost_tmp [string map { [ \\[ ] \\] } $debughost]
+	# We need a "gdbserver" version of the debughost, which will
+	# have the possible connection prefix stripped.  This is
+	# because gdbserver currently doesn't recognize the prefixes.
+	regsub -all "^\(tcp:|udp:|tcp4:|udp4:|tcp6:|udp6:\)" $debughost_tmp "" debughost_gdbserver
+    } elseif [target_info exists sockethost] {
 	set debughost [target_info sockethost]
+	set debughost_gdbserver $debughost
     } else {
 	set debughost "localhost:"
+	set debughost_gdbserver $debughost
     }
 
     # Some boards use a different value for the port that is passed to
@@ -277,8 +290,14 @@ proc gdbserver_start { options arguments } {
 	if { $options != "" } {
 	    append gdbserver_command " $options"
 	}
+	if { $debughost_gdbserver != "" } {
+	    append gdbserver_command " $debughost_gdbserver"
+	}
 	if { $portnum != "" } {
-	    append gdbserver_command " [$get_comm_port $portnum]"
+	    if { $debughost_gdbserver == "" } {
+		append gdbserver_command " "
+	    }
+	    append gdbserver_command "[$get_comm_port $portnum]"
 	}
 	if { $arguments != "" } {
 	    append gdbserver_command " $arguments"
@@ -307,6 +326,9 @@ proc gdbserver_start { options arguments } {
 		    continue
 		}
 	    }
+	    -re ".*: cannot resolve name: Name or service not known\r\n" {
+		error "gdbserver cannot resolve name."
+	    }
 	    timeout {
 		error "Timeout waiting for gdbserver response."
 	    }
diff --git a/gdb/unittests/parse-connection-spec-selftests.c b/gdb/unittests/parse-connection-spec-selftests.c
new file mode 100644
index 0000000000..10155ae133
--- /dev/null
+++ b/gdb/unittests/parse-connection-spec-selftests.c
@@ -0,0 +1,251 @@
+/* Self tests for parsing connection specs for GDB, the GNU debugger.
+
+   Copyright (C) 2017-2018 Free Software Foundation, Inc.
+
+   This file is part of GDB.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+#include "defs.h"
+#include "selftest.h"
+#include "common/netstuff.h"
+#include "diagnostics.h"
+#ifdef USE_WIN32API
+#include <winsock2.h>
+#include <wspiapi.h>
+#else
+#include <netinet/in.h>
+#include <arpa/inet.h>
+#include <netdb.h>
+#include <sys/socket.h>
+#include <netinet/tcp.h>
+#endif
+
+namespace selftests {
+namespace parse_connection_spec_tests {
+
+/* Auxiliary struct that holds info about a specific test for a
+   connection spec.  */
+
+struct parse_conn_test
+{
+  /* The connection spec.  */
+  const char *connspec;
+
+  /* Expected result from 'parse_connection_spec'.  */
+  parsed_connection_spec expected_result;
+
+  /* True if this test should fail, false otherwise.  If true, only
+     the CONNSPEC field should be considered as valid.  */
+  bool should_fail;
+
+  /* The expected AI_FAMILY to be found on the 'struct addrinfo'
+     HINT.  */
+  int exp_ai_family;
+
+  /* The expected AI_SOCKTYPE to be found on the 'struct addrinfo'
+     HINT.  */
+  int exp_ai_socktype;
+
+  /* The expected AI_PROTOCOL to be found on the 'struct addrinfo'
+     HINT.  */
+  int exp_ai_protocol;
+};
+
+/* Some defines to help us fill a 'struct parse_conn_test'.  */
+
+/* Initialize a full entry.  */
+#define INIT_ENTRY(ADDR, EXP_HOST, EXP_PORT, SHOULD_FAIL, EXP_AI_FAMILY, \
+		   EXP_AI_SOCKTYPE, EXP_AI_PROTOCOL)			\
+  { ADDR, { EXP_HOST, EXP_PORT }, SHOULD_FAIL, EXP_AI_FAMILY, \
+    EXP_AI_SOCKTYPE, EXP_AI_PROTOCOL }
+
+/* Initialized an unprefixed entry.  In this case, we don't expect
+   nothing on the 'struct addrinfo' HINT.  */
+#define INIT_UNPREFIXED_ENTRY(ADDR, EXP_HOST, EXP_PORT) \
+  INIT_ENTRY (ADDR, EXP_HOST, EXP_PORT, false, 0, 0, 0)
+
+/* Initialized an unprefixed IPv6 entry.  In this case, we don't
+   expect nothing on the 'struct addrinfo' HINT.  */
+#define INIT_UNPREFIXED_IPV6_ENTRY(ADDR, EXP_HOST, EXP_PORT) \
+  INIT_ENTRY (ADDR, EXP_HOST, EXP_PORT, false, AF_INET6, 0, 0)
+
+/* Initialize a prefixed entry.  */
+#define INIT_PREFIXED_ENTRY(ADDR, EXP_HOST, EXP_PORT, EXP_AI_FAMILY, \
+			    EXP_AI_SOCKTYPE, EXP_AI_PROTOCOL) \
+  INIT_ENTRY (ADDR, EXP_HOST, EXP_PORT, false, EXP_AI_FAMILY, \
+	      EXP_AI_SOCKTYPE, EXP_AI_PROTOCOL)
+
+/* Initialize an entry prefixed with "tcp4:".  */
+#define INIT_PREFIXED_IPV4_TCP(ADDR, EXP_HOST, EXP_PORT) \
+  INIT_PREFIXED_ENTRY (ADDR, EXP_HOST, EXP_PORT, AF_INET, SOCK_STREAM, \
+		       IPPROTO_TCP)
+
+/* Initialize an entry prefixed with "tcp6:".  */
+#define INIT_PREFIXED_IPV6_TCP(ADDR, EXP_HOST, EXP_PORT) \
+  INIT_PREFIXED_ENTRY (ADDR, EXP_HOST, EXP_PORT, AF_INET6, SOCK_STREAM, \
+		       IPPROTO_TCP)
+
+/* Initialize an entry prefixed with "udp4:".  */
+#define INIT_PREFIXED_IPV4_UDP(ADDR, EXP_HOST, EXP_PORT) \
+  INIT_PREFIXED_ENTRY (ADDR, EXP_HOST, EXP_PORT, AF_INET, SOCK_DGRAM, \
+		       IPPROTO_UDP)
+
+/* Initialize an entry prefixed with "udp6:".  */
+#define INIT_PREFIXED_IPV6_UDP(ADDR, EXP_HOST, EXP_PORT) \
+  INIT_PREFIXED_ENTRY (ADDR, EXP_HOST, EXP_PORT, AF_INET6, SOCK_DGRAM, \
+		       IPPROTO_UDP)
+
+/* Initialize a bogus entry, i.e., a connection spec that should
+   fail.  */
+#define INIT_BOGUS_ENTRY(ADDR) \
+  INIT_ENTRY (ADDR, "", "", true, 0, 0, 0)
+
+/* The variable which holds all of our tests.  */
+
+static const parse_conn_test conn_test[] =
+  {
+    /* Unprefixed addresses.  */
+
+    /* IPv4, host and port present.  */
+    INIT_UNPREFIXED_ENTRY ("127.0.0.1:1234", "127.0.0.1", "1234"),
+    /* IPv4, only host.  */
+    INIT_UNPREFIXED_ENTRY ("127.0.0.1", "127.0.0.1", ""),
+    /* IPv4, missing port.  */
+    INIT_UNPREFIXED_ENTRY ("127.0.0.1:", "127.0.0.1", ""),
+
+    /* IPv6, host and port present, no brackets.  */
+    INIT_UNPREFIXED_ENTRY ("::1:1234", "::1", "1234"),
+    /* IPv6, only host, no brackets.  */
+    // INIT_UNPREFIXED_ENTRY ("::1", "::1", ""),
+    /* IPv6, missing port, no brackets.  */
+    INIT_UNPREFIXED_ENTRY ("::1:", "::1", ""),
+    /* IPv6, host and port present, with brackets.  */
+    INIT_UNPREFIXED_IPV6_ENTRY ("[::1]:1234", "::1", "1234"),
+    /* IPv6, only host, with brackets.  */
+    INIT_UNPREFIXED_IPV6_ENTRY ("[::1]", "::1", ""),
+    /* IPv6, missing port, with brackets.  */
+    INIT_UNPREFIXED_IPV6_ENTRY ("[::1]:", "::1", ""),
+
+    /* Unspecified, only port.  */
+    INIT_UNPREFIXED_ENTRY (":1234", "localhost", "1234"),
+
+    /* Prefixed addresses.  */
+
+    /* Prefixed "tcp4:" IPv4, host and port presents.  */
+    INIT_PREFIXED_IPV4_TCP ("tcp4:127.0.0.1:1234", "127.0.0.1", "1234"),
+    /* Prefixed "tcp4:" IPv4, only port.  */
+    INIT_PREFIXED_IPV4_TCP ("tcp4::1234", "localhost", "1234"),
+    /* Prefixed "tcp4:" IPv4, only host.  */
+    INIT_PREFIXED_IPV4_TCP ("tcp4:127.0.0.1", "127.0.0.1", ""),
+    /* Prefixed "tcp4:" IPv4, missing port.  */
+    INIT_PREFIXED_IPV4_TCP ("tcp4:127.0.0.1:", "127.0.0.1", ""),
+
+    /* Prefixed "udp4:" IPv4, host and port presents.  */
+    INIT_PREFIXED_IPV4_UDP ("udp4:127.0.0.1:1234", "127.0.0.1", "1234"),
+    /* Prefixed "udp4:" IPv4, only port.  */
+    INIT_PREFIXED_IPV4_UDP ("udp4::1234", "localhost", "1234"),
+    /* Prefixed "udp4:" IPv4, only host.  */
+    INIT_PREFIXED_IPV4_UDP ("udp4:127.0.0.1", "127.0.0.1", ""),
+    /* Prefixed "udp4:" IPv4, missing port.  */
+    INIT_PREFIXED_IPV4_UDP ("udp4:127.0.0.1:", "127.0.0.1", ""),
+
+
+    /* Prefixed "tcp6:" IPv6, host and port presents.  */
+    INIT_PREFIXED_IPV6_TCP ("tcp6:::1:1234", "::1", "1234"),
+    /* Prefixed "tcp6:" IPv6, only port.  */
+    INIT_PREFIXED_IPV6_TCP ("tcp6::1234", "localhost", "1234"),
+    /* Prefixed "tcp6:" IPv6, only host.  */
+    //INIT_PREFIXED_IPV6_TCP ("tcp6:::1", "::1", ""),
+    /* Prefixed "tcp6:" IPv6, missing port.  */
+    INIT_PREFIXED_IPV6_TCP ("tcp6:::1:", "::1", ""),
+
+    /* Prefixed "udp6:" IPv6, host and port presents.  */
+    INIT_PREFIXED_IPV6_UDP ("udp6:::1:1234", "::1", "1234"),
+    /* Prefixed "udp6:" IPv6, only port.  */
+    INIT_PREFIXED_IPV6_UDP ("udp6::1234", "localhost", "1234"),
+    /* Prefixed "udp6:" IPv6, only host.  */
+    //INIT_PREFIXED_IPV6_UDP ("udp6:::1", "::1", ""),
+    /* Prefixed "udp6:" IPv6, missing port.  */
+    INIT_PREFIXED_IPV6_UDP ("udp6:::1:", "::1", ""),
+
+    /* Prefixed "tcp6:" IPv6 with brackets, host and port presents.  */
+    INIT_PREFIXED_IPV6_TCP ("tcp6:[::1]:1234", "::1", "1234"),
+    /* Prefixed "tcp6:" IPv6 with brackets, only host.  */
+    INIT_PREFIXED_IPV6_TCP ("tcp6:[::1]", "::1", ""),
+    /* Prefixed "tcp6:" IPv6 with brackets, missing port.  */
+    INIT_PREFIXED_IPV6_TCP ("tcp6:[::1]:", "::1", ""),
+
+    /* Prefixed "udp6:" IPv6 with brackets, host and port presents.  */
+    INIT_PREFIXED_IPV6_UDP ("udp6:[::1]:1234", "::1", "1234"),
+    /* Prefixed "udp6:" IPv6 with brackets, only host.  */
+    INIT_PREFIXED_IPV6_UDP ("udp6:[::1]", "::1", ""),
+    /* Prefixed "udp6:" IPv6 with brackets, missing port.  */
+    INIT_PREFIXED_IPV6_UDP ("udp6:[::1]:", "::1", ""),
+
+
+    /* Bogus addresses.  */
+    INIT_BOGUS_ENTRY ("tcp6:[::1]123:44"),
+    INIT_BOGUS_ENTRY ("[::1"),
+    INIT_BOGUS_ENTRY ("tcp6:::1]:"),
+  };
+
+/* Test a connection spec C.  */
+
+static void
+test_conn (const parse_conn_test &c)
+{
+  struct addrinfo hint;
+  parsed_connection_spec ret;
+
+  memset (&hint, 0, sizeof (hint));
+
+  TRY
+    {
+      ret = parse_connection_spec (c.connspec, &hint);
+    }
+  CATCH (ex, RETURN_MASK_ERROR)
+    {
+      /* If we caught an error, we should check if this connection
+	 spec was supposed to fail.  */
+      SELF_CHECK (c.should_fail);
+      return;
+    }
+  END_CATCH
+
+  SELF_CHECK (!c.should_fail);
+  SELF_CHECK (ret.host_str == c.expected_result.host_str);
+  SELF_CHECK (ret.port_str == c.expected_result.port_str);
+  SELF_CHECK (hint.ai_family == c.exp_ai_family);
+  SELF_CHECK (hint.ai_socktype == c.exp_ai_socktype);
+  SELF_CHECK (hint.ai_protocol == c.exp_ai_protocol);
+}
+
+/* Run the tests associated with parsing connection specs.  */
+
+static void
+run_tests ()
+{
+  for (const parse_conn_test &c : conn_test)
+    test_conn (c);
+}
+} /* namespace parse_connection_spec_tests */
+} /* namespace selftests */
+
+void
+_initialize_parse_connection_spec_selftests ()
+{
+  selftests::register_test ("parse_connection_spec",
+			    selftests::parse_connection_spec_tests::run_tests);
+}
