This is the mail archive of the systemtap@sourceware.org mailing list for the systemtap project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Re: [PATCH] - DRAFT - Easy access to IP address in struct sockaddr in syscall.bind probe (for now)]


Hi all.

New version of patch is released.

Please, take a look and don't hesitate
to comment.

This patch (partially?) adds support for pretty print of abstract sockets.
On this place please look at conv_buf static solution which is not
good, but I'm not able to use (on x86_64) bigger function frame than
512 bytes (-Wframe-larger-than= gcc restriction).

Also I wrote small example (now without documentation).

BTW: What would be nice is to have systemtap function which is not string oriented.
Function _stp_text_str stops on first NUL char and then does'nt
print all bytes in memory region.

Have nice day.

PS 2 Frank: No delimters are supported yet. Maybe delimiters aren't
necessary on this place.

On Sun, Nov 17, 2013 at 11:18:34AM +0100, Robin Hack wrote:
> On Wed, Nov 13, 2013 at 05:18:35PM -0500, Frank Ch. Eigler wrote:
> 
> Hi Frank.
> 
> Thanks again for comments. I did some changes, but comments and changes
> are still needed.
> > 
> > Hi, Robin -
> > 
> > rhack wrote:
> > 
> > > [...]  Then I decided to write this patch. Patch is only draft now
> > > and comments are very welcome.
> > 
> > Nice.  A few code comments:
> > 
> > The use of TMP_STAP_RETVALUE / MAXLEN in the embedded-c function is a
> > little clumsy.  Have you considered using ordinarily named variables
> > to track the remainder base/length of STAP_RETVALUE,
> It's fixed.
> > and doing the
> > RETVALUE_INC_SKIP dance inlined instead of as a macro?
> I apologize here, but this part is not clear enought for me.
> 
> > What about delimiters between the data corresponding to multiple SA_* selections?
> I changed approach. Now I export values direct to probes.
> Delimiters will be good in tapset library.
> > 
> > 
> > > Very easy example are attached too.
> > 
> > It might be even simpler if the related tapset functions all get this
> > kind of stuff, but perhaps plopped into a macro for easier handling:
> > 
> > probe syscall.bind = ... {
> > %( systemtap_v >= "2.5" %? 
> >     if (_struct_sockaddr_u_sa_family(my_addr_uaddr, addrlen) =~ "AF_INET.*") {
> >        uaddr_ip = _struct_sockaddr_u_ip_addr(my_addr_uaddr, addrlen)
> >        uaddr_ip_port = ... 
> >     }
> > %)
> > 
> > where the whole %(  %)  block could be @defined in a macro, kind of like
> > _nfs_data_timestamp in tapset/linux/nfs_proc.stpm.
> > 
> > 
> > > What is not solved in this patch:
> > >     * Error handling if wrong struct is passed - now it's just return empty ("") string. Maybe throw exception will be better.
> I hope, that this will be part of tapset.
> > >     * Expansion to syscall.connect probe.
> Done :).
> > >     * Write tapset shell for new internal functions.
> In progress.
> > 
> > Yup, plus a test case (e.g., a testsuite/buildok file).
> I added some tests.
> > 
> > Thanks!
> > 
> > - FChE

> diff --git a/tapset/linux/aux_syscalls.stp b/tapset/linux/aux_syscalls.stp
> index 0f9c9e4..1513150 100644
> --- a/tapset/linux/aux_syscalls.stp
> +++ b/tapset/linux/aux_syscalls.stp
> @@ -280,7 +280,7 @@ function _struct_compat_itimerval_u:string(uaddr:long)
>  %}
>  
>  %{
> -// Needed for function _struct_sockaddr_u. Unfortunately cannot be
> +// Needed for function _struct_sockaddr_u_impl. Unfortunately cannot be
>  // inlined into the function since these header files define static
>  // functions themselves.
>  #include <linux/socket.h>
> @@ -288,18 +288,75 @@ function _struct_compat_itimerval_u:string(uaddr:long)
>  #include <linux/netlink.h>
>  %}
>  
> +%{
> +// Enum for _struct_sockaddr_u_* functions.
> +typedef enum {
> +    SA_PRETTY           = 1,
> +    SA_IP_ADDR          = 2,
> +    SA_TCP_PORT         = 4,
> +    SA_FAMILY           = 8,
> +    SA_IPV6_FLOWINFO    = 16,
> +    SA_IPV6_SCOPE_ID    = 32,
> +} sa_dispatch;
> +%}
> +
> +function _struct_sockaddr_u_ip_addr:string(uaddr:long, len:long)
> +{
> +    return _struct_sockaddr_u_impl(uaddr, len, %{ SA_IP_ADDR %});
> +}
> +
> +function _struct_sockaddr_u_tcp_port:string(uaddr:long, len:long)
> +{
> +    return _struct_sockaddr_u_impl(uaddr, len, %{ SA_TCP_PORT %});
> +}
> +
> +function _struct_sockaddr_u_ip_addr_tcp_port:string(uaddr:long, len:long)
> +{
> +    return _struct_sockaddr_u_impl(uaddr, len, %{ SA_IP_ADDR | SA_TCP_PORT %});
> +}
> +
> +function _struct_sockaddr_u_sa_family:string(uaddr:long, len:long)
> +{
> +    return _struct_sockaddr_u_impl(uaddr, len, %{ SA_FAMILY %});
> +}
> +
> +function _struct_sockaddr_u_ipv6_flowinfo:string(uaddr:long, len:long)
> +{
> +    return _struct_sockaddr_u_impl(uaddr, len, %{ SA_IPV6_FLOWINFO %});
> +}
> +
> +function _struct_sockaddr_u_ipv6_scope_id:string(uaddr:long, len:long)
> +{
> +    return _struct_sockaddr_u_impl(uaddr, len, %{ SA_IPV6_SCOPE_ID %});
> +}
> +
>  function _struct_sockaddr_u:string(uaddr:long, len:long)
> +{
> +    return _struct_sockaddr_u_impl(uaddr, len, %{ SA_PRETTY %});
> +}
> +
> +function _struct_sockaddr_u_impl:string(uaddr:long, len:long, what:long)
>  %{ /* pure */
>  #include <linux/version.h>
>  #include <linux/in6.h>
>  #include <linux/un.h>
>  #include <linux/if_packet.h>
>  
> +	sa_dispatch what = (sa_dispatch)STAP_ARG_what;
> +
>  	char *ptr = (char *)(unsigned long)STAP_ARG_uaddr;
>  	char buf[128];
>  	size_t len = STAP_ARG_len < 128 ? STAP_ARG_len : 128;
>  	struct sockaddr *sa = (struct sockaddr *)buf;
>  
> +// Don't use this macro outside of if (what & ... ) statement!
> +// (n - 1) mean: cut of null char
> +#define RETVALUE_INC_SKIP() do {stap_retvalue += (n); maxstringlen -= (n - 1);} while (0)
> +    char *stap_retvalue = (char *)(unsigned long)STAP_RETVALUE;
> +    int maxstringlen = MAXSTRINGLEN;
> +    size_t n;
> +
> +
>  	if (ptr == NULL)
>  	{
>  		strlcpy (STAP_RETVALUE, "NULL", MAXSTRINGLEN);
> @@ -320,60 +377,163 @@ function _struct_sockaddr_u:string(uaddr:long, len:long)
>  #define DADDR   (&inet->daddr)
>  #endif
>  
> +
>  // Use kernel builtin instead of picking up user space ntohs (function).
>  #define _stp_ntohs be16_to_cpu
>  
>  	if ((sa->sa_family == AF_INET) && (len == sizeof(struct sockaddr_in)))
>  	{
>  		struct sockaddr_in *sin = (struct sockaddr_in *)buf;
> -#ifndef NIPQUAD_FMT			// kver >= 2.6.36
> -		snprintf(STAP_RETVALUE, MAXSTRINGLEN, "{AF_INET, %pI4, %d}",
> -			 &sin->sin_addr, _stp_ntohs(sin->sin_port));
> +
> +        if (what & SA_PRETTY)
> +        {
> +#ifndef NIPQUAD_FMT                     // kver >= 2.6.36
> +            snprintf(STAP_RETVALUE, MAXSTRINGLEN, "{AF_INET, %pI4, %d}",
> +                     &sin->sin_addr, _stp_ntohs(sin->sin_port));
>  #else
> -		snprintf(STAP_RETVALUE, MAXSTRINGLEN,
> -			 "{AF_INET, " NIPQUAD_FMT ", %d}",
> -			 NIPQUAD(sin->sin_addr), _stp_ntohs(sin->sin_port));
> -#endif
> +            snprintf(STAP_RETVALUE, MAXSTRINGLEN,
> +                     "{AF_INET, " NIPQUAD_FMT ", %d}",
> +                     NIPQUAD(sin->sin_addr), _stp_ntohs(sin->sin_port));
> +#endif
> +            return;
> +        }
> +
> +        if (what & SA_FAMILY)
> +        {
> +            n = strlcpy(stap_retvalue, "AF_INET", maxstringlen);
> +            RETVALUE_INC_SKIP();
> +        }
> +
> +        if (what & SA_IP_ADDR)
> +        {
> +#ifndef NIPQUAD_FMT                     // kver >= 2.6.36
> +            n = snprintf(stap_retvalue, maxstringlen, "%pI4", &sin->sin_addr);
> +#else
> +            n = snprintf(stap_retvalue, maxstringlen, NIPQUAD_FMT,
> +                    NIPQUAD(sin->sin_addr));
> +#endif
> +            RETVALUE_INC_SKIP();
> +        }
> +
> +        if (what & SA_TCP_PORT)
> +        {
> +            n = snprintf(stap_retvalue, maxstringlen, "%d",
> +                    _stp_ntohs(sin->sin_port));
> +            RETVALUE_INC_SKIP();
> +        }
>  	}
>  	else if ((sa->sa_family == AF_UNIX)
>  		 && (len == sizeof(struct sockaddr_un)))
> -	{	
> -		struct sockaddr_un *sun = (struct sockaddr_un *)buf;	
> -		snprintf(STAP_RETVALUE, MAXSTRINGLEN, "{AF_UNIX, %s}",
> -			 sun->sun_path); 
> +	{
> +		struct sockaddr_un *sun = (struct sockaddr_un *)buf;
> +
> +        if (what & SA_PRETTY)
> +        {
> +            snprintf(STAP_RETVALUE, MAXSTRINGLEN, "{AF_UNIX, %s}",
> +                 sun->sun_path);
> +        } else if (what & SA_FAMILY)
> +        {
> +            strlcpy(STAP_RETVALUE, "AF_UNIX", MAXSTRINGLEN);
> +        } else
> +        {
> +            strlcpy(STAP_RETVALUE, "", MAXSTRINGLEN);
> +        }
>  	}
>  	else if ((sa->sa_family == AF_NETLINK)
>  		 && (len == sizeof(struct sockaddr_nl)))
>  	{
>  		struct sockaddr_nl *nl = (struct sockaddr_nl *)buf;
> -		snprintf(STAP_RETVALUE, MAXSTRINGLEN,
> -			 "{AF_NETLINK, pid=%d, groups=%08x}",
> -			 nl->nl_pid, nl->nl_groups);
> +
> +        if (what & SA_PRETTY) {
> +            snprintf(STAP_RETVALUE, MAXSTRINGLEN,
> +                 "{AF_NETLINK, pid=%d, groups=%08x}",
> +                 nl->nl_pid, nl->nl_groups);
> +        } else if (what & SA_FAMILY)
> +        {
> +            strlcpy(STAP_RETVALUE, "AF_NETLINK", MAXSTRINGLEN);
> +        } else
> +        {
> +            strlcpy(STAP_RETVALUE, "", MAXSTRINGLEN);
> +        }
>  	}
>  	else if ((sa->sa_family == AF_INET6)
>  		 && (len == sizeof(struct sockaddr_in6)))
>  	{
>  		struct sockaddr_in6 *sin = (struct sockaddr_in6 *)buf;
> +
> +        if (what & SA_PRETTY)
> +        {
>  #ifndef NIP6_FMT			// kver >= 2.6.36
> -		snprintf(STAP_RETVALUE, MAXSTRINGLEN,
> -			 "{AF_INET6, %pI6, %d}", &sin->sin6_addr,
> -			 _stp_ntohs(sin->sin6_port));
> +            snprintf(STAP_RETVALUE, MAXSTRINGLEN,
> +                 "{AF_INET6, %pI6, %d}", &sin->sin6_addr,
> +                 _stp_ntohs(sin->sin6_port));
>  #else
> -		snprintf(STAP_RETVALUE, MAXSTRINGLEN,
> -			 "{AF_INET6, " NIP6_FMT ", %d}", NIP6(sin->sin6_addr),
> -			 _stp_ntohs(sin->sin6_port));
> +            snprintf(STAP_RETVALUE, MAXSTRINGLEN,
> +                 "{AF_INET6, " NIP6_FMT ", %d}", NIP6(sin->sin6_addr),
> +                 _stp_ntohs(sin->sin6_port));
>  #endif
> +            return;
> +        }
> +
> +        if (what & SA_FAMILY)
> +        {
> +            n = strlcpy(stap_retvalue, "AF_INET6", maxstringlen);
> +            RETVALUE_INC_SKIP();
> +        }
> +
> +        if (what & SA_IP_ADDR)
> +        {
> +#ifndef NIP6_FMT			// kver >= 2.6.36
> +            n = snprintf(stap_retvalue, maxstringlen,
> +                 "%pI6", &sin->sin6_addr);
> +#else
> +            n = snprintf(stap_retvalue, maxstringlen,
> +                 NIP6_FMT, NIP6(sin->sin6_addr));
> +#endif
> +            RETVALUE_INC_SKIP();
> +        }
> +
> +        if (what & SA_TCP_PORT)
> +        {
> +            n = snprintf(stap_retvalue, maxstringlen,
> +                 "%d", _stp_ntohs(sin->sin6_port));
> +            RETVALUE_INC_SKIP();
> +        }
> +
> +        if (what & SA_IPV6_FLOWINFO)
> +        {
> +            n = snprintf(stap_retvalue, maxstringlen,
> +                 "%d", sin->sin6_flowinfo);
> +            RETVALUE_INC_SKIP();
> +        }
> +
> +        if (what & SA_IPV6_SCOPE_ID)
> +        {
> +            n = snprintf(stap_retvalue, maxstringlen,
> +                 "%d", sin->sin6_flowinfo);
> +            RETVALUE_INC_SKIP();
> +        }
>  	}
>  	else if ((sa->sa_family == AF_PACKET)
> -		 && (len == sizeof(struct sockaddr_ll))) 
> +		 && (len == sizeof(struct sockaddr_ll)))
>  	{
>  		struct sockaddr_ll *sll = (struct sockaddr_ll *)buf;
> -		snprintf(STAP_RETVALUE, MAXSTRINGLEN,
> -			 "{AF_PACKET, proto=%d, ind=%d, hatype=%d, pkttype=%d, halen=%d, addr=0x%llx}",
> -			 (int)sll->sll_protocol, sll->sll_ifindex,
> -			 (int)sll->sll_hatype, (int)sll->sll_pkttype,
> -			 (int)sll->sll_halen,
> -			 (long long)(*(uint64_t *)sll->sll_addr));
> +
> +        if (what & SA_PRETTY)
> +        {
> +            snprintf(STAP_RETVALUE, MAXSTRINGLEN,
> +                 "{AF_PACKET, proto=%d, ind=%d, hatype=%d, pkttype=%d, halen=%d, addr=0x%llx}",
> +                 (int)sll->sll_protocol, sll->sll_ifindex,
> +                 (int)sll->sll_hatype, (int)sll->sll_pkttype,
> +                 (int)sll->sll_halen,
> +                 (long long)(*(uint64_t *)sll->sll_addr));
> +        } else if (what & SA_FAMILY)
> +        { 
> +            strlcpy(STAP_RETVALUE, "AF_PACKET", MAXSTRINGLEN);
> +        } else
> +        {
> +            strlcpy(STAP_RETVALUE, "", MAXSTRINGLEN);
> +        }
>  	}
>  	else
>  	{
> @@ -389,6 +549,8 @@ function _struct_sockaddr_u:string(uaddr:long, len:long)
>  				 "{unknown sockaddr with salen=%d}", (int)len);
>  		}
>  	}
> +
> +#undef RETVALUE_INC_SKIP
>  %}
>  
>  function _struct_rlimit_u:string(uaddr:long)
> diff --git a/tapset/linux/nd_syscalls.stp b/tapset/linux/nd_syscalls.stp
> index f2daa01..5121751 100644
> --- a/tapset/linux/nd_syscalls.stp
> +++ b/tapset/linux/nd_syscalls.stp
> @@ -247,6 +247,7 @@ probe nd_syscall.bind = kprobe.function("sys_bind") ?
>  	sockfd = int_arg(1)
>  	my_addr_uaddr = pointer_arg(2)
>  	addrlen = int_arg(3)
> +	@_af_inet_info_u(my_addr_uaddr, addrlen)
>  	argstr = sprintf("%d, %s, %d", sockfd, _struct_sockaddr_u(my_addr_uaddr, addrlen), addrlen)
>  }
>  probe nd_syscall.bind.return = kprobe.function("sys_bind").return ?
> @@ -586,6 +587,7 @@ probe nd_syscall.connect = kprobe.function("sys_connect") ?
>  	sockfd = int_arg(1)
>  	serv_addr_uaddr = pointer_arg(2)
>  	addrlen = int_arg(3)
> +	@_af_inet_info_u(serv_addr_uaddr, addrlen)
>  	argstr = sprintf("%d, %s, %d", sockfd, _struct_sockaddr_u(serv_addr_uaddr, addrlen), addrlen)
>  }
>  probe nd_syscall.connect.return = kprobe.function("sys_connect").return ?
> diff --git a/tapset/linux/syscalls.stp b/tapset/linux/syscalls.stp
> index 13fb92f..d8e1d05 100644
> --- a/tapset/linux/syscalls.stp
> +++ b/tapset/linux/syscalls.stp
> @@ -199,6 +199,7 @@ probe syscall.bind = kernel.function("sys_bind").call ?
>  	sockfd = $fd
>  	my_addr_uaddr = $umyaddr
>  	addrlen = $addrlen
> +	@_af_inet_info_u(my_addr_uaddr, addrlen)
>  	argstr = sprintf("%d, %s, %d", $fd, _struct_sockaddr_u($umyaddr, $addrlen), $addrlen)
>  }
>  probe syscall.bind.return = kernel.function("sys_bind").return ?
> @@ -472,6 +473,7 @@ probe syscall.connect = kernel.function("sys_connect").call ?
>  	sockfd = $fd
>  	serv_addr_uaddr = $uservaddr
>  	addrlen = $addrlen
> +	@_af_inet_info_u(serv_addr_uaddr, addrlen)
>  	argstr = sprintf("%d, %s, %d", $fd, _struct_sockaddr_u($uservaddr, $addrlen), $addrlen)
>  }
>  probe syscall.connect.return = kernel.function("sys_connect").return ?
> diff --git a/tapset/linux/syscalls.stpm b/tapset/linux/syscalls.stpm
> new file mode 100644
> index 0000000..0ab18ab
> --- /dev/null
> +++ b/tapset/linux/syscalls.stpm
> @@ -0,0 +1,24 @@
> +// Macros for syscalls.stp and nd_syscalls.stp
> +// Copyright (C) 2013 Red Hat
> +//
> +// Author : Robin Hack <rhack@redhat.com>
> +//
> +// This file is part of systemtap, and is free software.  You can
> +// redistribute it and/or modify it under the terms of the GNU General
> +// Public License (GPL); either version 2, or (at your option) any
> +// later version.
> +
> +@define _af_inet_info_u(my_addr_uaddr, addrlen)
> +%(
> +	%( systemtap_v >= "2.5" %?
> +		uaddr_af = _struct_sockaddr_u_sa_family(@my_addr_uaddr, @addrlen)
> +		if (_struct_sockaddr_u_sa_family(@my_addr_uaddr, @addrlen) =~ "AF_INET.*") {
> +			uaddr_ip = _struct_sockaddr_u_ip_addr(@my_addr_uaddr, @addrlen)
> +			uaddr_ip_port = _struct_sockaddr_u_tcp_port(@my_addr_uaddr, @addrlen)
> +			if (_struct_sockaddr_u_sa_family(@my_addr_uaddr, @addrlen) == "AF_INET6") {
> +				uaddr_ipv6_flowinfo =  _struct_sockaddr_u_ipv6_flowinfo(@my_addr_uaddr, @addrlen)
> +				uaddr_ipv6_scope_id =  _struct_sockaddr_u_ipv6_scope_id(@my_addr_uaddr, @addrlen)
> +			}
> +		}
> +	%)
> +%)
> diff --git a/testsuite/buildok/aux_syscalls-embedded.stp b/testsuite/buildok/aux_syscalls-embedded.stp
> index 1fb5114..51b02c1 100755
> --- a/testsuite/buildok/aux_syscalls-embedded.stp
> +++ b/testsuite/buildok/aux_syscalls-embedded.stp
> @@ -14,6 +14,14 @@ probe begin {
>  	print (_struct_itimerval_u(0))
>  	print (_struct_compat_itimerval_u(0))
>  	print (_struct_sockaddr_u(0,0))
> +%( systemtap_v >= "2.5" %?
> +	print (_struct_sockaddr_u_ip_addr(0,0))
> +	print (_struct_sockaddr_u_tcp_port(0,0))
> +	print (_struct_sockaddr_u_sa_family(0,0))
> +	print (_struct_sockaddr_u_ipv6_flowinfo(0,0))
> +	print (_struct_sockaddr_u_ipv6_scope_id(0,0))
> +	print (_struct_sockaddr_u_impl(0,0,0))
> +%)
>  	print (_struct_rlimit_u(0))
>  	print (_fildes_index_u(0, 0))
>  
> diff --git a/testsuite/buildok/nd_syscalls-detailed.stp b/testsuite/buildok/nd_syscalls-detailed.stp
> index 8152f8d..4c9e0ed 100755
> --- a/testsuite/buildok/nd_syscalls-detailed.stp
> +++ b/testsuite/buildok/nd_syscalls-detailed.stp
> @@ -74,8 +74,13 @@ probe nd_syscall.bdflush.return ?
>  probe nd_syscall.bind
>  {
>  	printf("%s, %s\n", name, argstr)
> +%( systemtap_v >= "2.5" %?
> +	printf("%d, %p, %d, %s\n", sockfd, my_addr_uaddr, addrlen, uaddr_af)
> +%:
>  	printf("%d, %p, %d\n", sockfd, my_addr_uaddr, addrlen)
> +%)
>  }
> +
>  probe nd_syscall.bind.return
>  {
>  	printf("%s, %s\n", name, retstr)
> @@ -194,7 +199,11 @@ probe nd_syscall.close.return
>  probe nd_syscall.connect
>  {
>  	printf("%s, %s\n", name, argstr)
> +%( systemtap_v >= "2.5" %?
> +	printf("%d, %p, %d, %s\n", sockfd, serv_addr_uaddr, addrlen, uaddr_af)
> +%:
>  	printf("%d, %p, %d\n", sockfd, serv_addr_uaddr, addrlen)
> +%)
>  }
>  probe nd_syscall.connect.return
>  {
> diff --git a/testsuite/buildok/syscalls-detailed.stp b/testsuite/buildok/syscalls-detailed.stp
> index e1c626c..17544f7 100755
> --- a/testsuite/buildok/syscalls-detailed.stp
> +++ b/testsuite/buildok/syscalls-detailed.stp
> @@ -74,7 +74,12 @@ probe syscall.bdflush.return ?
>  probe syscall.bind
>  {
>  	printf("%s, %s\n", name, argstr)
> +
> +%( systemtap_v >= "2.5" %?
> +	printf("%d, %p, %d, %s\n", sockfd, my_addr_uaddr, addrlen, uaddr_af)
> +%:
>  	printf("%d, %p, %d\n", sockfd, my_addr_uaddr, addrlen)
> +%)
>  }
>  probe syscall.bind.return
>  {
> @@ -194,7 +199,11 @@ probe syscall.close.return
>  probe syscall.connect
>  {
>  	printf("%s, %s\n", name, argstr)
> +%( systemtap_v >= "2.5" %?
> +	printf("%d, %p, %d, %s\n", sockfd, serv_addr_uaddr, addrlen, uaddr_af)
> +%:
>  	printf("%d, %p, %d\n", sockfd, serv_addr_uaddr, addrlen)
> +%)
>  }
>  probe syscall.connect.return
>  {


diff --git a/tapset/linux/aux_syscalls.stp b/tapset/linux/aux_syscalls.stp
index 0f9c9e4..7b02628 100644
--- a/tapset/linux/aux_syscalls.stp
+++ b/tapset/linux/aux_syscalls.stp
@@ -280,7 +280,7 @@ function _struct_compat_itimerval_u:string(uaddr:long)
 %}
 
 %{
-// Needed for function _struct_sockaddr_u. Unfortunately cannot be
+// Needed for function _struct_sockaddr_u_impl. Unfortunately cannot be
 // inlined into the function since these header files define static
 // functions themselves.
 #include <linux/socket.h>
@@ -288,27 +288,87 @@ function _struct_compat_itimerval_u:string(uaddr:long)
 #include <linux/netlink.h>
 %}
 
+%{
+// Enum for _struct_sockaddr_u_* functions.
+typedef enum {
+    SA_PRETTY           = 1,
+    SA_IP_ADDR          = 2,
+    SA_TCP_PORT         = 4,
+    SA_FAMILY           = 8,
+    SA_IPV6_FLOWINFO    = 16,
+    SA_IPV6_SCOPE_ID    = 32,
+} sa_dispatch;
+%}
+
+function _struct_sockaddr_u_ip_addr:string(uaddr:long, len:long)
+{
+    return _struct_sockaddr_u_impl(uaddr, len, %{ SA_IP_ADDR %});
+}
+
+function _struct_sockaddr_u_tcp_port:string(uaddr:long, len:long)
+{
+    return _struct_sockaddr_u_impl(uaddr, len, %{ SA_TCP_PORT %});
+}
+
+function _struct_sockaddr_u_ip_addr_tcp_port:string(uaddr:long, len:long)
+{
+    return _struct_sockaddr_u_impl(uaddr, len, %{ SA_IP_ADDR | SA_TCP_PORT %});
+}
+
+function _struct_sockaddr_u_sa_family:string(uaddr:long, len:long)
+{
+    return _struct_sockaddr_u_impl(uaddr, len, %{ SA_FAMILY %});
+}
+
+function _struct_sockaddr_u_ipv6_flowinfo:string(uaddr:long, len:long)
+{
+    return _struct_sockaddr_u_impl(uaddr, len, %{ SA_IPV6_FLOWINFO %});
+}
+
+function _struct_sockaddr_u_ipv6_scope_id:string(uaddr:long, len:long)
+{
+    return _struct_sockaddr_u_impl(uaddr, len, %{ SA_IPV6_SCOPE_ID %});
+}
+
 function _struct_sockaddr_u:string(uaddr:long, len:long)
+{
+    return _struct_sockaddr_u_impl(uaddr, len, %{ SA_PRETTY %});
+}
+
+function _struct_sockaddr_u_impl:string(uaddr:long, len:long, what:long)
 %{ /* pure */
 #include <linux/version.h>
 #include <linux/in6.h>
 #include <linux/un.h>
 #include <linux/if_packet.h>
 
-	char *ptr = (char *)(unsigned long)STAP_ARG_uaddr;
-	char buf[128];
-	size_t len = STAP_ARG_len < 128 ? STAP_ARG_len : 128;
-	struct sockaddr *sa = (struct sockaddr *)buf;
+    sa_dispatch what = (sa_dispatch)STAP_ARG_what;
+
+    char *ptr = (char *)(unsigned long)STAP_ARG_uaddr;
+    // This helps handle variable lenght sockaddr_un.
+    // Some application - like systemd - sends path string
+    // without ending null character. Kernel will handle this.
+    char buf[128] = {'\0'};
+    size_t len = STAP_ARG_len < 128 ? STAP_ARG_len: 128;
+    struct sockaddr *sa = (struct sockaddr *)buf;
+
+    char *stap_retvalue = (char *)(unsigned long)STAP_RETVALUE;
+    int maxstringlen = MAXSTRINGLEN;
+    size_t n;
+
+    // If this will not be static, then gcc will be unhappy.
+    // There is limit to function frame size.
+    static char conv_buf[MAXSTRINGLEN];
 
 	if (ptr == NULL)
 	{
-		strlcpy (STAP_RETVALUE, "NULL", MAXSTRINGLEN);
+		strlcpy(STAP_RETVALUE, "NULL", MAXSTRINGLEN);
 		return;
 	}
 
 	if (_stp_copy_from_user(buf, ptr, len))
 	{
-		strlcpy (STAP_RETVALUE, "[...]", MAXSTRINGLEN);
+		strlcpy(STAP_RETVALUE, "[...]", MAXSTRINGLEN);
 		return;
 	}
 
@@ -326,54 +386,195 @@ function _struct_sockaddr_u:string(uaddr:long, len:long)
 	if ((sa->sa_family == AF_INET) && (len == sizeof(struct sockaddr_in)))
 	{
 		struct sockaddr_in *sin = (struct sockaddr_in *)buf;
-#ifndef NIPQUAD_FMT			// kver >= 2.6.36
-		snprintf(STAP_RETVALUE, MAXSTRINGLEN, "{AF_INET, %pI4, %d}",
-			 &sin->sin_addr, _stp_ntohs(sin->sin_port));
+
+        if (what & SA_PRETTY)
+        {
+#ifndef NIPQUAD_FMT                     // kver >= 2.6.36
+            snprintf(STAP_RETVALUE, MAXSTRINGLEN, "{AF_INET, %pI4, %d}",
+                &sin->sin_addr, _stp_ntohs(sin->sin_port));
 #else
-		snprintf(STAP_RETVALUE, MAXSTRINGLEN,
-			 "{AF_INET, " NIPQUAD_FMT ", %d}",
-			 NIPQUAD(sin->sin_addr), _stp_ntohs(sin->sin_port));
-#endif
+            snprintf(STAP_RETVALUE, MAXSTRINGLEN,
+                "{AF_INET, " NIPQUAD_FMT ", %d}",
+                NIPQUAD(sin->sin_addr), _stp_ntohs(sin->sin_port));
+#endif
+            return;
+        }
+
+        if (what & SA_FAMILY)
+        {
+            n = strlcpy(stap_retvalue, "AF_INET", maxstringlen);
+			// (n - 1) mean: cut of null char
+			stap_retvalue += (n);
+			maxstringlen -= (n - 1);
+        }
+
+        if (what & SA_IP_ADDR)
+        {
+#ifndef NIPQUAD_FMT                     // kver >= 2.6.36
+            n = snprintf(stap_retvalue, maxstringlen, "%pI4", &sin->sin_addr);
+#else
+            n = snprintf(stap_retvalue, maxstringlen, NIPQUAD_FMT,
+                    NIPQUAD(sin->sin_addr));
+#endif
+            // (n - 1) mean: cut of null char
+            stap_retvalue += (n);
+            maxstringlen -= (n - 1);
+        }
+
+        if (what & SA_TCP_PORT)
+        {
+            n = snprintf(stap_retvalue, maxstringlen, "%d",
+            _stp_ntohs(sin->sin_port));
+            // (n - 1) mean: cut of null char
+            stap_retvalue += (n);
+            maxstringlen -= (n - 1);
+        }
 	}
+    // Why 2 * sizeof (char) here?
+    // Because I want to support abstract sockets with
+    // at least one usable byte after initial \0 char.
+    // Unnamed sockets aren't supported yet.
 	else if ((sa->sa_family == AF_UNIX)
-		 && (len == sizeof(struct sockaddr_un)))
-	{	
-		struct sockaddr_un *sun = (struct sockaddr_un *)buf;	
-		snprintf(STAP_RETVALUE, MAXSTRINGLEN, "{AF_UNIX, %s}",
-			 sun->sun_path); 
+            && ((len == sizeof(struct sockaddr_un))
+            || (len >= ((sizeof(sa_family_t)) + (2 * sizeof(char))))))
+	{
+		struct sockaddr_un *sun = (struct sockaddr_un *)buf;
+		if (what & SA_PRETTY)
+		{
+
+			// Support for abstract sockets
+			if (sun->sun_path[0] == '\0')
+			{
+                // Abstract sockets aren't string oriented.
+                // We need conversion on this place.
+                // No check of ret value, because _stp_text_str returns
+                // "<unknown>" if bad things happen.
+                // Well. There can be NUL chars inside sun_path.
+                // We just stop at first NUL char.
+                _stp_text_str(conv_buf, &sun->sun_path[1],
+                    len - sizeof(sa_family_t), MAXSTRINGLEN - 1, 0, 0);
+                snprintf(STAP_RETVALUE, MAXSTRINGLEN, "{AF_UNIX, \\000%s}",
+                    conv_buf);
+			} else
+			{
+                // Just cut path if is too long
+                buf[127] = '\0';
+                snprintf(STAP_RETVALUE, MAXSTRINGLEN, "{AF_UNIX, %s}",
+                    sun->sun_path);
+			}
+		} else if (what & SA_FAMILY)
+		{
+            strlcpy(STAP_RETVALUE, "AF_UNIX", MAXSTRINGLEN);
+		} else
+		{
+			strlcpy(STAP_RETVALUE, "", MAXSTRINGLEN);
+		}
 	}
 	else if ((sa->sa_family == AF_NETLINK)
 		 && (len == sizeof(struct sockaddr_nl)))
 	{
 		struct sockaddr_nl *nl = (struct sockaddr_nl *)buf;
-		snprintf(STAP_RETVALUE, MAXSTRINGLEN,
-			 "{AF_NETLINK, pid=%d, groups=%08x}",
-			 nl->nl_pid, nl->nl_groups);
-	}
+
+        if (what & SA_PRETTY) {
+            snprintf(STAP_RETVALUE, MAXSTRINGLEN,
+                "{AF_NETLINK, pid=%d, groups=%08x}",
+                nl->nl_pid, nl->nl_groups);
+        } else if (what & SA_FAMILY)
+        {
+            strlcpy(STAP_RETVALUE, "AF_NETLINK", MAXSTRINGLEN);
+        } else
+        {
+            strlcpy(STAP_RETVALUE, "", MAXSTRINGLEN);
+        }
+    }
 	else if ((sa->sa_family == AF_INET6)
 		 && (len == sizeof(struct sockaddr_in6)))
 	{
 		struct sockaddr_in6 *sin = (struct sockaddr_in6 *)buf;
+
+        if (what & SA_PRETTY)
+        {
 #ifndef NIP6_FMT			// kver >= 2.6.36
-		snprintf(STAP_RETVALUE, MAXSTRINGLEN,
-			 "{AF_INET6, %pI6, %d}", &sin->sin6_addr,
-			 _stp_ntohs(sin->sin6_port));
+            snprintf(STAP_RETVALUE, MAXSTRINGLEN,
+                 "{AF_INET6, %pI6, %d}", &sin->sin6_addr,
+                 _stp_ntohs(sin->sin6_port));
 #else
-		snprintf(STAP_RETVALUE, MAXSTRINGLEN,
-			 "{AF_INET6, " NIP6_FMT ", %d}", NIP6(sin->sin6_addr),
-			 _stp_ntohs(sin->sin6_port));
-#endif
+            snprintf(STAP_RETVALUE, MAXSTRINGLEN,
+                 "{AF_INET6, " NIP6_FMT ", %d}", NIP6(sin->sin6_addr),
+                 _stp_ntohs(sin->sin6_port));
+#endif
+            return;
+        }
+
+        if (what & SA_FAMILY)
+        {
+            n = strlcpy(stap_retvalue, "AF_INET6", maxstringlen);
+			// (n - 1) mean: cut of null char
+			stap_retvalue += (n);
+			maxstringlen -= (n - 1);
+        }
+
+        if (what & SA_IP_ADDR)
+        {
+#ifndef NIP6_FMT			// kver >= 2.6.36
+            n = snprintf(stap_retvalue, maxstringlen,
+                 "%pI6", &sin->sin6_addr);
+#else
+            n = snprintf(stap_retvalue, maxstringlen,
+                 NIP6_FMT, NIP6(sin->sin6_addr));
+#endif
+			// (n - 1) mean: cut of null char
+			stap_retvalue += (n);
+			maxstringlen -= (n - 1);
+        }
+
+        if (what & SA_TCP_PORT)
+        {
+            n = snprintf(stap_retvalue, maxstringlen,
+                "%d", _stp_ntohs(sin->sin6_port));
+            // (n - 1) mean: cut of null char
+            stap_retvalue += (n);
+            maxstringlen -= (n - 1);
+        }
+
+        if (what & SA_IPV6_FLOWINFO)
+        {
+            n = snprintf(stap_retvalue, maxstringlen,
+                 "%d", sin->sin6_flowinfo);
+			// (n - 1) mean: cut of null char
+			stap_retvalue += (n);
+			maxstringlen -= (n - 1);
+        }
+
+        if (what & SA_IPV6_SCOPE_ID)
+        {
+            n = snprintf(stap_retvalue, maxstringlen,
+                 "%d", sin->sin6_flowinfo);
+			// (n - 1) mean: cut of null char
+			stap_retvalue += (n);
+			maxstringlen -= (n - 1);
+        }
 	}
 	else if ((sa->sa_family == AF_PACKET)
-		 && (len == sizeof(struct sockaddr_ll))) 
+		 && (len == sizeof(struct sockaddr_ll)))
 	{
 		struct sockaddr_ll *sll = (struct sockaddr_ll *)buf;
-		snprintf(STAP_RETVALUE, MAXSTRINGLEN,
-			 "{AF_PACKET, proto=%d, ind=%d, hatype=%d, pkttype=%d, halen=%d, addr=0x%llx}",
-			 (int)sll->sll_protocol, sll->sll_ifindex,
-			 (int)sll->sll_hatype, (int)sll->sll_pkttype,
-			 (int)sll->sll_halen,
-			 (long long)(*(uint64_t *)sll->sll_addr));
+
+        if (what & SA_PRETTY)
+        {
+            snprintf(STAP_RETVALUE, MAXSTRINGLEN,
+                 "{AF_PACKET, proto=%d, ind=%d, hatype=%d, pkttype=%d, halen=%d, addr=0x%llx}",
+                 (int)sll->sll_protocol, sll->sll_ifindex,
+                 (int)sll->sll_hatype, (int)sll->sll_pkttype,
+                 (int)sll->sll_halen,
+                 (long long)(*(uint64_t *)sll->sll_addr));
+        } else if (what & SA_FAMILY)
+        { 
+            strlcpy(STAP_RETVALUE, "AF_PACKET", MAXSTRINGLEN);
+        } else
+        {
+            strlcpy(STAP_RETVALUE, "", MAXSTRINGLEN);
+        }
 	}
 	else
 	{
diff --git a/tapset/linux/nd_syscalls.stp b/tapset/linux/nd_syscalls.stp
index f2daa01..5121751 100644
--- a/tapset/linux/nd_syscalls.stp
+++ b/tapset/linux/nd_syscalls.stp
@@ -247,6 +247,7 @@ probe nd_syscall.bind = kprobe.function("sys_bind") ?
 	sockfd = int_arg(1)
 	my_addr_uaddr = pointer_arg(2)
 	addrlen = int_arg(3)
+	@_af_inet_info_u(my_addr_uaddr, addrlen)
 	argstr = sprintf("%d, %s, %d", sockfd, _struct_sockaddr_u(my_addr_uaddr, addrlen), addrlen)
 }
 probe nd_syscall.bind.return = kprobe.function("sys_bind").return ?
@@ -586,6 +587,7 @@ probe nd_syscall.connect = kprobe.function("sys_connect") ?
 	sockfd = int_arg(1)
 	serv_addr_uaddr = pointer_arg(2)
 	addrlen = int_arg(3)
+	@_af_inet_info_u(serv_addr_uaddr, addrlen)
 	argstr = sprintf("%d, %s, %d", sockfd, _struct_sockaddr_u(serv_addr_uaddr, addrlen), addrlen)
 }
 probe nd_syscall.connect.return = kprobe.function("sys_connect").return ?
diff --git a/tapset/linux/syscalls.stp b/tapset/linux/syscalls.stp
index 13fb92f..d8e1d05 100644
--- a/tapset/linux/syscalls.stp
+++ b/tapset/linux/syscalls.stp
@@ -199,6 +199,7 @@ probe syscall.bind = kernel.function("sys_bind").call ?
 	sockfd = $fd
 	my_addr_uaddr = $umyaddr
 	addrlen = $addrlen
+	@_af_inet_info_u(my_addr_uaddr, addrlen)
 	argstr = sprintf("%d, %s, %d", $fd, _struct_sockaddr_u($umyaddr, $addrlen), $addrlen)
 }
 probe syscall.bind.return = kernel.function("sys_bind").return ?
@@ -472,6 +473,7 @@ probe syscall.connect = kernel.function("sys_connect").call ?
 	sockfd = $fd
 	serv_addr_uaddr = $uservaddr
 	addrlen = $addrlen
+	@_af_inet_info_u(serv_addr_uaddr, addrlen)
 	argstr = sprintf("%d, %s, %d", $fd, _struct_sockaddr_u($uservaddr, $addrlen), $addrlen)
 }
 probe syscall.connect.return = kernel.function("sys_connect").return ?
diff --git a/tapset/linux/syscalls.stpm b/tapset/linux/syscalls.stpm
new file mode 100644
index 0000000..0ab18ab
--- /dev/null
+++ b/tapset/linux/syscalls.stpm
@@ -0,0 +1,24 @@
+// Macros for syscalls.stp and nd_syscalls.stp
+// Copyright (C) 2013 Red Hat
+//
+// Author : Robin Hack <rhack@redhat.com>
+//
+// This file is part of systemtap, and is free software.  You can
+// redistribute it and/or modify it under the terms of the GNU General
+// Public License (GPL); either version 2, or (at your option) any
+// later version.
+
+@define _af_inet_info_u(my_addr_uaddr, addrlen)
+%(
+	%( systemtap_v >= "2.5" %?
+		uaddr_af = _struct_sockaddr_u_sa_family(@my_addr_uaddr, @addrlen)
+		if (_struct_sockaddr_u_sa_family(@my_addr_uaddr, @addrlen) =~ "AF_INET.*") {
+			uaddr_ip = _struct_sockaddr_u_ip_addr(@my_addr_uaddr, @addrlen)
+			uaddr_ip_port = _struct_sockaddr_u_tcp_port(@my_addr_uaddr, @addrlen)
+			if (_struct_sockaddr_u_sa_family(@my_addr_uaddr, @addrlen) == "AF_INET6") {
+				uaddr_ipv6_flowinfo =  _struct_sockaddr_u_ipv6_flowinfo(@my_addr_uaddr, @addrlen)
+				uaddr_ipv6_scope_id =  _struct_sockaddr_u_ipv6_scope_id(@my_addr_uaddr, @addrlen)
+			}
+		}
+	%)
+%)
diff --git a/testsuite/buildok/aux_syscalls-embedded.stp b/testsuite/buildok/aux_syscalls-embedded.stp
index 1fb5114..51b02c1 100755
--- a/testsuite/buildok/aux_syscalls-embedded.stp
+++ b/testsuite/buildok/aux_syscalls-embedded.stp
@@ -14,6 +14,14 @@ probe begin {
 	print (_struct_itimerval_u(0))
 	print (_struct_compat_itimerval_u(0))
 	print (_struct_sockaddr_u(0,0))
+%( systemtap_v >= "2.5" %?
+	print (_struct_sockaddr_u_ip_addr(0,0))
+	print (_struct_sockaddr_u_tcp_port(0,0))
+	print (_struct_sockaddr_u_sa_family(0,0))
+	print (_struct_sockaddr_u_ipv6_flowinfo(0,0))
+	print (_struct_sockaddr_u_ipv6_scope_id(0,0))
+	print (_struct_sockaddr_u_impl(0,0,0))
+%)
 	print (_struct_rlimit_u(0))
 	print (_fildes_index_u(0, 0))
 
diff --git a/testsuite/buildok/nd_syscalls-detailed.stp b/testsuite/buildok/nd_syscalls-detailed.stp
index 8152f8d..4c9e0ed 100755
--- a/testsuite/buildok/nd_syscalls-detailed.stp
+++ b/testsuite/buildok/nd_syscalls-detailed.stp
@@ -74,8 +74,13 @@ probe nd_syscall.bdflush.return ?
 probe nd_syscall.bind
 {
 	printf("%s, %s\n", name, argstr)
+%( systemtap_v >= "2.5" %?
+	printf("%d, %p, %d, %s\n", sockfd, my_addr_uaddr, addrlen, uaddr_af)
+%:
 	printf("%d, %p, %d\n", sockfd, my_addr_uaddr, addrlen)
+%)
 }
+
 probe nd_syscall.bind.return
 {
 	printf("%s, %s\n", name, retstr)
@@ -194,7 +199,11 @@ probe nd_syscall.close.return
 probe nd_syscall.connect
 {
 	printf("%s, %s\n", name, argstr)
+%( systemtap_v >= "2.5" %?
+	printf("%d, %p, %d, %s\n", sockfd, serv_addr_uaddr, addrlen, uaddr_af)
+%:
 	printf("%d, %p, %d\n", sockfd, serv_addr_uaddr, addrlen)
+%)
 }
 probe nd_syscall.connect.return
 {
diff --git a/testsuite/buildok/syscalls-detailed.stp b/testsuite/buildok/syscalls-detailed.stp
index e1c626c..17544f7 100755
--- a/testsuite/buildok/syscalls-detailed.stp
+++ b/testsuite/buildok/syscalls-detailed.stp
@@ -74,7 +74,12 @@ probe syscall.bdflush.return ?
 probe syscall.bind
 {
 	printf("%s, %s\n", name, argstr)
+
+%( systemtap_v >= "2.5" %?
+	printf("%d, %p, %d, %s\n", sockfd, my_addr_uaddr, addrlen, uaddr_af)
+%:
 	printf("%d, %p, %d\n", sockfd, my_addr_uaddr, addrlen)
+%)
 }
 probe syscall.bind.return
 {
@@ -194,7 +199,11 @@ probe syscall.close.return
 probe syscall.connect
 {
 	printf("%s, %s\n", name, argstr)
+%( systemtap_v >= "2.5" %?
+	printf("%d, %p, %d, %s\n", sockfd, serv_addr_uaddr, addrlen, uaddr_af)
+%:
 	printf("%d, %p, %d\n", sockfd, serv_addr_uaddr, addrlen)
+%)
 }
 probe syscall.connect.return
 {
diff --git a/testsuite/systemtap.examples/network/connect_stat.stp b/testsuite/systemtap.examples/network/connect_stat.stp
new file mode 100644
index 0000000..e0b59d0
--- /dev/null
+++ b/testsuite/systemtap.examples/network/connect_stat.stp
@@ -0,0 +1,31 @@
+#! /usr/bin/env stap
+
+############################################################
+# connect_stat.stp
+# Author: Robin Hack <rhack@redhat.com>
+# An example script show process tree of process
+# which tried to call connect with specific ip address
+############################################################
+
+function process_tree (ip:string) {
+    cur_proc = task_current();
+    parent_pid = task_pid(task_parent (cur_proc));
+
+    printf ("%s: ", ip);
+    while (parent_pid != 0) {
+        printf ("%s (%d),%d,%d -> ", task_execname(cur_proc), task_pid(cur_proc), task_uid(cur_proc),task_gid (cur_proc));
+        cur_proc = task_parent(cur_proc);
+        parent_pid = task_pid(task_parent (cur_proc));
+    }
+    # init process
+    if (task_pid (cur_proc) == 1) {
+        printf ("%s (%d),%d,%d\n", task_execname(cur_proc), task_pid(cur_proc), task_uid(cur_proc),task_gid (cur_proc));
+    }
+}
+
+probe syscall.connect {
+    if ((uaddr_af !~ "AF_INET*") || (uaddr_ip != @1)) {
+        next;
+    }
+    process_tree (uaddr_ip);
+}


----- End forwarded message -----


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]