[PATCH] Print protocol name of socket descriptors with -yy option

Dmitry V. Levin ldv at altlinux.org
Wed Nov 19 16:10:54 UTC 2014


On Wed, Nov 19, 2014 at 11:32:32PM +0900, Masatake YAMATO wrote:
> When -yy option is specified other than inet socket
> were printed as <socket:[INODE]>.
> 
> e.g.
> 
>      # ./strace -e recvmsg -yy ping 127.0.0.1 > /dev/null
>      ...
>      recvmsg(3<socket:[43222052]>, ...
>      ...
> 
> This patch makes the output more informative; instead of
> printing "socket" strace prints the name of protocol behind
> the socket descriptor.
> 
> e.g.
> 
>      recvmsg(3<RAW:[43222052]>, ...
> 
>      recvmsg(1<TCP:[...
>      recvmsg(2<UDP:[...
>      recvmsg(3<UNIX:[...
>      recvmsg(4<NETLINK:[...
> 
> Signed-off-by: Masatake YAMATO <yamato at redhat.com>
> ---
>  tests/net-yy-accept.awk  |  6 +++---
>  tests/net-yy-connect.awk |  4 ++--
>  util.c                   | 29 ++++++++++++++++++++++++++++-
>  3 files changed, 33 insertions(+), 6 deletions(-)
> 
> diff --git a/tests/net-yy-accept.awk b/tests/net-yy-accept.awk
> index 3ea4afe..ac3c19a 100644
> --- a/tests/net-yy-accept.awk
> +++ b/tests/net-yy-accept.awk
> @@ -9,7 +9,7 @@ BEGIN {
>    r_i = "[1-9][0-9]*"
>    r_port = "[1-9][0-9][0-9][0-9]+"
>    r_localhost = "127\\.0\\.0\\.1"
> -  r_bind = "^bind\\(0<socket:\\[(" r_i ")\\]>, {sa_family=AF_INET, sin_port=htons\\(0\\), sin_addr=inet_addr\\(\"" r_localhost "\"\\)}, " r_i "\\) += 0$"
> +  r_bind = "^bind\\(0<(TCP|socket):\\[(" r_i ")\\]>, {sa_family=AF_INET, sin_port=htons\\(0\\), sin_addr=inet_addr\\(\"" r_localhost "\"\\)}, " r_i "\\) += 0$"
>    r_listen = "^/$"
>    r_getsockname = "^getsockname\\(0<" r_localhost ":(" r_port ")>, {sa_family=AF_INET, sin_port=htons\\((" r_port ")\\), sin_addr=inet_addr\\(\"" r_localhost "\"\\)}, \\[" r_i "\\]\\) += 0$"
>    r_accept = "^/$"
> @@ -23,8 +23,8 @@ NR == 1 && /^socket\(PF_INET, SOCK_STREAM, IPPROTO_IP\) += 0$/ {next}
>  
>  NR == 2 {
>    if (match($0, r_bind, a)) {
> -    inode = a[1]
> -    r_listen = "^listen\\(0<socket:\\[" inode "\\]>, 5\\) += 0$"
> +    inode = a[2]
> +    r_listen = "^listen\\(0<(TCP|socket):\\[" inode "\\]>, 5\\) += 0$"
>      next
>    }
>  }
> diff --git a/tests/net-yy-connect.awk b/tests/net-yy-connect.awk
> index 18c1a28..c7c63af 100644
> --- a/tests/net-yy-connect.awk
> +++ b/tests/net-yy-connect.awk
> @@ -8,7 +8,7 @@ BEGIN {
>    r_i = "[1-9][0-9]*"
>    r_port = "[1-9][0-9][0-9][0-9]+"
>    r_localhost = "127\\.0\\.0\\.1"
> -  r_connect = "^connect\\(0<socket:\\[" r_i "\\]>, {sa_family=AF_INET, sin_port=htons\\((" r_port ")\\), sin_addr=inet_addr\\(\"" r_localhost "\"\\)}, " r_i ") += 0$"
> +  r_connect = "^connect\\(0<(TCP|socket):\\[" r_i "\\]>, {sa_family=AF_INET, sin_port=htons\\((" r_port ")\\), sin_addr=inet_addr\\(\"" r_localhost "\"\\)}, " r_i ") += 0$"
>    r_send = "^/$"
>    r_sendto = "^/$"
>    r_close = "^/$"
> @@ -18,7 +18,7 @@ NR == 1 && /^socket\(PF_INET, SOCK_STREAM, IPPROTO_IP\) += 0$/ {next}
>  
>  NR == 2 {
>    if (match($0, r_connect, a)) {
> -    port_r = a[1]
> +    port_r = a[2]
>      r_send = "^send\\(0<" r_localhost ":(" r_port ")->" r_localhost ":" port_r ">, \"data\", 4, MSG_DONTROUTE\\) += 4$"
>      r_sendto = "^sendto\\(0<" r_localhost ":(" r_port ")->" r_localhost ":" port_r ">, \"data\", 4, MSG_DONTROUTE, NULL, 0\\) += 4$"
>      next
> diff --git a/util.c b/util.c
> index b13f3dc..c59fff0 100644
> --- a/util.c
> +++ b/util.c
> @@ -35,6 +35,7 @@
>  #include <sys/user.h>
>  #include <sys/param.h>
>  #include <fcntl.h>
> +#include <sys/xattr.h>

<sys/xattr.h> was introduced in glibc v2.3 about 12 years ago,
not sure about other libc implementations.
Can we rely on <sys/xattr.h> and include it unconditionally?

>  #if HAVE_SYS_UIO_H
>  # include <sys/uio.h>
>  #endif

This reminds me that all HAVE_SYS_UIO_H checks are redundant.

> @@ -420,6 +421,23 @@ printnum_int(struct tcb *tcp, long addr, const char *fmt)
>  	tprints("]");
>  }
>  
> +
> +static char *
> +getfdproto(struct tcb *tcp, int fd, char *buf, unsigned bufsize)
> +{
> +	char path[sizeof("/proc/%u/fd/%u") + 2 * sizeof(int)*3];
> +
> +	if (fd < 0)
> +		return NULL;
> +
> +	sprintf(path, "/proc/%u/fd/%u", tcp->pid, fd);
> +	if (getxattr(path, "system.sockprotoname", buf, bufsize) <= 0)
> +		return NULL;
> +	buf[bufsize - 1] = '\0';

Masatake, since the code on the kernel side is yours, you should know
better than anybody else whether the value returned by this syscall is
null-terminated or not.  If it is surely null-terminated, then we don't
have to.  If not, then we have to reserve one byte for null, pass
(bufsize-1) to the syscall, save its return value, and terminate the
string at the right place.

> +
> +	return buf;
> +}
> +
>  void
>  printfd(struct tcb *tcp, int fd)
>  {
> @@ -433,10 +451,19 @@ printfd(struct tcb *tcp, int fd)
>  		    strncmp(path, socket_prefix, socket_prefix_len) == 0 &&
>  		    path[(path_len = strlen(path)) - 1] == ']') {
>  			unsigned long inodenr;
> +#define PROTO_NAME_LEN (32 + 1)
> +			char proto_buf[PROTO_NAME_LEN];
> +			char *proto;
>  			inodenr = strtoul(path + socket_prefix_len, NULL, 10);
> +			proto = getfdproto(tcp, fd, proto_buf, PROTO_NAME_LEN);
>  			tprintf("%d<", fd);
>  			if (!print_sockaddr_by_inode(inodenr))
> -				tprints(path);
> +			{
> +				if (proto)
> +					tprintf("%s:[%lu]", proto, inodenr);
> +				else
> +					tprints(path);
> +			}
>  			tprints(">");

The result of getfdproto call is going to be used only in
!print_sockaddr_by_inode case, so it would be logical to call
getfdproto only in that case.


-- 
ldv
-------------- next part --------------
A non-text attachment was scrubbed...
Name: not available
Type: application/pgp-signature
Size: 181 bytes
Desc: not available
URL: <http://lists.strace.io/pipermail/strace-devel/attachments/20141119/6c4e9cb4/attachment.bin>


More information about the Strace-devel mailing list