From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 17026 invoked by alias); 9 Oct 2006 14:17:00 -0000 Received: (qmail 16998 invoked by uid 22791); 9 Oct 2006 14:16:56 -0000 X-Spam-Check-By: sourceware.org Received: from 195.22.55.53.adsl.nextra.cz (HELO host0.dyn.jankratochvil.net) (195.22.55.53) by sourceware.org (qpsmtpd/0.31) with ESMTP; Mon, 09 Oct 2006 14:16:48 +0000 Received: from host0.dyn.jankratochvil.net (localhost [127.0.0.1]) by host0.dyn.jankratochvil.net (8.13.8/8.13.8) with ESMTP id k99EGZrb023546; Mon, 9 Oct 2006 16:16:35 +0200 Received: (from jkratoch@localhost) by host0.dyn.jankratochvil.net (8.13.8/8.13.8/Submit) id k99EGZl8023545; Mon, 9 Oct 2006 16:16:35 +0200 Date: Mon, 09 Oct 2006 14:17:00 -0000 From: Jan Kratochvil To: Eli Zaretskii Cc: gdb-patches@sourceware.org Subject: Re: [patch] IPv6 support for gdbserver Message-ID: <20061009141634.GA392@host0.dyn.jankratochvil.net> References: <20060927163337.GA27149@host0.dyn.jankratochvil.net> <20060927182038.GA5635@nevyn.them.org> <20060927185547.GA13544@host0.dyn.jankratochvil.net> <20060927190611.GA7326@nevyn.them.org> <20060930152757.GA27372@host0.dyn.jankratochvil.net> <20061008190239.GA29584@host0.dyn.jankratochvil.net> Mime-Version: 1.0 Content-Type: multipart/mixed; boundary="yrj/dFKFPuw6o+aM" Content-Disposition: inline In-Reply-To: User-Agent: Mutt/1.4.2.2i X-IsSubscribed: yes Mailing-List: contact gdb-patches-help@sourceware.org; run by ezmlm Precedence: bulk List-Subscribe: List-Archive: List-Post: List-Help: , Sender: gdb-patches-owner@sourceware.org X-SW-Source: 2006-10/txt/msg00075.txt.bz2 --yrj/dFKFPuw6o+aM Content-Type: text/plain; charset=us-ascii Content-Disposition: inline Content-length: 5737 Hi Eli, the first patch (formerly "gdb-cvs-IPv6-fds-plus.patch") updated. On Mon, 09 Oct 2006 06:33:09 +0200, Eli Zaretskii wrote: ... > > -@item target remote @code{@var{host}:@var{port}} > > +@item target remote @code{@var{host}:@var{port}} > > This just changes whitespace; please don't. OK. [ Code written before I read such advice from Mark Kettenis. ] > > +@code{tcp6:} prefix forces IPv6 network connection while @code{tcp4:} forces > > Please say ``The @code{tcp6:} prefix forces IPv6 network ...''. OK. > > +@code{udp6:} prefix forces IPv6 network connection while @code{udp4:} forces > > Same here. OK. > > +@var{comm} is either a device name (to use a serial line) or file descriptions > > +numbers or a TCP hostname and portnumber. For example, to debug Emacs with the > > A better way of putting it would be > > @var{comm} is a device name (to use a serial line), a file descriptor, > or a TCP hostname and portnumber. OK. [ Assumed the "hostname" part will get dropped by the second patch. ] > > -The only difference from the previous example is the first argument, > > -specifying that you are communicating with the host @value{GDBN} via > > -TCP. The @samp{host:2345} argument means that @code{gdbserver} is to > > -expect a TCP connection from machine @samp{host} to local TCP port 2345. > > -(Currently, the @samp{host} part is ignored.) You can choose any number > > -you want for the port number as long as it does not conflict with any > > -TCP ports already in use on the target system (for example, @code{23} is > > -reserved for @code{telnet}).@footnote{If you choose a port number that > > -conflicts with another service, @code{gdbserver} prints an error message > > -and exits.} You must use the same port number with the host @value{GDBN} > > -@code{target remote} command. > > Why did you drop this part? Only its first part was dropped - till "You can choose any port number ...". The first sentence was reformulated as it is generally more complicated command using socat(1) and so it is not "the only difference". The part with "@samp{host}" part has been dropped completely as it never got implemented (the "@samp{host}" part is still being ignored nowadays) and it is no longer implementable on top of socat(1), moreover the whole "@samp{host:port}" syntax has been considered as obsolete by the second patch. Patch not changed in this case. > > +This example still debugs the same program just in this case it is specifying > > +that you are communicating with the host @value{GDBN} via TCP. > > +The @code{gdbserver} specific part @code{fd34} directs @code{gdbserver} to use > > +already preopened file descriptor 3 for @value{GDBN} remote serial protocol > > +input and file descriptor 4 for the protocol output. As the format is > > +@code{fd} you cannot specify file descriptors numbers > > +above 9. > > First, please use @var{} instead of <..>, as in > @code{fd@var{c1}@var{c2}} (I find too lengthy). > > And second, isn't there a better way of specifying two descriptors? I > find the "fdNM" method inelegant, and the limitation of a single-digit > descriptor it requires too high a price to pay. I hope we can come up > with a better method. Designed for trivia C parsing as the IPv6 support was considered too complicated by Daniel Jacobowitz and the string parsing in C is a lot of lines. The new syntax looks like that of socat(1): socat EXEC:'gdbserver fdin=3,fdout=4 emacs foo.txt',fdin=3,fdout=4 TCP-LISTEN:2345 > > +You can choose any port number you want (@code{2345} here) as long as it does > > +not conflict with any TCP ports already in use on the target system (for > > +example, @code{23} is reserved for @code{telnet}).@footnote{If you choose > > +a port number that conflicts with another service, @code{socat} prints an error > > +message and exits.} You must use the same port number with the host > > +@value{GDBN} @code{target remote} command. > > + > > +On IPv4 networks you may also run @code{gdbserver} directly, without the > > +@code{socat} helper there (equivalent command to the example above): > > + > > +@smallexample > > +target> gdbserver :2345 emacs foo.txt > > +@end smallexample > > The example (and the sentence that precedes it) should be before the > descriptive text, otherwise the text doesn't make sense. The first paragraph describes the line above it: socat EXEC:'gdbserver fdin=3,fdout=4 emacs foo.txt',fdin=3,fdout=4 TCP-LISTEN:2345 It looks weird to me to move the deprecated syntax above the first paragraph describing the port in 2345 general (primarily for the new socat(1) syntax). Moreover even the following paragraph starting "On some targets, @code{gdbserver} can also attach ..." precedes its sample code below it. Text reshuffled although the port description is still above - for the socat(1) syntax. Otherwise the whole text should be reorganized to keep the IPv4 "host:port" syntax as the preferred one and socat(1) syntax as the secondary one. For example I personally do not like the requirement to use socat(1) at the resource-limited embedded systems running gdbserver(1) at all. > > * gdb.texinfo (Using the gdbserver program): Remove "host:port". > > Why? I think back-compatibility is important. It looks broken to me to support IPv4 without supporting IPv6, moreover if the IPv6 functions to use are simpler. I hope you are aware of the former full IPv6 support posted here: http://sourceware.org/ml/gdb-patches/2006-09/msg00216.html The second patch "gdb-cvs-IPv6-hostport-minus.patch" was not updated for this one as it looks as the IPv4 legacy code is not going to be dropped even with the socat(1) support there. Thanks, Jan --yrj/dFKFPuw6o+aM Content-Type: text/plain; charset=us-ascii Content-Disposition: attachment; filename="gdb-cvs-IPv6-fds.patch" Content-length: 33838 gdb: 2006-10-09 Jan Kratochvil * ser-tcp.c (net_open): Support IPv6 "tcp6:"&co. notation. * configure.ac: Check for IPv6 getaddrinfo, getnameinfo and AF_INET6. * configure, config.in: Regenerate. gdb/gdbserver: 2006-10-09 Jan Kratochvil * gdbreplay.c (remote_open, main): Support "fdin=...," fds argument. (remote_desc_in, remote_desc_out, remote_close, remote_open, expect, play): Replace `remote_desc' by `remote_desc_in' and `remote_desc_out'. * remote-utils.c (remote_desc_in, remote_desc_out, remote_close, remote_open, putpkt_binary, input_interrupt, readchar, getpkt): Replace `remote_desc' by `remote_desc_in' and `remote_desc_out'. * server.c (gdbserver_usage): Descripe "fdin=...," fds argument. gdb/doc: 2006-10-09 Jan Kratochvil * gdb.texinfo (Connecting to a remote target): Describe IPv6 "tcp6:"&co. notation. (Using the gdbserver program): Describe "fdin=...," comm notation. diff -u -p -r1.84 config.in --- gdb/config.in 8 Aug 2006 20:32:15 -0000 1.84 +++ gdb/config.in 9 Oct 2006 14:02:29 -0000 @@ -67,6 +67,10 @@ /* Define to 1 if you have the header file. */ #undef HAVE_CURSES_H +/* Define to 1 if you have the declaration of `AF_INET6', and to 0 if you + don't. */ +#undef HAVE_DECL_AF_INET6 + /* Define to 1 if you have the declaration of `free', and to 0 if you don't. */ #undef HAVE_DECL_FREE @@ -113,9 +117,15 @@ /* Define if has fpregset_t. */ #undef HAVE_FPREGSET_T +/* Define to 1 if you have the `getaddrinfo' function. */ +#undef HAVE_GETADDRINFO + /* Define to 1 if you have the `getgid' function. */ #undef HAVE_GETGID +/* Define to 1 if you have the `getnameinfo' function. */ +#undef HAVE_GETNAMEINFO + /* Define to 1 if you have the `getpagesize' function. */ #undef HAVE_GETPAGESIZE diff -u -p -r1.213 configure --- gdb/configure 8 Aug 2006 20:32:15 -0000 1.213 +++ gdb/configure 9 Oct 2006 14:02:32 -0000 @@ -17453,6 +17453,285 @@ fi done +for ac_func in getaddrinfo +do +as_ac_var=`echo "ac_cv_func_$ac_func" | $as_tr_sh` +echo "$as_me:$LINENO: checking for $ac_func" >&5 +echo $ECHO_N "checking for $ac_func... $ECHO_C" >&6 +if eval "test \"\${$as_ac_var+set}\" = set"; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +/* Define $ac_func to an innocuous variant, in case declares $ac_func. + For example, HP-UX 11i declares gettimeofday. */ +#define $ac_func innocuous_$ac_func + +/* System header to define __stub macros and hopefully few prototypes, + which can conflict with char $ac_func (); below. + Prefer to if __STDC__ is defined, since + exists even on freestanding compilers. */ + +#ifdef __STDC__ +# include +#else +# include +#endif + +#undef $ac_func + +/* Override any gcc2 internal prototype to avoid an error. */ +#ifdef __cplusplus +extern "C" +{ +#endif +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char $ac_func (); +/* The GNU C library defines this for functions which it implements + to always fail with ENOSYS. Some functions are actually named + something starting with __ and the normal name is an alias. */ +#if defined (__stub_$ac_func) || defined (__stub___$ac_func) +choke me +#else +char (*f) () = $ac_func; +#endif +#ifdef __cplusplus +} +#endif + +int +main () +{ +return f != $ac_func; + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 + (eval $ac_link) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" + || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest$ac_exeext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + eval "$as_ac_var=yes" +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +eval "$as_ac_var=no" +fi +rm -f conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +fi +echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_var'}'`" >&5 +echo "${ECHO_T}`eval echo '${'$as_ac_var'}'`" >&6 +if test `eval echo '${'$as_ac_var'}'` = yes; then + cat >>confdefs.h <<_ACEOF +#define `echo "HAVE_$ac_func" | $as_tr_cpp` 1 +_ACEOF + +fi +done + + +for ac_func in getnameinfo +do +as_ac_var=`echo "ac_cv_func_$ac_func" | $as_tr_sh` +echo "$as_me:$LINENO: checking for $ac_func" >&5 +echo $ECHO_N "checking for $ac_func... $ECHO_C" >&6 +if eval "test \"\${$as_ac_var+set}\" = set"; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +/* Define $ac_func to an innocuous variant, in case declares $ac_func. + For example, HP-UX 11i declares gettimeofday. */ +#define $ac_func innocuous_$ac_func + +/* System header to define __stub macros and hopefully few prototypes, + which can conflict with char $ac_func (); below. + Prefer to if __STDC__ is defined, since + exists even on freestanding compilers. */ + +#ifdef __STDC__ +# include +#else +# include +#endif + +#undef $ac_func + +/* Override any gcc2 internal prototype to avoid an error. */ +#ifdef __cplusplus +extern "C" +{ +#endif +/* We use char because int might match the return type of a gcc2 + builtin and then its argument prototype would still apply. */ +char $ac_func (); +/* The GNU C library defines this for functions which it implements + to always fail with ENOSYS. Some functions are actually named + something starting with __ and the normal name is an alias. */ +#if defined (__stub_$ac_func) || defined (__stub___$ac_func) +choke me +#else +char (*f) () = $ac_func; +#endif +#ifdef __cplusplus +} +#endif + +int +main () +{ +return f != $ac_func; + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext conftest$ac_exeext +if { (eval echo "$as_me:$LINENO: \"$ac_link\"") >&5 + (eval $ac_link) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" + || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest$ac_exeext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + eval "$as_ac_var=yes" +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +eval "$as_ac_var=no" +fi +rm -f conftest.err conftest.$ac_objext \ + conftest$ac_exeext conftest.$ac_ext +fi +echo "$as_me:$LINENO: result: `eval echo '${'$as_ac_var'}'`" >&5 +echo "${ECHO_T}`eval echo '${'$as_ac_var'}'`" >&6 +if test `eval echo '${'$as_ac_var'}'` = yes; then + cat >>confdefs.h <<_ACEOF +#define `echo "HAVE_$ac_func" | $as_tr_cpp` 1 +_ACEOF + +fi +done + +echo "$as_me:$LINENO: checking whether AF_INET6 is declared" >&5 +echo $ECHO_N "checking whether AF_INET6 is declared... $ECHO_C" >&6 +if test "${ac_cv_have_decl_AF_INET6+set}" = set; then + echo $ECHO_N "(cached) $ECHO_C" >&6 +else + cat >conftest.$ac_ext <<_ACEOF +/* confdefs.h. */ +_ACEOF +cat confdefs.h >>conftest.$ac_ext +cat >>conftest.$ac_ext <<_ACEOF +/* end confdefs.h. */ +#include +#include + + +int +main () +{ +#ifndef AF_INET6 + char *p = (char *) AF_INET6; +#endif + + ; + return 0; +} +_ACEOF +rm -f conftest.$ac_objext +if { (eval echo "$as_me:$LINENO: \"$ac_compile\"") >&5 + (eval $ac_compile) 2>conftest.er1 + ac_status=$? + grep -v '^ *+' conftest.er1 >conftest.err + rm -f conftest.er1 + cat conftest.err >&5 + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); } && + { ac_try='test -z "$ac_c_werror_flag" + || test ! -s conftest.err' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; } && + { ac_try='test -s conftest.$ac_objext' + { (eval echo "$as_me:$LINENO: \"$ac_try\"") >&5 + (eval $ac_try) 2>&5 + ac_status=$? + echo "$as_me:$LINENO: \$? = $ac_status" >&5 + (exit $ac_status); }; }; then + ac_cv_have_decl_AF_INET6=yes +else + echo "$as_me: failed program was:" >&5 +sed 's/^/| /' conftest.$ac_ext >&5 + +ac_cv_have_decl_AF_INET6=no +fi +rm -f conftest.err conftest.$ac_objext conftest.$ac_ext +fi +echo "$as_me:$LINENO: result: $ac_cv_have_decl_AF_INET6" >&5 +echo "${ECHO_T}$ac_cv_have_decl_AF_INET6" >&6 +if test $ac_cv_have_decl_AF_INET6 = yes; then + +cat >>confdefs.h <<_ACEOF +#define HAVE_DECL_AF_INET6 1 +_ACEOF + + +else + cat >>confdefs.h <<_ACEOF +#define HAVE_DECL_AF_INET6 0 +_ACEOF + + +fi + + + # Check the return and argument types of ptrace. No canned test for # this, so roll our own. gdb_ptrace_headers=' @@ -22335,7 +22614,7 @@ ac_x_header_dirs=' /usr/openwin/share/include' if test "$ac_x_includes" = no; then - # Guess where to find include files, by looking for Intrinsic.h. + # Guess where to find include files, by looking for Xlib.h. # First, try using that file with no special directory specified. cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ @@ -22343,7 +22622,7 @@ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ -#include +#include _ACEOF if { (eval echo "$as_me:$LINENO: \"$ac_cpp conftest.$ac_ext\"") >&5 (eval $ac_cpp conftest.$ac_ext) 2>conftest.er1 @@ -22370,7 +22649,7 @@ else sed 's/^/| /' conftest.$ac_ext >&5 for ac_dir in $ac_x_header_dirs; do - if test -r "$ac_dir/X11/Intrinsic.h"; then + if test -r "$ac_dir/X11/Xlib.h"; then ac_x_includes=$ac_dir break fi @@ -22384,18 +22663,18 @@ if test "$ac_x_libraries" = no; then # See if we find them without any special options. # Don't add to $LIBS permanently. ac_save_LIBS=$LIBS - LIBS="-lXt $LIBS" + LIBS="-lX11 $LIBS" cat >conftest.$ac_ext <<_ACEOF /* confdefs.h. */ _ACEOF cat confdefs.h >>conftest.$ac_ext cat >>conftest.$ac_ext <<_ACEOF /* end confdefs.h. */ -#include +#include int main () { -XtMalloc (0) +XrmInitialize () ; return 0; } diff -u -p -r1.34 configure.ac --- gdb/configure.ac 8 Aug 2006 20:26:23 -0000 1.34 +++ gdb/configure.ac 9 Oct 2006 14:02:32 -0000 @@ -446,6 +446,12 @@ AC_CHECK_FUNCS(socketpair) AC_CHECK_FUNCS(syscall) AC_CHECK_FUNCS(ttrace) AC_CHECK_FUNCS(wborder) +AC_CHECK_FUNCS(getaddrinfo) +AC_CHECK_FUNCS(getnameinfo) +AC_CHECK_DECLS(AF_INET6, [], [], +[#include +#include +]) # Check the return and argument types of ptrace. No canned test for # this, so roll our own. diff -u -p -r1.26 ser-tcp.c --- gdb/ser-tcp.c 10 Feb 2006 22:01:43 -0000 1.26 +++ gdb/ser-tcp.c 9 Oct 2006 14:02:32 -0000 @@ -68,67 +68,142 @@ void _initialize_ser_tcp (void); int net_open (struct serial *scb, const char *name) { - char *port_str, hostname[100]; - int n, port, tmp; - int use_udp; - struct hostent *hostent; - struct sockaddr_in sockaddr; + char *name_base; + char *port_str; + int n, tmp; #ifdef USE_WIN32API u_long ioarg; #else int ioarg; #endif - - use_udp = 0; - if (strncmp (name, "udp:", 4) == 0) + struct prefix + { + const char *string; + int family; + int socktype; + }; + const struct prefix prefixes[] = { - use_udp = 1; - name = name + 4; + { "udp:", AF_UNSPEC, SOCK_DGRAM }, + { "tcp:", AF_UNSPEC, SOCK_STREAM }, + { "udp4:", AF_INET, SOCK_DGRAM }, + { "tcp4:", AF_INET, SOCK_STREAM }, +/* We do not support `AF_INET6' without getaddrinfo(3). */ +#if defined (HAVE_GETADDRINFO) && HAVE_DECL_AF_INET6 + { "udp6:", AF_INET6, SOCK_DGRAM }, + { "tcp6:", AF_INET6, SOCK_STREAM }, +#endif /* defined (HAVE_GETADDRINFO) && HAVE_DECL_AF_INET6 */ + }; + const struct prefix *prefix; +#ifdef HAVE_GETADDRINFO + struct addrinfo hints; + struct addrinfo *addrinfo_base, *addrinfo = NULL; +#else /* !HAVE_GETADDRINFO */ + struct hostent *hostent; + struct sockaddr_in sockaddr; +#endif /* !HAVE_GETADDRINFO */ + /* Error by default. */ + int retval = -1; + + name_base = xstrdup (name); + name = name_base; +#ifdef HAVE_GETADDRINFO + memset (&hints, 0, sizeof (hints)); + hints.ai_family = AF_UNSPEC; + hints.ai_flags = AI_ADDRCONFIG; +#endif /* HAVE_GETADDRINFO */ + for (prefix = prefixes; prefix < prefixes + ARRAY_SIZE (prefixes); prefix++) + if (strncmp (name, prefix->string, strlen (prefix->string)) == 0) + { + name += strlen (prefix->string); +#ifdef HAVE_GETADDRINFO + hints.ai_family = prefix->family; + hints.ai_socktype = prefix->socktype; +#endif /* HAVE_GETADDRINFO */ + break; + } + if (prefix >= prefixes + ARRAY_SIZE (prefixes)) + prefix = NULL; + if ((prefix == NULL || prefix->family != AF_INET) + && name[0] == '[' && (port_str = strchr (name, ']'))) + { + name++; + *port_str++ = 0; + } + else + port_str = strchr (name, ':'); + /* It may happen with IPv6 for like "[::1]". */ + if (port_str == NULL || *port_str != ':') + error (_("net_open: No colon in host name!")); + *port_str++ = 0; + + /* Default hostname for `node == NULL' is localhost + as we did not specify `hints.ai_flags & AI_PASSIVE'. */ + if (name[0] == 0) + name = NULL; + +#ifdef HAVE_GETADDRINFO + n = getaddrinfo (name, port_str, &hints, &addrinfo_base); + if (n != 0) + { + fprintf_unfiltered (gdb_stderr, "%s:%s: cannot resolve name: %s\n", + (name != NULL ? name : ""), + port_str, gai_strerror (n)); + errno = ENOENT; + free (name_base); + return -1; } - else if (strncmp (name, "tcp:", 4) == 0) - name = name + 4; - - port_str = strchr (name, ':'); - - if (!port_str) - error (_("net_open: No colon in host name!")); /* Shouldn't ever happen */ - - 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 hostname is localhost */ - if (!hostname[0]) - strcpy (hostname, "localhost"); + /* Still used for `port_str' above. */ + free (name_base); - hostent = gethostbyname (hostname); - if (!hostent) + for (addrinfo = addrinfo_base; addrinfo != NULL; addrinfo = addrinfo->ai_next) + { + scb->fd = socket (addrinfo->ai_family, addrinfo->ai_socktype, + addrinfo->ai_protocol); + if (scb->fd >= 0) + break; + } + if (addrinfo == NULL) { - fprintf_unfiltered (gdb_stderr, "%s: unknown host\n", hostname); + freeaddrinfo (addrinfo_base); + return -1; + } +#else /* !HAVE_GETADDRINFO */ + hostent = gethostbyname ((name != NULL ? name : "localhost")); + if (hostent == NULL) + { + fprintf_unfiltered (gdb_stderr, "%s: unknown host\n", name); errno = ENOENT; + free (name_base); return -1; } - if (use_udp) - scb->fd = socket (PF_INET, SOCK_DGRAM, 0); - else - scb->fd = socket (PF_INET, SOCK_STREAM, 0); + sockaddr.sin_family = PF_INET; + sockaddr.sin_port = htons (atoi (port_str)); + memcpy (&sockaddr.sin_addr.s_addr, hostent->h_addr, + sizeof (struct in_addr)); + /* Still used for `port_str' above. */ + free (name_base); + + scb->fd = socket (sockaddr.sin_family, + (prefix != NULL ? prefix->socktype : SOCK_STREAM), + 0); if (scb->fd < 0) 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)); +#endif /* !HAVE_GETADDRINFO */ /* set socket nonblocking */ ioarg = 1; ioctl (scb->fd, FIONBIO, &ioarg); /* Use Non-blocking connect. connect() will return 0 if connected already. */ +#ifdef HAVE_GETADDRINFO + n = connect (scb->fd, addrinfo->ai_addr, addrinfo->ai_addrlen); +#else /* !HAVE_GETADDRINFO */ n = connect (scb->fd, (struct sockaddr *) &sockaddr, sizeof (sockaddr)); +#endif /* !HAVE_GETADDRINFO */ if (n < 0 #ifdef USE_WIN32API @@ -143,8 +218,7 @@ net_open (struct serial *scb, const char #ifdef USE_WIN32API errno = WSAGetLastError(); #endif - net_close (scb); - return -1; + goto cleanup_scb; } if (n) @@ -165,8 +239,7 @@ net_open (struct serial *scb, const char if (deprecated_ui_loop_hook (0)) { errno = EINTR; - net_close (scb); - return -1; + goto cleanup_scb; } } @@ -192,8 +265,7 @@ net_open (struct serial *scb, const char { if (polls > TIMEOUT * POLL_INTERVAL) errno = ETIMEDOUT; - net_close (scb); - return -1; + goto cleanup_scb; } } @@ -211,8 +283,7 @@ net_open (struct serial *scb, const char { if (err) errno = err; - net_close (scb); - return -1; + goto cleanup_scb; } } @@ -220,7 +291,7 @@ net_open (struct serial *scb, const char ioarg = 0; ioctl (scb->fd, FIONBIO, &ioarg); - if (use_udp == 0) + if (prefix == NULL || prefix->socktype == SOCK_STREAM) { /* Disable Nagle algorithm. Needed in some cases. */ tmp = 1; @@ -234,7 +305,16 @@ net_open (struct serial *scb, const char signal (SIGPIPE, SIG_IGN); #endif - return 0; + retval = 0; + goto cleanup_addrinfo_base; + +cleanup_scb: + net_close (scb); +cleanup_addrinfo_base: +#ifdef HAVE_GETADDRINFO + freeaddrinfo (addrinfo_base); +#endif /* HAVE_GETADDRINFO */ + return retval; } void diff -u -p -r1.355 gdb.texinfo --- gdb/doc/gdb.texinfo 21 Sep 2006 14:01:12 -0000 1.355 +++ gdb/doc/gdb.texinfo 9 Oct 2006 14:02:42 -0000 @@ -12406,6 +12406,8 @@ If you're using a serial line, you may w @item target remote @code{@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}} @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} @@ -12414,6 +12416,9 @@ the target machine itself, if it is dire it might be a terminal server which in turn has a serial line to the target. +The @code{tcp6:} prefix forces IPv6 network connection while @code{tcp4:} +forces IPv4, both on the reliable stream TCP connection. + For example, to connect to port 2828 on a terminal server named @code{manyfarms}: @@ -12434,10 +12439,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{udp6:@var{host}:@var{port}} +@itemx target remote @code{udp4:@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}: +The @code{udp6:} prefix forces IPv6 network connection while @code{udp4:} +forces IPv4, both on the unreliable datagram UDP connection. + @smallexample target remote udp:manyfarms:2828 @end smallexample @@ -12556,9 +12566,9 @@ syntax is: target> gdbserver @var{comm} @var{program} [ @var{args} @dots{} ] @end smallexample -@var{comm} is either a device name (to use a serial line) or a TCP -hostname and portnumber. For example, to debug Emacs with the argument -@samp{foo.txt} and communicate with @value{GDBN} over the serial port +@var{comm} is a device name (to use a serial line), a file descriptor, +or a TCP hostname and portnumber. For example, to debug Emacs with the +argument @samp{foo.txt} and communicate with @value{GDBN} over the serial port @file{/dev/com1}: @smallexample @@ -12571,20 +12581,33 @@ with it. To use a TCP connection instead of a serial line: @smallexample -target> gdbserver host:2345 emacs foo.txt +target> socat EXEC:'gdbserver fdin=3,fdout=4 emacs foo.txt',fdin=3,fdout=4 TCP-LISTEN:2345 +@end smallexample + +This example still debugs the same program just in this case it is specifying +that you are communicating with the host @value{GDBN} via TCP. +The @code{gdbserver} specific part @code{fd34} directs @code{gdbserver} to use +already preopened file descriptor 3 for @value{GDBN} remote serial protocol +input and file descriptor 4 for the protocol output. Do not use the file +descriptors 0, 1 or 2 as the @value{GDBN} protocol communication could get +corrupted by the inferior program's stdio. + +Please check external @code{socat} program documentation for other available +network options (such as using @code{TCP6-LISTEN} for IPv6 networks). + +You can choose any port number you want (@code{2345} here) as long as it does +not conflict with any TCP ports already in use on the target system (for +example, @code{23} is reserved for @code{telnet}).@footnote{If you choose +a port number that conflicts with another service, @code{socat} prints an error +message and exits.} You must use the same port number with the host +@value{GDBN} @code{target remote} command. + +@smallexample +target> gdbserver :2345 emacs foo.txt @end smallexample -The only difference from the previous example is the first argument, -specifying that you are communicating with the host @value{GDBN} via -TCP. The @samp{host:2345} argument means that @code{gdbserver} is to -expect a TCP connection from machine @samp{host} to local TCP port 2345. -(Currently, the @samp{host} part is ignored.) You can choose any number -you want for the port number as long as it does not conflict with any -TCP ports already in use on the target system (for example, @code{23} is -reserved for @code{telnet}).@footnote{If you choose a port number that -conflicts with another service, @code{gdbserver} prints an error message -and exits.} You must use the same port number with the host @value{GDBN} -@code{target remote} command. +On IPv4 networks you may also run @code{gdbserver} directly as shown above, +without the @code{socat} helper there. On some targets, @code{gdbserver} can also attach to running programs. This is accomplished via the @code{--attach} argument. The syntax is: diff -u -p -r1.12 gdbreplay.c --- gdb/gdbserver/gdbreplay.c 23 Jul 2006 03:52:15 -0000 1.12 +++ gdb/gdbserver/gdbreplay.c 9 Oct 2006 14:02:42 -0000 @@ -61,7 +61,7 @@ typedef int socklen_t; /* Sort of a hack... */ #define EOL (EOF - 1) -static int remote_desc; +static int remote_desc_in, remote_desc_out; /* Print the system error message for errno, and also mention STRING as the file name for which the error was encountered. @@ -103,26 +103,80 @@ static void remote_close (void) { #ifdef USE_WIN32API - closesocket (remote_desc); + closesocket (remote_desc_in); + if (remote_desc_in != remote_desc_out) + closesocket (remote_desc_out); #else - close (remote_desc); + close (remote_desc_in); + if (remote_desc_in != remote_desc_out) + close (remote_desc_out); #endif } +/* Parse the string "fdin=<#>,fdout=<#>" into `remote_desc_in' and + `remote_desc_out' file descripts. Return non-zero for success. */ + +static int +parse_fds (char *name) +{ + const char *fdin_string = "fdin="; + size_t fdin_string_len = strlen (fdin_string); + const char *comma_fdout_string = ",fdout="; + size_t comma_fdout_string_len = strlen (comma_fdout_string); + long l; + + if (strncmp (name, fdin_string, fdin_string_len) != 0) + return 0; + name += fdin_string_len; + + if (*name == 0 || *name == ',') + return 0; + errno = 0; + l = strtol (name, &name, 10); + remote_desc_in = l; + if (errno != 0 || name == NULL || l < 0 || remote_desc_in != l) + return 0; + + if (strncmp (name, comma_fdout_string, comma_fdout_string_len) != 0) + return 0; + name += comma_fdout_string_len; + + if (*name == 0 || *name == ',') + return 0; + errno = 0; + l = strtol (name, &name, 10); + remote_desc_out = l; + if (errno != 0 || name == NULL || l < 0 || remote_desc_out != l) + return 0; + + if (*name != 0) + return 0; + + return 1; +} + /* Open a connection to a remote debugger. NAME is the filename used for communication. */ static void remote_open (char *name) { - if (!strchr (name, ':')) + /* "fdin=<#>,fdout=<#>" */ + if (parse_fds (name)) + { + fprintf (stderr, "Remote debugging using file descriptors" + " (input = %d, output = %d)\n", remote_desc_in, remote_desc_out); + } + else if (!strchr (name, ':')) { - fprintf (stderr, "%s: Must specify tcp connection as host:addr\n", name); + fprintf (stderr, "%s: Must specify tcp connection as host:addr" + " or use fdin=,fdout=\n", name); fflush (stderr); exit (1); } else { + int remote_desc; #ifdef USE_WIN32API static int winsock_initialized; #endif @@ -188,10 +242,13 @@ remote_open (char *name) #else closesocket (tmp_desc); /* No longer need this */ #endif + remote_desc_in = remote_desc_out = remote_desc; } #if defined(F_SETFL) && defined (FASYNC) - fcntl (remote_desc, F_SETFL, FASYNC); + fcntl (remote_desc_in, F_SETFL, FASYNC); + if (remote_desc_in != remote_desc_out) + fcntl (remote_desc_out, F_SETFL, FASYNC); #endif fprintf (stderr, "Replay logfile using %s\n", name); @@ -299,7 +356,7 @@ expect (FILE *fp) { break; } - read (remote_desc, &fromgdb, 1); + read (remote_desc_in, &fromgdb, 1); } while (fromlog == fromgdb); if (fromlog != EOL) @@ -326,7 +383,7 @@ play (FILE *fp) while ((fromlog = logchar (fp)) != EOL) { ch = fromlog; - write (remote_desc, &ch, 1); + write (remote_desc_out, &ch, 1); } } @@ -338,7 +395,13 @@ main (int argc, char *argv[]) if (argc < 3) { - fprintf (stderr, "Usage: gdbreplay \n"); + fprintf (stderr, "Usage: gdbreplay " + " { | fdin=,fdout=}\n" + "\n" + "Use host:port to listen for a TCP connection, or\n" + "fdin=,fdout= for networking over file descriptors:\n" + " socat EXEC:'gdbserver fdin=3,fdout=4 PROG',fdin=3,fdout=4" + " TCP6-LISTEN:5000\n"); fflush (stderr); exit (1); } diff -u -p -r1.32 remote-utils.c --- gdb/gdbserver/remote-utils.c 21 Sep 2006 16:09:54 -0000 1.32 +++ gdb/gdbserver/remote-utils.c 9 Oct 2006 14:02:42 -0000 @@ -52,6 +52,7 @@ #if HAVE_ARPA_INET_H #include #endif +#include #if USE_WIN32API #include @@ -79,12 +80,54 @@ int all_symbols_looked_up; int remote_debug = 0; struct ui_file *gdb_stdlog; -static int remote_desc; +static int remote_desc_in, remote_desc_out; /* FIXME headerize? */ extern int using_threads; extern int debug_threads; +/* Parse the string "fdin=<#>,fdout=<#>" into `remote_desc_in' and + `remote_desc_out' file descripts. Return non-zero for success. */ + +static int +parse_fds (char *name) +{ + const char *fdin_string = "fdin="; + size_t fdin_string_len = strlen (fdin_string); + const char *comma_fdout_string = ",fdout="; + size_t comma_fdout_string_len = strlen (comma_fdout_string); + long l; + + if (strncmp (name, fdin_string, fdin_string_len) != 0) + return 0; + name += fdin_string_len; + + if (*name == 0 || *name == ',') + return 0; + errno = 0; + l = strtol (name, &name, 10); + remote_desc_in = l; + if (errno != 0 || name == NULL || l < 0 || remote_desc_in != l) + return 0; + + if (strncmp (name, comma_fdout_string, comma_fdout_string_len) != 0) + return 0; + name += comma_fdout_string_len; + + if (*name == 0 || *name == ',') + return 0; + errno = 0; + l = strtol (name, &name, 10); + remote_desc_out = l; + if (errno != 0 || name == NULL || l < 0 || remote_desc_out != l) + return 0; + + if (*name != 0) + return 0; + + return 1; +} + /* Open a connection to a remote debugger. NAME is the filename used for communication. */ @@ -94,11 +137,20 @@ remote_open (char *name) #if defined(F_SETFL) && defined (FASYNC) int save_fcntl_flags; #endif - - if (!strchr (name, ':')) + + /* "fdin=<#>,fdout=<#>" */ + if (parse_fds (name)) { + fprintf (stderr, "Remote debugging using file descriptors" + " (input = %d, output = %d)\n", remote_desc_in, remote_desc_out); + } + else if (!strchr (name, ':')) + { + int remote_desc; + #ifdef USE_WIN32API - error ("Only : is supported on this platform."); + error ("Only : or fdin=,fdout=" + " supported on this platform."); #else remote_desc = open (name, O_RDWR); if (remote_desc < 0) @@ -149,10 +201,13 @@ remote_open (char *name) #endif fprintf (stderr, "Remote debugging using %s\n", name); + remote_desc_in = remote_desc_out = remote_desc; #endif /* USE_WIN32API */ } else { + int remote_desc; + #ifdef USE_WIN32API static int winsock_initialized; #endif @@ -224,13 +279,21 @@ remote_open (char *name) /* Convert IP address to string. */ fprintf (stderr, "Remote debugging from host %s\n", inet_ntoa (sockaddr.sin_addr)); + remote_desc_in = remote_desc_out = remote_desc; } #if defined(F_SETFL) && defined (FASYNC) - save_fcntl_flags = fcntl (remote_desc, F_GETFL, 0); - fcntl (remote_desc, F_SETFL, save_fcntl_flags | FASYNC); + save_fcntl_flags = fcntl (remote_desc_in, F_GETFL, 0); + fcntl (remote_desc_in, F_SETFL, save_fcntl_flags | FASYNC); + if (remote_desc_in != remote_desc_out) + { + save_fcntl_flags = fcntl (remote_desc_out, F_GETFL, 0); + fcntl (remote_desc_out, F_SETFL, save_fcntl_flags | FASYNC); + } #if defined (F_SETOWN) - fcntl (remote_desc, F_SETOWN, getpid ()); + fcntl (remote_desc_in, F_SETOWN, getpid ()); + if (remote_desc_in != remote_desc_out) + fcntl (remote_desc_out, F_SETOWN, getpid ()); #endif #endif disable_async_io (); @@ -240,9 +303,13 @@ void remote_close (void) { #ifdef USE_WIN32API - closesocket (remote_desc); + closesocket (remote_desc_in); + if (remote_desc_in != remote_desc_out) + closesocket (remote_desc_out); #else - close (remote_desc); + close (remote_desc_in); + if (remote_desc_in != remote_desc_out) + close (remote_desc_out); #endif } @@ -486,7 +553,7 @@ putpkt_binary (char *buf, int cnt) { int cc; - if (send (remote_desc, buf2, p - buf2, 0) != p - buf2) + if (send (remote_desc_out, buf2, p - buf2, 0) != p - buf2) { perror ("putpkt(write)"); return -1; @@ -497,7 +564,7 @@ putpkt_binary (char *buf, int cnt) fprintf (stderr, "putpkt (\"%s\"); [looking for ack]\n", buf2); fflush (stderr); } - cc = recv (remote_desc, buf3, 1, 0); + cc = recv (remote_desc_in, buf3, 1, 0); if (remote_debug) { fprintf (stderr, "[received '%c' (0x%x)]\n", buf3[0], buf3[0]); @@ -552,13 +619,13 @@ input_interrupt (int unused) be a problem under NetBSD 1.4 and 1.5. */ FD_ZERO (&readset); - FD_SET (remote_desc, &readset); - if (select (remote_desc + 1, &readset, 0, 0, &immediate) > 0) + FD_SET (remote_desc_in, &readset); + if (select (remote_desc_in + 1, &readset, 0, 0, &immediate) > 0) { int cc; char c = 0; - cc = recv (remote_desc, &c, 1, 0); + cc = recv (remote_desc_in, &c, 1, 0); if (cc != 1 || c != '\003') { @@ -639,7 +706,7 @@ readchar (void) if (bufcnt-- > 0) return *bufp++; - bufcnt = recv (remote_desc, buf, sizeof (buf), 0); + bufcnt = recv (remote_desc_in, buf, sizeof (buf), 0); if (bufcnt <= 0) { @@ -706,7 +773,7 @@ getpkt (char *buf) fprintf (stderr, "Bad checksum, sentsum=0x%x, csum=0x%x, buf=%s\n", (c1 << 4) + c2, csum, buf); - send (remote_desc, "-", 1, 0); + send (remote_desc_out, "-", 1, 0); } if (remote_debug) @@ -715,7 +782,7 @@ getpkt (char *buf) fflush (stderr); } - send (remote_desc, "+", 1, 0); + send (remote_desc_out, "+", 1, 0); if (remote_debug) { diff -u -p -r1.39 server.c --- gdb/gdbserver/server.c 8 Aug 2006 16:03:29 -0000 1.39 +++ gdb/gdbserver/server.c 9 Oct 2006 14:02:45 -0000 @@ -435,8 +435,11 @@ gdbserver_usage (void) printf ("Usage:\tgdbserver COMM PROG [ARGS ...]\n" "\tgdbserver COMM --attach PID\n" "\n" - "COMM may either be a tty device (for serial debugging), or \n" - "HOST:PORT to listen for a TCP connection.\n"); + "COMM may either be a tty device (for serial debugging), or\n" + "HOST:PORT to listen for a TCP connection, or\n" + "fdin=,fdout= for networking over file descriptors:\n" + " socat EXEC:'gdbserver fdin=3,fdout=4 PROG',fdin=3,fdout=4" + " TCP6-LISTEN:5000\n"); } int --yrj/dFKFPuw6o+aM--