GDBSERVER: Listen on a unix domain (instead of TCP) socket if requested.
When invoking gdbserver, if the COMM parameter takes the form "unix::/path/name" then a local (unix) domain socket will be created with that name and gdbserver will listen for connections on that. gdb/ * NEWS: Mention new feature. gdb/gdbserver/ * configure.ac (AC_CHECK_HEADERS): Add sys/un.h. * configure: Regenerate. * remote-utils.c (remote_prepare): Create a local socket if requested. (remote_open): Don't attempt to open a file if it's a socket. (handle_accept_event): Display the name of the socket on connection. gdb/common/ * netstuff.c (parse_connection_spec)[prefixes]: New member for local domain sockets.
This commit is contained in:
parent
2849d19feb
commit
f19c7ff839
4
gdb/NEWS
4
gdb/NEWS
@ -15,6 +15,10 @@
|
||||
can be passed using the '[ADDRESS]:PORT' notation, or the regular
|
||||
'ADDRESS:PORT' method.
|
||||
|
||||
* GDB and GDBserver now support local domain socket connections. The
|
||||
name of a local domain socket may be provided instead of the
|
||||
[ADDRESS]:PORT notation.
|
||||
|
||||
* DWARF index cache: GDB can now automatically save indices of DWARF
|
||||
symbols on disk to speed up further loading of the same binaries.
|
||||
|
||||
|
@ -56,6 +56,7 @@ parse_connection_spec_without_prefix (std::string spec, struct addrinfo *hint)
|
||||
&& (spec[0] == '['
|
||||
|| std::count (spec.begin (),
|
||||
spec.end (), ':') > 1)));
|
||||
bool is_unix = hint->ai_family == AF_UNIX;
|
||||
|
||||
if (is_ipv6)
|
||||
{
|
||||
@ -109,6 +110,12 @@ parse_connection_spec_without_prefix (std::string spec, struct addrinfo *hint)
|
||||
if (ret.host_str.empty ())
|
||||
ret.host_str = "localhost";
|
||||
|
||||
if (is_unix && ret.host_str != "localhost")
|
||||
error (_("The host name must be empty or 'localhost' for a unix domain socket."));
|
||||
|
||||
if (is_unix && ret.port_str.empty ())
|
||||
error (_("A path name must be specified for a unix domain socket."));
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
@ -138,6 +145,7 @@ parse_connection_spec (const char *spec, struct addrinfo *hint)
|
||||
{ "tcp4:", AF_INET, SOCK_STREAM },
|
||||
{ "udp6:", AF_INET6, SOCK_DGRAM },
|
||||
{ "tcp6:", AF_INET6, SOCK_STREAM },
|
||||
{ "unix:", AF_LOCAL, SOCK_STREAM },
|
||||
};
|
||||
|
||||
for (const host_prefix prefix : prefixes)
|
||||
|
@ -96,7 +96,7 @@ ACX_CONFIGURE_DIR(["../../libiberty"], ["build-libiberty-gdbserver"])
|
||||
AC_CHECK_HEADERS(termios.h sys/reg.h string.h dnl
|
||||
proc_service.h sys/procfs.h linux/elf.h dnl
|
||||
fcntl.h signal.h sys/file.h dnl
|
||||
sys/ioctl.h netinet/in.h sys/socket.h netdb.h dnl
|
||||
sys/ioctl.h netinet/in.h sys/socket.h sys/un.h netdb.h dnl
|
||||
netinet/tcp.h arpa/inet.h)
|
||||
AC_FUNC_FORK
|
||||
AC_CHECK_FUNCS(getauxval pread pwrite pread64 setns)
|
||||
|
@ -38,6 +38,9 @@
|
||||
#if HAVE_NETINET_IN_H
|
||||
#include <netinet/in.h>
|
||||
#endif
|
||||
#if HAVE_SYS_UN_H
|
||||
#include <sys/un.h>
|
||||
#endif
|
||||
#if HAVE_SYS_SOCKET_H
|
||||
#include <sys/socket.h>
|
||||
#endif
|
||||
@ -193,20 +196,36 @@ handle_accept_event (int err, gdb_client_data client_data)
|
||||
descriptor open for add_file_handler to wait for a new connection. */
|
||||
delete_file_handler (listen_desc);
|
||||
|
||||
/* Convert IP address to string. */
|
||||
char orig_host[GDB_NI_MAX_ADDR], orig_port[GDB_NI_MAX_PORT];
|
||||
#if HAVE_SYS_UN_H
|
||||
if (sockaddr.ss_family == AF_UNIX)
|
||||
{
|
||||
struct sockaddr_un su;
|
||||
socklen_t socklen = sizeof (su);
|
||||
|
||||
int r = getnameinfo ((struct sockaddr *) &sockaddr, len,
|
||||
orig_host, sizeof (orig_host),
|
||||
orig_port, sizeof (orig_port),
|
||||
NI_NUMERICHOST | NI_NUMERICSERV);
|
||||
if (getsockname (listen_desc, (struct sockaddr *) &su, &socklen) != 0)
|
||||
perror (_("Could not obtain remote address"));
|
||||
|
||||
if (r != 0)
|
||||
fprintf (stderr, _("Could not obtain remote address: %s\n"),
|
||||
gai_strerror (r));
|
||||
fprintf (stderr, _("Remote debugging on local socket bound to %s\n"),
|
||||
su.sun_path);
|
||||
}
|
||||
else
|
||||
fprintf (stderr, _("Remote debugging from host %s, port %s\n"),
|
||||
orig_host, orig_port);
|
||||
#endif
|
||||
{
|
||||
/* Convert IP address to string. */
|
||||
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);
|
||||
|
||||
@ -250,6 +269,9 @@ remote_prepare (const char *name)
|
||||
struct addrinfo hint;
|
||||
struct addrinfo *ainfo;
|
||||
|
||||
struct sockaddr *addr;
|
||||
socklen_t addrlen;
|
||||
|
||||
memset (&hint, 0, sizeof (hint));
|
||||
/* Assume no prefix will be passed, therefore we should use
|
||||
AF_UNSPEC. */
|
||||
@ -258,7 +280,7 @@ remote_prepare (const char *name)
|
||||
hint.ai_protocol = IPPROTO_TCP;
|
||||
|
||||
parsed_connection_spec parsed
|
||||
= parse_connection_spec_without_prefix (name, &hint);
|
||||
= parse_connection_spec (name, &hint);
|
||||
|
||||
if (parsed.port_str.empty ())
|
||||
{
|
||||
@ -276,47 +298,92 @@ remote_prepare (const char *name)
|
||||
}
|
||||
#endif
|
||||
|
||||
int r = getaddrinfo (parsed.host_str.c_str (), parsed.port_str.c_str (),
|
||||
&hint, &ainfo);
|
||||
#if HAVE_SYS_UN_H
|
||||
struct sockaddr_un unix_addr;
|
||||
|
||||
if (r != 0)
|
||||
error (_("%s: cannot resolve name: %s"), name, gai_strerror (r));
|
||||
#ifndef UNIX_PATH_MAX
|
||||
#define UNIX_PATH_MAX sizeof (((struct sockaddr_un *) NULL)->sun_path)
|
||||
#endif
|
||||
|
||||
scoped_free_addrinfo freeaddrinfo (ainfo);
|
||||
|
||||
struct addrinfo *iter;
|
||||
|
||||
for (iter = ainfo; iter != NULL; iter = iter->ai_next)
|
||||
if (hint.ai_family == AF_LOCAL)
|
||||
{
|
||||
listen_desc = gdb_socket_cloexec (iter->ai_family, iter->ai_socktype,
|
||||
iter->ai_protocol);
|
||||
const char *sock_name = parsed.port_str.c_str ();
|
||||
if (parsed.port_str.length () > UNIX_PATH_MAX - 1)
|
||||
{
|
||||
error
|
||||
(_("%s is too long. Socket names may be no longer than %s bytes."),
|
||||
sock_name, pulongest (UNIX_PATH_MAX - 1));
|
||||
return;
|
||||
}
|
||||
listen_desc = socket (AF_UNIX, SOCK_STREAM, 0);
|
||||
if (listen_desc < 0)
|
||||
perror_with_name ("Can't open socket");
|
||||
|
||||
if (listen_desc >= 0)
|
||||
break;
|
||||
memset (&unix_addr, 0, sizeof (unix_addr));
|
||||
unix_addr.sun_family = AF_UNIX;
|
||||
strncpy (unix_addr.sun_path, sock_name, UNIX_PATH_MAX - 1);
|
||||
|
||||
struct stat statbuf;
|
||||
int stat_result = stat (sock_name, &statbuf);
|
||||
|
||||
if (stat_result == 0
|
||||
&& S_ISSOCK (statbuf.st_mode))
|
||||
unlink (sock_name);
|
||||
|
||||
addr = (struct sockaddr *) &unix_addr;
|
||||
addrlen = sizeof (unix_addr);
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
struct addrinfo *iter;
|
||||
|
||||
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);
|
||||
|
||||
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. */
|
||||
tmp = 1;
|
||||
setsockopt (listen_desc, SOL_SOCKET, SO_REUSEADDR, (char *) &tmp,
|
||||
sizeof (tmp));
|
||||
|
||||
if (iter->ai_socktype == SOCK_DGRAM)
|
||||
error (_("Only stream orientated protocols are currently supported."));
|
||||
|
||||
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);
|
||||
}
|
||||
addr = iter->ai_addr;
|
||||
addrlen = iter->ai_addrlen;
|
||||
}
|
||||
|
||||
if (iter == NULL)
|
||||
perror_with_name ("Can't open socket");
|
||||
|
||||
/* Allow rapid reuse of this port. */
|
||||
tmp = 1;
|
||||
setsockopt (listen_desc, SOL_SOCKET, SO_REUSEADDR, (char *) &tmp,
|
||||
sizeof (tmp));
|
||||
|
||||
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, iter->ai_addr, iter->ai_addrlen) != 0)
|
||||
if (bind (listen_desc, addr, addrlen) != 0)
|
||||
perror_with_name ("Can't bind address");
|
||||
|
||||
if (listen (listen_desc, 1) != 0)
|
||||
@ -354,11 +421,11 @@ remote_open (const char *name)
|
||||
}
|
||||
#ifndef USE_WIN32API
|
||||
else if (port_str == NULL)
|
||||
{
|
||||
{
|
||||
struct stat statbuf;
|
||||
|
||||
if (stat (name, &statbuf) == 0
|
||||
&& (S_ISCHR (statbuf.st_mode) || S_ISFIFO (statbuf.st_mode)))
|
||||
&& (S_ISCHR (statbuf.st_mode) || S_ISFIFO (statbuf.st_mode)))
|
||||
remote_desc = open (name, O_RDWR);
|
||||
else
|
||||
{
|
||||
@ -1153,7 +1220,7 @@ prepare_resume_reply (char *buf, ptid_t ptid,
|
||||
struct regcache *regcache;
|
||||
|
||||
if ((status->kind == TARGET_WAITKIND_FORKED && cs.report_fork_events)
|
||||
|| (status->kind == TARGET_WAITKIND_VFORKED
|
||||
|| (status->kind == TARGET_WAITKIND_VFORKED
|
||||
&& cs.report_vfork_events))
|
||||
{
|
||||
enum gdb_signal signal = GDB_SIGNAL_TRAP;
|
||||
@ -1165,7 +1232,7 @@ prepare_resume_reply (char *buf, ptid_t ptid,
|
||||
buf = write_ptid (buf, status->value.related_pid);
|
||||
strcat (buf, ";");
|
||||
}
|
||||
else if (status->kind == TARGET_WAITKIND_VFORK_DONE
|
||||
else if (status->kind == TARGET_WAITKIND_VFORK_DONE
|
||||
&& cs.report_vfork_events)
|
||||
{
|
||||
enum gdb_signal signal = GDB_SIGNAL_TRAP;
|
||||
|
Loading…
x
Reference in New Issue
Block a user