[PATCH] supports IPv6 only remote target

Tsutomu Seki sekiriki@gmail.com
Tue Feb 9 13:50:00 GMT 2016


Hi,

While I'm trying to connect remote target that has only IPv6
(Link-Local) address,
> $ getent hosts hogehoge.local
> fe80::XXXX:XXff:feXX:XXXX hogehoge.local
> $ arm-none-eabi-gdb
> (gdb) target remote hogehoge.local:2159

I found gdb is sending packets for invalid address,
> $ tcpdump -n "tcp port 2159"
> 14:06:39.611372 IP 10.XX.XX.10.51012 > 254.128.0.0.2159: Flags [S], seq 4014569856, win 29200, options [mss 1460,sackOK,TS val 429376439 ecr 0,nop,wscale 7], length 0
> 14:06:40.608993 IP 10.XX.XX.10.51012 > 254.128.0.0.2159: Flags [S], seq 4014569856, win 29200, options [mss 1460,sackOK,TS val 429376689 ecr 0,nop,wscale 7], length 0
> ...
and then, it fails to connect after few seconds.

In addition to that, it seems port number is invalidly parsed when only colon,
without decimal number was passed. I mean;
> (gdb) target remote tcp::
will result to try to connect tcp port 0 on localhost.

Forthcoming patch fixes these problem and add IPv6 support.

Tested to build for --target=arm-none-eabi, with --host=x86_64-linux-gnu
and i686-w64-mingw32, by applying the patch to a version 5-2015-q4-major
of https://launchpad.net/gcc-arm-embedded, and to run on Ubuntu 14.04.3
and Windows 7 Enterprise SP1, respectively.

Thanks in advance and sorry for my poor English.

Regards,
Seki, Tsutomu

---
gdb/ChangeLog:

        * ser-tcp.c (net_open): Use getaddrinfo instead of gethostbyname
        (net_open): Add IPv6 numerical address support
        (net_open): Use "gdbremote" as default service name

gdb/doc/ChangeLog:

        * gdb.texinfo (Remote Connection Commands): Update to mention
        IPv6 numerical address and default service name.

---
 gdb/doc/gdb.texinfo | 27 +++++++++++++---
 gdb/ser-tcp.c       | 91 ++++++++++++++++++++++++++++++++++-------------------
 2 files changed, 82 insertions(+), 36 deletions(-)

diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo
index 2d09d13..d696ce4 100644
--- a/gdb/doc/gdb.texinfo
+++ b/gdb/doc/gdb.texinfo
@@ -19565,16 +19565,17 @@ 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 extended-remote @code{@var{host}:@var{port}}
 @itemx target extended-remote @code{tcp:@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.
+address; @var{port} may be either a service name or 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}:
@@ -19583,6 +19584,14 @@ For example, to connect to port 2828 on a
terminal server named
 target remote manyfarms:2828
 @end smallexample

+Numerical @acronym{IPv6} address must be enclosed in square brackets.
+For example, to connect to port 2159 of a target which has IPv6
+link-local address fe80::1 on eth1:
+
+@smallexample
+target remote [fe80::1%eth1]:2159
+@end smallexample
+
 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
@@ -19591,6 +19600,16 @@ port 1234 on your local machine:
 @smallexample
 target remote :1234
 @end smallexample
+
+The service name is default to ``gdbremote''. If the service name is
+present in service list (e.g.@: @file{/etc/services} on @sc{gnu}/Linux
+systems), and target is listening on assigned port, you can omit the
+service name. For example, to connect to service ``gdbremote'' on your
+local machine:
+
+@smallexample
+target remote :
+@end smallexample
 @noindent

 Note that the colon is still required here.
diff --git a/gdb/ser-tcp.c b/gdb/ser-tcp.c
index df3af4c..4ed5f2a 100644
--- a/gdb/ser-tcp.c
+++ b/gdb/ser-tcp.c
@@ -39,6 +39,7 @@

 #ifdef USE_WIN32API
 #include <winsock2.h>
+#include <wspiapi.h>
 #ifndef ETIMEDOUT
 #define ETIMEDOUT WSAETIMEDOUT
 #endif
@@ -156,11 +157,10 @@ int
 net_open (struct serial *scb, const char *name)
 {
   char hostname[100];
-  const char *port_str;
-  int n, port, tmp;
+  const char *port_str, *host_str;
+  int n, tmp, err;
   int use_udp;
-  struct hostent *hostent;
-  struct sockaddr_in sockaddr;
+  struct addrinfo *ai, hint;
 #ifdef USE_WIN32API
   u_long ioarg;
 #else
@@ -177,43 +177,65 @@ net_open (struct serial *scb, const char *name)
   else if (startswith (name, "tcp:"))
     name = name + 4;

-  port_str = strchr (name, ':');
+  if (name[0] == '[')
+    {
+      const char *end = strchr(name + 1, ']');
+      if (!end)
+ error (_("net_open: No close bracket in host name!"));
+
+      tmp = min (end - name - 1, (int) sizeof hostname - 1);
+      strncpy (hostname, name + 1, tmp); /* Don't want brackets. */
+      hostname[tmp] = '\0'; /* Tie off host name.  */
+      host_str = hostname;
+      port_str = end + 1;
+    }
+  else if ((port_str = strrchr(name, ':')) != NULL)
+    {
+      tmp = min (port_str - name, (int) sizeof hostname - 1);
+      strncpy (hostname, name, tmp); /* Don't want colon.  */
+      hostname[tmp] = '\0'; /* Tie off host name.  */
+      host_str = hostname;
+    }
+  else
+    {
+      host_str = name;
+      port_str = NULL;
+    }

-  if (!port_str)
-    error (_("net_open: No colon in host name!"));  /* Shouldn't ever
-       happen.  */
+  if (port_str != NULL && port_str[0] == ':')
+    port_str++;

-  tmp = min (port_str - name, (int) sizeof hostname - 1);
-  strncpy (hostname, name, tmp); /* Don't want colon.  */
-  hostname[tmp] = '\000'; /* Tie off host name.  */
-  port = atoi (port_str + 1);
+  /* Default service name is gdbremote.  */
+  if (port_str == NULL || port_str[0] == '\0')
+    port_str = "gdbremote";

   /* Default hostname is localhost.  */
-  if (!hostname[0])
-    strcpy (hostname, "localhost");
-
-  hostent = gethostbyname (hostname);
-  if (!hostent)
+  if (host_str[0] == '\0')
+    host_str = "localhost";
+
+  memset(&hint, 0, sizeof hint);
+  hint.ai_family = AF_UNSPEC;
+  hint.ai_socktype = use_udp ? SOCK_DGRAM : SOCK_STREAM;
+  hint.ai_flags = 0;
+  hint.ai_protocol = use_udp ? IPPROTO_UDP : IPPROTO_TCP;
+  hint.ai_canonname = NULL;
+  hint.ai_addr = NULL;
+  hint.ai_next = NULL;
+  ai = NULL;
+
+  if ((err = getaddrinfo (host_str, port_str, &hint, &ai)) != 0)
     {
-      fprintf_unfiltered (gdb_stderr, "%s: unknown host\n", hostname);
+      fprintf_unfiltered (gdb_stderr, "%s: %s\n", name, gai_strerror(err));
       errno = ENOENT;
       return -1;
     }

-  sockaddr.sin_family = PF_INET;
-  sockaddr.sin_port = htons (port);
-  memcpy (&sockaddr.sin_addr.s_addr, hostent->h_addr,
-  sizeof (struct in_addr));
-
  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);
+  scb->fd = gdb_socket_cloexec (ai->ai_family, ai->ai_socktype,
ai->ai_protocol);

   if (scb->fd == -1)
-    return -1;
+    goto bailout;

   /* Set socket nonblocking.  */
   ioarg = 1;
@@ -221,7 +243,7 @@ net_open (struct serial *scb, const char *name)

   /* Use Non-blocking connect.  connect() will return 0 if connected
      already.  */
-  n = connect (scb->fd, (struct sockaddr *) &sockaddr, sizeof (sockaddr));
+  n = connect (scb->fd, ai->ai_addr, ai->ai_addrlen);

   if (n < 0)
     {
@@ -257,7 +279,7 @@ net_open (struct serial *scb, const char *name)
  {
   errno = err;
   net_close (scb);
-  return -1;
+  goto bailout;
  }

       /* Looks like we need to wait for the connect.  */
@@ -269,7 +291,7 @@ net_open (struct serial *scb, const char *name)
       if (n < 0)
  {
   net_close (scb);
-  return -1;
+  goto bailout;
  }
     }

@@ -301,7 +323,7 @@ net_open (struct serial *scb, const char *name)
  if (err)
   errno = err;
  net_close (scb);
- return -1;
+ goto bailout;
       }
   }

@@ -323,7 +345,12 @@ net_open (struct serial *scb, const char *name)
   signal (SIGPIPE, SIG_IGN);
 #endif

+  freeaddrinfo (ai);
   return 0;
+
+ bailout:
+  freeaddrinfo (ai);
+  return -1;
 }

 void



More information about the Gdb-patches mailing list