public inbox for git-commits@fedoraproject.org
help / color / mirror / Atom feed
* [rpms/gdb] gdb-17.2-rebase-f44: Rebase to FSF GDB 8.1.90.20180714 (8.2pre).
@ 2026-06-27 23:58 Sergio Durigan Junior
0 siblings, 0 replies; only message in thread
From: Sergio Durigan Junior @ 2026-06-27 23:58 UTC (permalink / raw)
To: git-commits
A new commit has been pushed.
Repo : rpms/gdb
Branch : gdb-17.2-rebase-f44
Commit : 2cbda85f1ce90ca3d8c1db5743f544e4fc9ebdd6
Author : Sergio Durigan Junior <sergiodj@redhat.com>
Date : 2018-07-15T12:27:21-04:00
Stats : +2049/-8 in 10 file(s)
URL : https://src.fedoraproject.org/rpms/gdb/c/2cbda85f1ce90ca3d8c1db5743f544e4fc9ebdd6?branch=gdb-17.2-rebase-f44
Log:
Rebase to FSF GDB 8.1.90.20180714 (8.2pre).
Backport IPv6 patch (RH BZ 881849, Sergio Durigan Junior).
---
diff --git a/_gdb.spec.Patch.include b/_gdb.spec.Patch.include
index edce570..8ba0e48 100644
--- a/_gdb.spec.Patch.include
+++ b/_gdb.spec.Patch.include
@@ -504,3 +504,9 @@ Patch120: gdb-vla-intel-fix-print-char-array.patch
# =fedoratest
Patch121: gdb-rhbz1553104-s390x-arch12-test.patch
+# Implement IPv6 support for GDB/gdbserver (RH BZ 881849, Sergio Durigan Junior).
+Patch122: gdb-rhbz881849-ipv6-1of2.patch
+
+# Implement IPv6 support for GDB/gdbserver (RH BZ 881849, Sergio Durigan Junior).
+Patch123: gdb-rhbz881849-ipv6-2of2.patch
+
diff --git a/_gdb.spec.patch.include b/_gdb.spec.patch.include
index a663edb..27a39b7 100644
--- a/_gdb.spec.patch.include
+++ b/_gdb.spec.patch.include
@@ -119,3 +119,5 @@
%patch119 -p1
%patch120 -p1
%patch121 -p1
+%patch122 -p1
+%patch123 -p1
diff --git a/_git_upstream_commit b/_git_upstream_commit
index d890f7b..6eddfd2 100644
--- a/_git_upstream_commit
+++ b/_git_upstream_commit
@@ -1 +1 @@
-0bad166b920254974ad2e35f087e14aa913afe44
+baa98cb7e6298cd74ad9638e5b02aa192f804659
diff --git a/_patch_order b/_patch_order
index 1b3a5fe..11b4131 100644
--- a/_patch_order
+++ b/_patch_order
@@ -119,3 +119,5 @@ gdb-testsuite-readline63-sigint.patch
gdb-archer.patch
gdb-vla-intel-fix-print-char-array.patch
gdb-rhbz1553104-s390x-arch12-test.patch
+gdb-rhbz881849-ipv6-1of2.patch
+gdb-rhbz881849-ipv6-2of2.patch
diff --git a/gdb-container-rh-pkg.patch b/gdb-container-rh-pkg.patch
index a58af23..2defc8d 100644
--- a/gdb-container-rh-pkg.patch
+++ b/gdb-container-rh-pkg.patch
@@ -9,7 +9,7 @@ Subject: gdb-container-rh-pkg.patch
diff --git a/gdb/remote.c b/gdb/remote.c
--- a/gdb/remote.c
+++ b/gdb/remote.c
-@@ -13901,7 +13901,17 @@ remote_target::pid_to_exec_file (int pid)
+@@ -13909,7 +13909,17 @@ remote_target::pid_to_exec_file (int pid)
char *annex = NULL;
if (packet_support (PACKET_qXfer_exec_file) != PACKET_ENABLE)
diff --git a/gdb-rhbz795424-bitpos-20of25.patch b/gdb-rhbz795424-bitpos-20of25.patch
index e3d4713..6ebda52 100644
--- a/gdb-rhbz795424-bitpos-20of25.patch
+++ b/gdb-rhbz795424-bitpos-20of25.patch
@@ -2758,7 +2758,7 @@ diff --git a/gdb/remote.c b/gdb/remote.c
int insert_watchpoint (CORE_ADDR, int, enum target_hw_bp_type,
struct expression *) override;
-@@ -10405,7 +10405,7 @@ int remote_hw_watchpoint_length_limit = -1;
+@@ -10413,7 +10413,7 @@ int remote_hw_watchpoint_length_limit = -1;
int remote_hw_breakpoint_limit = -1;
int
diff --git a/gdb-rhbz795424-bitpos-22of25.patch b/gdb-rhbz795424-bitpos-22of25.patch
index eb81a17..8072f77 100644
--- a/gdb-rhbz795424-bitpos-22of25.patch
+++ b/gdb-rhbz795424-bitpos-22of25.patch
@@ -384,7 +384,7 @@ diff --git a/gdb/remote.c b/gdb/remote.c
int can_use_hw_breakpoint (enum bptype, int, int) override;
-@@ -10334,7 +10334,7 @@ remote_target::insert_watchpoint (CORE_ADDR addr, int len,
+@@ -10342,7 +10342,7 @@ remote_target::insert_watchpoint (CORE_ADDR addr, int len,
p = strchr (rs->buf, '\0');
addr = remote_address_masked (addr);
p += hexnumstr (p, (ULONGEST) addr);
@@ -393,7 +393,7 @@ diff --git a/gdb/remote.c b/gdb/remote.c
putpkt (rs->buf);
getpkt (&rs->buf, &rs->buf_size, 0);
-@@ -10354,7 +10354,7 @@ remote_target::insert_watchpoint (CORE_ADDR addr, int len,
+@@ -10362,7 +10362,7 @@ remote_target::insert_watchpoint (CORE_ADDR addr, int len,
bool
remote_target::watchpoint_addr_within_range (CORE_ADDR addr,
@@ -402,7 +402,7 @@ diff --git a/gdb/remote.c b/gdb/remote.c
{
CORE_ADDR diff = remote_address_masked (addr - start);
-@@ -10383,7 +10383,7 @@ remote_target::remove_watchpoint (CORE_ADDR addr, int len,
+@@ -10391,7 +10391,7 @@ remote_target::remove_watchpoint (CORE_ADDR addr, int len,
p = strchr (rs->buf, '\0');
addr = remote_address_masked (addr);
p += hexnumstr (p, (ULONGEST) addr);
diff --git a/gdb-rhbz881849-ipv6-1of2.patch b/gdb-rhbz881849-ipv6-1of2.patch
new file mode 100644
index 0000000..32745c9
--- /dev/null
+++ b/gdb-rhbz881849-ipv6-1of2.patch
@@ -0,0 +1,1964 @@
+From FEDORA_PATCHES Mon Sep 17 00:00:00 2001
+From: Sergio Durigan Junior <sergiodj@redhat.com>
+Date: Fri, 18 May 2018 01:29:24 -0400
+Subject: gdb-rhbz881849-ipv6-1of2.patch
+
+;; Implement IPv6 support for GDB/gdbserver (RH BZ 881849, Sergio Durigan Junior).
+
+Implement IPv6 support for GDB/gdbserver
+
+This patch implements IPv6 support for both GDB and gdbserver. Based
+on my research, it is the fourth attempt to do that since 2006. Since
+I used ideas from all of the previous patches, I also added their
+authors's names on the ChangeLogs as a way to recognize their
+efforts. For reference sake, you can find the previous attempts at:
+
+ https://sourceware.org/ml/gdb-patches/2006-09/msg00192.html
+
+ https://sourceware.org/ml/gdb-patches/2014-02/msg00248.html
+
+ https://sourceware.org/ml/gdb-patches/2016-02/msg00226.html
+
+The basic idea behind the patch is to start using the new
+'getaddrinfo'/'getnameinfo' calls, which are responsible for
+translating names and addresses in a protocol-independent way. This
+means that if we ever have a new version of the IP protocol, we won't
+need to change the code again (or, at least, won't have to change the
+majority of the code).
+
+The function 'getaddrinfo' returns a linked list of possible addresses
+to connect to. Dealing with multiple addresses proved to be a hard
+task with the current TCP auto-retry mechanism implemented on
+ser-tcp:net_open. For example, when gdbserver listened only on an
+IPv4 socket:
+
+ $ ./gdbserver --once 127.0.0.1:1234 ./a.out
+
+and GDB was instructed to try to connect to both IPv6 and IPv4
+sockets:
+
+ $ ./gdb -ex 'target extended-remote localhost:1234' ./a.out
+
+the user would notice a somewhat big delay before GDB was able to
+connect to the IPv4 socket. This happened because GDB was trying to
+connect to the IPv6 socket first, and had to wait until the connection
+timed out before it tried to connect to the IPv4 socket.
+
+For that reason, I had to rewrite the main loop and implement a new
+method for handling multiple connections. After some discussion,
+Pedro and I agreed on the following algorithm:
+
+ 1) For each entry returned by 'getaddrinfo', we try to open a socket
+ and connect to it.
+
+ 2.a) If we have a successful 'connect', we just use that connection.
+
+ 2.b) If we don't have a successfull 'connect', but if we've got a
+ ECONNREFUSED (meaning the the connection was refused), we keep track
+ of this fact by using a flag.
+
+ 2.c) If we don't have a successfull 'connect', but if we've got a
+ EINPROGRESS (meaning that the connection is in progress), we perform
+ a 'select' call on the socket until we have a result (either a
+ successful connection, or an error on the socket).
+
+ 3) If tcp_auto_retry is true, and we haven't gotten a successful
+ connection, and at least one of our attempts failed with
+ ECONNREFUSED, then we wait a little bit (i.e., call
+ 'wait_for_connect'), check to see if there was a
+ timeout/interruption (in which case we bail out), and then go back
+ to (1).
+
+After multiple tests, I was able to connect without delay on the
+scenario described above, and was also able to connect in all other
+types of scenarios.
+
+I also implemented some hostname parsing functions (along with their
+corresponding unit tests) which are used to help GDB and gdbserver to
+parse hostname strings provided by the user. These new functions are
+living inside common/netstuff.[ch]. I've had to do that since IPv6
+introduces a new URL scheme, which defines that square brackets can be
+used to enclose the host part and differentiate it from the
+port (e.g., "[::1]:1234" means "host ::1, port 1234"). I spent some
+time thinking about a reasonable way to interpret what the user wants,
+and I came up with the following:
+
+ - If the user has provided a prefix that doesn't specify the protocol
+ version (i.e., "tcp:" or "udp:"), or if the user has not provided
+ any prefix, don't make any assumptions (i.e., assume AF_UNSPEC when
+ dealing with 'getaddrinfo') *unless* the host starts with "[" (in
+ which case, assume it's an IPv6 host).
+
+ - If the user has provided a prefix that does specify the protocol
+ version (i.e., "tcp4:", "tcp6:", "udp4:" or "udp6:"), then respect
+ that.
+
+This method doesn't follow strictly what RFC 2732 proposes (that
+literal IPv6 addresses should be provided enclosed in "[" and "]")
+because IPv6 addresses still can be provided without square brackets
+in our case, but since we have prefixes to specify protocol versions I
+think this is not an issue.
+
+Another thing worth mentioning is the new 'GDB_TEST_SOCKETHOST'
+testcase parameter, which makes it possible to specify the
+hostname (without the port) to be used when testing GDB and
+gdbserver. For example, to run IPv6 tests:
+
+ $ make check-gdb RUNTESTFLAGS='GDB_TEST_SOCKETHOST=tcp6:[::1]'
+
+Or, to run IPv4 tests:
+
+ $ make check-gdb RUNTESTFLAGS='GDB_TEST_SOCKETHOST=tcp4:127.0.0.1'
+
+This required a few changes on the gdbserver-base.exp, and also a
+minimal adjustment on gdb.server/run-without-local-binary.exp.
+
+Finally, I've implemented a new testcase,
+gdb.server/server-connect.exp, which is supposed to run on the native
+host and perform various "smoke tests" using different connection
+methods.
+
+This patch has been regression-tested on BuildBot and locally, and
+also built using a x86_64-w64-mingw32 GCC, and no problems were found.
+
+gdb/ChangeLog:
+2018-07-11 Sergio Durigan Junior <sergiodj@redhat.com>
+ Jan Kratochvil <jan.kratochvil@redhat.com>
+ Paul Fertser <fercerpav@gmail.com>
+ Tsutomu Seki <sekiriki@gmail.com>
+ Pedro Alves <palves@redhat.com>
+
+ * Makefile.in (SUBDIR_UNITTESTS_SRCS): Add
+ 'unittests/parse-connection-spec-selftests.c'.
+ (COMMON_SFILES): Add 'common/netstuff.c'.
+ (HFILES_NO_SRCDIR): Add 'common/netstuff.h'.
+ * NEWS (Changes since GDB 8.2): Mention IPv6 support.
+ * common/netstuff.c: New file.
+ * common/netstuff.h: New file.
+ * ser-tcp.c: Include 'netstuff.h' and 'wspiapi.h'.
+ (wait_for_connect): Update comment. New parameter
+ 'gdb::optional<int> sock' instead of 'struct serial *scb'.
+ Use 'sock' directly instead of 'scb->fd'.
+ (try_connect): New function, with code from 'net_open'.
+ (net_open): Rewrite main loop to deal with multiple
+ sockets/addresses. Handle IPv6-style hostnames; implement
+ support for IPv6 connections.
+ * unittests/parse-connection-spec-selftests.c: New file.
+
+gdb/gdbserver/ChangeLog:
+2018-07-11 Sergio Durigan Junior <sergiodj@redhat.com>
+ Jan Kratochvil <jan.kratochvil@redhat.com>
+ Paul Fertser <fercerpav@gmail.com>
+ Tsutomu Seki <sekiriki@gmail.com>
+
+ * Makefile.in (SFILES): Add '$(srcdir)/common/netstuff.c'.
+ (OBS): Add 'common/netstuff.o'.
+ (GDBREPLAY_OBS): Likewise.
+ * gdbreplay.c: Include 'wspiapi.h' and 'netstuff.h'.
+ (remote_open): Implement support for IPv6
+ connections.
+ * remote-utils.c: Include 'netstuff.h', 'filestuff.h'
+ and 'wspiapi.h'.
+ (handle_accept_event): Accept connections from IPv6 sources.
+ (remote_prepare): Handle IPv6-style hostnames; implement
+ support for IPv6 connections.
+ (remote_open): Implement support for printing connections from
+ IPv6 sources.
+
+gdb/testsuite/ChangeLog:
+2018-07-11 Sergio Durigan Junior <sergiodj@redhat.com>
+ Jan Kratochvil <jan.kratochvil@redhat.com>
+ Paul Fertser <fercerpav@gmail.com>
+ Tsutomu Seki <sekiriki@gmail.com>
+
+ * README (Testsuite Parameters): Mention new 'GDB_TEST_SOCKETHOST'
+ parameter.
+ * boards/native-extended-gdbserver.exp: Do not set 'sockethost'
+ by default.
+ * boards/native-gdbserver.exp: Likewise.
+ * gdb.server/run-without-local-binary.exp: Improve regexp used
+ for detecting when a remote debugging connection succeeds.
+ * gdb.server/server-connect.exp: New file.
+ * lib/gdbserver-support.exp (gdbserver_default_get_comm_port):
+ Do not prefix the port number with ":".
+ (gdbserver_start): New global GDB_TEST_SOCKETHOST. Implement
+ support for detecting and using it. Add '$debughost_gdbserver'
+ to the list of arguments used to start gdbserver. Handle case
+ when gdbserver cannot resolve a network name.
+
+gdb/doc/ChangeLog:
+2018-07-11 Sergio Durigan Junior <sergiodj@redhat.com>
+ Jan Kratochvil <jan.kratochvil@redhat.com>
+ Paul Fertser <fercerpav@gmail.com>
+ Tsutomu Seki <sekiriki@gmail.com>
+
+ * gdb.texinfo (Remote Connection Commands): Add explanation
+ about new IPv6 support. Add new connection prefixes.
+
+diff --git a/gdb/ChangeLog b/gdb/ChangeLog
+--- a/gdb/ChangeLog
++++ b/gdb/ChangeLog
+@@ -1,3 +1,26 @@
++2018-07-11 Sergio Durigan Junior <sergiodj@redhat.com>
++ Jan Kratochvil <jan.kratochvil@redhat.com>
++ Paul Fertser <fercerpav@gmail.com>
++ Tsutomu Seki <sekiriki@gmail.com>
++ Pedro Alves <palves@redhat.com>
++
++ * Makefile.in (SUBDIR_UNITTESTS_SRCS): Add
++ 'unittests/parse-connection-spec-selftests.c'.
++ (COMMON_SFILES): Add 'common/netstuff.c'.
++ (HFILES_NO_SRCDIR): Add 'common/netstuff.h'.
++ * NEWS (Changes since GDB 8.2): Mention IPv6 support.
++ * common/netstuff.c: New file.
++ * common/netstuff.h: New file.
++ * ser-tcp.c: Include 'netstuff.h' and 'wspiapi.h'.
++ (wait_for_connect): Update comment. New parameter
++ 'gdb::optional<int> sock' instead of 'struct serial *scb'.
++ Use 'sock' directly instead of 'scb->fd'.
++ (try_connect): New function, with code from 'net_open'.
++ (net_open): Rewrite main loop to deal with multiple
++ sockets/addresses. Handle IPv6-style hostnames; implement
++ support for IPv6 connections.
++ * unittests/parse-connection-spec-selftests.c: New file.
++
+ 2018-07-11 Pedro Alves <palves@redhat.com>
+
+ PR gdb/23377
+diff --git a/gdb/Makefile.in b/gdb/Makefile.in
+--- 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
+--- a/gdb/NEWS
++++ b/gdb/NEWS
+@@ -1,6 +1,12 @@
+ What has changed in GDB?
+ (Organized release by release)
+
++*** 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
+--- /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
+--- /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. */
++ explicit 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/ChangeLog b/gdb/doc/ChangeLog
+--- a/gdb/doc/ChangeLog
++++ b/gdb/doc/ChangeLog
+@@ -1,3 +1,11 @@
++2018-07-11 Sergio Durigan Junior <sergiodj@redhat.com>
++ Jan Kratochvil <jan.kratochvil@redhat.com>
++ Paul Fertser <fercerpav@gmail.com>
++ Tsutomu Seki <sekiriki@gmail.com>
++
++ * gdb.texinfo (Remote Connection Commands): Add explanation
++ about new IPv6 support. Add new connection prefixes.
++
+ 2018-07-02 Maciej W. Rozycki <macro@mips.com>
+
+ PR tdep/8282
+diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo
+--- a/gdb/doc/gdb.texinfo
++++ b/gdb/doc/gdb.texinfo
+@@ -20548,16 +20548,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}:
+@@ -20566,6 +20577,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
+@@ -20579,7 +20612,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/ChangeLog b/gdb/gdbserver/ChangeLog
+--- a/gdb/gdbserver/ChangeLog
++++ b/gdb/gdbserver/ChangeLog
+@@ -1,3 +1,22 @@
++2018-07-11 Sergio Durigan Junior <sergiodj@redhat.com>
++ Jan Kratochvil <jan.kratochvil@redhat.com>
++ Paul Fertser <fercerpav@gmail.com>
++ Tsutomu Seki <sekiriki@gmail.com>
++
++ * Makefile.in (SFILES): Add '$(srcdir)/common/netstuff.c'.
++ (OBS): Add 'common/netstuff.o'.
++ (GDBREPLAY_OBS): Likewise.
++ * gdbreplay.c: Include 'wspiapi.h' and 'netstuff.h'.
++ (remote_open): Implement support for IPv6
++ connections.
++ * remote-utils.c: Include 'netstuff.h', 'filestuff.h'
++ and 'wspiapi.h'.
++ (handle_accept_event): Accept connections from IPv6 sources.
++ (remote_prepare): Handle IPv6-style hostnames; implement
++ support for IPv6 connections.
++ (remote_open): Implement support for printing connections from
++ IPv6 sources.
++
+ 2018-07-11 Pedro Alves <palves@redhat.com>
+
+ PR gdb/23377
+diff --git a/gdb/gdbserver/Makefile.in b/gdb/gdbserver/Makefile.in
+--- 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
+--- 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
+--- 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
+--- 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 not -1, 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 (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 >= 0)
+ {
+ 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,28 @@ 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. Otherwise, return -1 and set ERRNO
++ accordingly. 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 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));
+-
+- 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)
++ if (sock < 0)
+ 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,21 +185,26 @@ 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);
++ errno = err;
++ return -1;
+ }
+
+ if (
++ /* 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. */
+ #ifdef USE_WIN32API
+ /* Under Windows, calling "connect" with a non-blocking socket
+ results in WSAEWOULDBLOCK, not WSAEINPROGRESS. */
+@@ -258,66 +214,166 @@ net_open (struct serial *scb, const char *name)
+ #endif
+ )
+ {
++ close (sock);
+ errno = err;
+- net_close (scb);
+ return -1;
+ }
+
+ /* 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);
++ int saved_errno = errno;
++
++ /* A negative value here means that we either timed out or
++ got interrupted by the user. Just return. */
++ close (sock);
++ errno = saved_errno;
+ 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)
++ {
++ int saved_errno = errno;
++
++ close (sock);
++ errno = saved_errno;
++ return -1;
++ }
++ else if (ret == 0 && err != 0)
++ {
++ close (sock);
++ errno = err;
++ return -1;
++ }
++
++ /* 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. */
++ int sock = try_connect (iter, &polls);
++
++ if (sock >= 0)
++ {
++ /* We've gotten a successful connection. Save its
++ 'struct addrinfo', the socket, and break. */
++ success_ainfo = iter;
++ scb->fd = sock;
++ break;
++ }
++ else if (
+ #ifdef USE_WIN32API
+- && err == WSAECONNREFUSED
++ errno == WSAECONNREFUSED
+ #else
+- && err == ECONNREFUSED
++ errno == ECONNREFUSED
+ #endif
+- && wait_for_connect (NULL, &polls) >= 0)
+- {
+- close (scb->fd);
+- goto retry;
+- }
+- if (err)
+- errno = err;
+- net_close (scb);
+- return -1;
+- }
+- }
++ )
++ got_connrefused = true;
++ }
++ }
++ /* 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 (-1, &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/ChangeLog b/gdb/testsuite/ChangeLog
+--- a/gdb/testsuite/ChangeLog
++++ b/gdb/testsuite/ChangeLog
+@@ -1,3 +1,23 @@
++2018-07-11 Sergio Durigan Junior <sergiodj@redhat.com>
++ Jan Kratochvil <jan.kratochvil@redhat.com>
++ Paul Fertser <fercerpav@gmail.com>
++ Tsutomu Seki <sekiriki@gmail.com>
++
++ * README (Testsuite Parameters): Mention new 'GDB_TEST_SOCKETHOST'
++ parameter.
++ * boards/native-extended-gdbserver.exp: Do not set 'sockethost'
++ by default.
++ * boards/native-gdbserver.exp: Likewise.
++ * gdb.server/run-without-local-binary.exp: Improve regexp used
++ for detecting when a remote debugging connection succeeds.
++ * gdb.server/server-connect.exp: New file.
++ * lib/gdbserver-support.exp (gdbserver_default_get_comm_port):
++ Do not prefix the port number with ":".
++ (gdbserver_start): New global GDB_TEST_SOCKETHOST. Implement
++ support for detecting and using it. Add '$debughost_gdbserver'
++ to the list of arguments used to start gdbserver. Handle case
++ when gdbserver cannot resolve a network name.
++
+ 2018-07-11 Sergio Durigan Junior <sergiodj@redhat.com>
+
+ PR c++/23373
+diff --git a/gdb/testsuite/README b/gdb/testsuite/README
+--- 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
+--- 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
+--- 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
+--- 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
+--- /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
+--- 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}:"
++ # Escape 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
+--- /dev/null
++++ b/gdb/unittests/parse-connection-spec-selftests.c
+@@ -0,0 +1,249 @@
++/* Self tests for parsing connection specs for GDB, the GNU debugger.
++
++ 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 "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 }
++
++/* Initialize an unprefixed entry. In this case, we don't expect
++ anything 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 anything 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, 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 present. */
++ 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 present. */
++ 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 present. */
++ 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 present. */
++ 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 present. */
++ 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);
++}
diff --git a/gdb-rhbz881849-ipv6-2of2.patch b/gdb-rhbz881849-ipv6-2of2.patch
new file mode 100644
index 0000000..339c966
--- /dev/null
+++ b/gdb-rhbz881849-ipv6-2of2.patch
@@ -0,0 +1,63 @@
+From FEDORA_PATCHES Mon Sep 17 00:00:00 2001
+From: Sergio Durigan Junior <sergiodj@redhat.com>
+Date: Fri, 13 Jul 2018 16:20:34 -0400
+Subject: gdb-rhbz881849-ipv6-2of2.patch
+
+;; Implement IPv6 support for GDB/gdbserver (RH BZ 881849, Sergio Durigan Junior).
+
+Expect for another variant of error message when gdbserver cannot resolve hostname
+
+I've noticed that on a few hosts, when given an invalid hostname,
+gdbserver fails with:
+
+ spawn /../../gdb/gdbserver/gdbserver --once tcp8:123:2353 /gdb/build/fedora-s390x/build/gdb/testsuite/outputs/gdb.server/server-connect/server-connect
+ tcp8:123:2353: cannot resolve name: No address associated with hostname
+ ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
+ Exiting
+
+Unfortunately, this causes a fail on the new
+gdb.server/server-connect.exp test (introduced by the IPv6 patch):
+
+ FAIL: gdb.server/server-connect.exp: tcp8: start gdbserver: gdbserver should fail but did not
+
+This happens because we're expecting for another variant of this error
+message:
+
+ cannot resolve name: Name or service not known
+
+Therefore, this patch extends the helper function 'gdbserver_start' to
+also recognize the "No address associated with hostname" message.
+This "fixes" the testcase on the hosts that use this variant.
+
+gdb/testsuite/ChangeLog:
+2018-07-13 Sergio Durigan Junior <sergiodj@redhat.com>
+
+ * lib/gdbserver-support.exp (gdbserver_start): Expect for the
+ message "No address associated with hostname" when gdbserver
+ cannot resolve the hostname.
+
+diff --git a/gdb/testsuite/ChangeLog b/gdb/testsuite/ChangeLog
+--- a/gdb/testsuite/ChangeLog
++++ b/gdb/testsuite/ChangeLog
+@@ -1,3 +1,9 @@
++2018-07-13 Sergio Durigan Junior <sergiodj@redhat.com>
++
++ * lib/gdbserver-support.exp (gdbserver_start): Expect for the
++ message "No address associated with hostname" when gdbserver
++ cannot resolve the hostname.
++
+ 2018-07-11 Sergio Durigan Junior <sergiodj@redhat.com>
+ Jan Kratochvil <jan.kratochvil@redhat.com>
+ Paul Fertser <fercerpav@gmail.com>
+diff --git a/gdb/testsuite/lib/gdbserver-support.exp b/gdb/testsuite/lib/gdbserver-support.exp
+--- a/gdb/testsuite/lib/gdbserver-support.exp
++++ b/gdb/testsuite/lib/gdbserver-support.exp
+@@ -326,7 +326,7 @@ proc gdbserver_start { options arguments } {
+ continue
+ }
+ }
+- -re ".*: cannot resolve name: Name or service not known\r\n" {
++ -re ".*: cannot resolve name: \(No address associated with hostname|Name or service not known\)\r\n" {
+ error "gdbserver cannot resolve name."
+ }
+ timeout {
diff --git a/gdb.spec b/gdb.spec
index 77a99c2..fc6d32b 100644
--- a/gdb.spec
+++ b/gdb.spec
@@ -18,7 +18,7 @@
Name: %{?scl_prefix}gdb
# Freeze it when GDB gets branched
-%global snapsrc 20180708
+%global snapsrc 20180714
# See timestamp of source gnulib installed into gdb/gnulib/ .
%global snapgnulib 20161115
%global tarname gdb-%{version}
@@ -26,7 +26,7 @@ Version: 8.1.90.%{snapsrc}
# The release always contains a leading reserved number, start it at 1.
# `upstream' is not a part of `name' to stay fully rpm dependencies compatible for the testing.
-Release: 34%{?dist}
+Release: 35%{?dist}
License: GPLv3+ and GPLv3+ with exceptions and GPLv2+ and GPLv2+ with exceptions and GPL+ and LGPLv2+ and LGPLv3+ and BSD and Public Domain and GFDL
Group: Development/Debuggers
@@ -1030,6 +1030,10 @@ fi
%endif
%changelog
+* Sat Jul 14 2018 Sergio Durigan Junior <sergiodj@redhat.com> - 8.1.90.20180714-35.fc29
+- Rebase to FSF GDB 8.1.90.20180714 (8.2pre).
+- Backport IPv6 patch (RH BZ 881849, Sergio Durigan Junior).
+
* Fri Jul 13 2018 Fedora Release Engineering <releng@fedoraproject.org>
- Rebuilt for https://fedoraproject.org/wiki/Fedora_29_Mass_Rebuild
^ permalink raw reply related [flat|nested] only message in thread
only message in thread, other threads:[~2026-06-27 23:58 UTC | newest]
Thread overview: (only message) (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2026-06-27 23:58 [rpms/gdb] gdb-17.2-rebase-f44: Rebase to FSF GDB 8.1.90.20180714 (8.2pre) Sergio Durigan Junior
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox