public inbox for systemtap@sourceware.org
 help / color / mirror / Atom feed
* [PATCH] - DRAFT - Easy access to IP address in struct sockaddr in syscall.bind probe (for now)
@ 2013-11-13 14:47 Robin Hack
  2013-11-13 22:18 ` Frank Ch. Eigler
  0 siblings, 1 reply; 6+ messages in thread
From: Robin Hack @ 2013-11-13 14:47 UTC (permalink / raw)
  To: systemtap

[-- Attachment #1: Type: text/plain, Size: 955 bytes --]

Hi all.

Sometimes, I need to investigate connections to specific IP adresses (or ports, or address family, ...) on my server.
I need to track process trees, uid and other stuff... lot of very badly
written programs are runing on this server.

Then aiming to specific IP adress is something, what I'm not able in
systemtap by hand today. But not tomorrow! :)

What I want to achieve is something like:

probe syscall.bind {
    if (uaddr_ip == "192.168.1.1") {
        //... some actions ...//
    }
}

or better in syscall.connect probe.


Then I decided to write this patch. Patch is only draft now and comments are
very welcome.

Very easy example are attached too.

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.
    * Expansion to syscall.connect probe.
    * Write tapset shell for new internal functions.


Have nice day.
Robin Hack


[-- Attachment #2: uaddr_ip.patch --]
[-- Type: text/plain, Size: 10303 bytes --]

diff --git a/tapset/linux/aux_syscalls.stp b/tapset/linux/aux_syscalls.stp
index 0f9c9e4..a278e0c 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 {TMP_STAP_RETVALUE += (n); MAXLEN -= (n - 1);} while (0)
+    char *TMP_STAP_RETVALUE = (char *)(unsigned long)STAP_RETVALUE;
+    int MAXLEN = 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(TMP_STAP_RETVALUE, "AF_INET", MAXLEN);
+            RETVALUE_INC_SKIP();
+        }
+
+        if (what & SA_IP_ADDR)
+        {
+#ifndef NIPQUAD_FMT                     // kver >= 2.6.36
+            n = snprintf(TMP_STAP_RETVALUE, MAXLEN, "%pI4", &sin->sin_addr);
+#else
+            n = snprintf(TMP_STAP_RETVALUE, MAXLEN, NIPQUAD_FMT,
+                    NIPQUAD(sin->sin_addr));
+#endif
+            RETVALUE_INC_SKIP();
+        }
+
+        if (what & SA_TCP_PORT)
+        {
+            n = snprintf(TMP_STAP_RETVALUE, MAXLEN, "%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(TMP_STAP_RETVALUE, "AF_INET6", MAXLEN);
+            RETVALUE_INC_SKIP();
+        }
+
+        if (what & SA_IP_ADDR)
+        {
+#ifndef NIP6_FMT			// kver >= 2.6.36
+            n = snprintf(TMP_STAP_RETVALUE, MAXLEN,
+                 "%pI6", &sin->sin6_addr);
+#else
+            n = snprintf(TMP_STAP_RETVALUE, MAXLEN,
+                 NIP6_FMT, NIP6(sin->sin6_addr));
+#endif
+            RETVALUE_INC_SKIP();
+        }
+
+        if (what & SA_TCP_PORT)
+        {
+            n = snprintf(TMP_STAP_RETVALUE, MAXLEN,
+                 "%d", _stp_ntohs(sin->sin6_port));
+            RETVALUE_INC_SKIP();
+        }
+
+        if (what & SA_IPV6_FLOWINFO)
+        {
+            n = snprintf(TMP_STAP_RETVALUE, MAXLEN,
+                 "%d", sin->sin6_flowinfo);
+            RETVALUE_INC_SKIP();
+        }
+
+        if (what & SA_IPV6_SCOPE_ID)
+        {
+            n = snprintf(TMP_STAP_RETVALUE, MAXLEN,
+                 "%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..9c813c6 100644
--- a/tapset/linux/nd_syscalls.stp
+++ b/tapset/linux/nd_syscalls.stp
@@ -247,6 +247,9 @@ probe nd_syscall.bind = kprobe.function("sys_bind") ?
 	sockfd = int_arg(1)
 	my_addr_uaddr = pointer_arg(2)
 	addrlen = int_arg(3)
+%( systemtap_v >= "2.5" %? 
+	uaddr_ip = _struct_sockaddr_u_ip_addr(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 ?
diff --git a/tapset/linux/syscalls.stp b/tapset/linux/syscalls.stp
index 13fb92f..449ec20 100644
--- a/tapset/linux/syscalls.stp
+++ b/tapset/linux/syscalls.stp
@@ -199,6 +199,9 @@ probe syscall.bind = kernel.function("sys_bind").call ?
 	sockfd = $fd
 	my_addr_uaddr = $umyaddr
 	addrlen = $addrlen
+%( systemtap_v >= "2.5" %? 
+	uaddr_ip = _struct_sockaddr_u_ip_addr($umyaddr, $addrlen)
+%)
 	argstr = sprintf("%d, %s, %d", $fd, _struct_sockaddr_u($umyaddr, $addrlen), $addrlen)
 }
 probe syscall.bind.return = kernel.function("sys_bind").return ?

[-- Attachment #3: conn.stp --]
[-- Type: text/plain, Size: 224 bytes --]


probe syscall.connect {
	family = _struct_sockaddr_u_sa_family(serv_addr_uaddr, addrlen);
	if ( family == "AF_INET" || family == "AF_INET6" ) {
		printf ("%s\n", _struct_sockaddr_u_ip_addr (serv_addr_uaddr, addrlen));
	}
}

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [PATCH] - DRAFT - Easy access to IP address in struct sockaddr in syscall.bind probe (for now)
  2013-11-13 14:47 [PATCH] - DRAFT - Easy access to IP address in struct sockaddr in syscall.bind probe (for now) Robin Hack
@ 2013-11-13 22:18 ` Frank Ch. Eigler
  2013-11-17 10:18   ` Robin Hack
  2013-12-02 13:40   ` [PATCH] - DRAFT - Easy access to IP address in struct sockaddr in syscall.bind probe (for now)] Robin Hack
  0 siblings, 2 replies; 6+ messages in thread
From: Frank Ch. Eigler @ 2013-11-13 22:18 UTC (permalink / raw)
  To: Robin Hack; +Cc: systemtap


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, and doing the
RETVALUE_INC_SKIP dance inlined instead of as a macro?  What about
delimiters between the data corresponding to multiple SA_* selections?


> 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.
>     * Expansion to syscall.connect probe.
>     * Write tapset shell for new internal functions.

Yup, plus a test case (e.g., a testsuite/buildok file).

Thanks!

- FChE

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [PATCH] - DRAFT - Easy access to IP address in struct sockaddr in syscall.bind probe (for now)
  2013-11-13 22:18 ` Frank Ch. Eigler
@ 2013-11-17 10:18   ` Robin Hack
  2013-12-02 13:40   ` [PATCH] - DRAFT - Easy access to IP address in struct sockaddr in syscall.bind probe (for now)] Robin Hack
  1 sibling, 0 replies; 6+ messages in thread
From: Robin Hack @ 2013-11-17 10:18 UTC (permalink / raw)
  To: Frank Ch. Eigler; +Cc: systemtap

[-- Attachment #1: Type: text/plain, Size: 1906 bytes --]

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

[-- Attachment #2: uaddr_ip-v2.patch --]
[-- Type: text/plain, Size: 14613 bytes --]

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
 {

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [PATCH] - DRAFT - Easy access to IP address in struct sockaddr in syscall.bind probe (for now)]
  2013-11-13 22:18 ` Frank Ch. Eigler
  2013-11-17 10:18   ` Robin Hack
@ 2013-12-02 13:40   ` Robin Hack
  2013-12-02 14:04     ` Robin Hack
  1 sibling, 1 reply; 6+ messages in thread
From: Robin Hack @ 2013-12-02 13:40 UTC (permalink / raw)
  To: systemtap

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 -----

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [PATCH] - DRAFT - Easy access to IP address in struct sockaddr in syscall.bind probe (for now)]
  2013-12-02 13:40   ` [PATCH] - DRAFT - Easy access to IP address in struct sockaddr in syscall.bind probe (for now)] Robin Hack
@ 2013-12-02 14:04     ` Robin Hack
  2013-12-04 14:44       ` Robin Hack
  0 siblings, 1 reply; 6+ messages in thread
From: Robin Hack @ 2013-12-02 14:04 UTC (permalink / raw)
  To: systemtap

[-- Attachment #1: Type: text/plain, Size: 38254 bytes --]

Patch is attached here. Sorry. I'm still fighting with mutt.

On Mon, Dec 02, 2013 at 02:40:13PM +0100, Robin Hack wrote:
> 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 -----

[-- Attachment #2: uaddr_ip-v3.patch --]
[-- Type: text/plain, Size: 17722 bytes --]

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);
+}

^ permalink raw reply	[flat|nested] 6+ messages in thread

* Re: [PATCH] - DRAFT - Easy access to IP address in struct sockaddr in syscall.bind probe (for now)]
  2013-12-02 14:04     ` Robin Hack
@ 2013-12-04 14:44       ` Robin Hack
  0 siblings, 0 replies; 6+ messages in thread
From: Robin Hack @ 2013-12-04 14:44 UTC (permalink / raw)
  To: systemtap

[-- Attachment #1: Type: text/plain, Size: 59301 bytes --]

Hi.

I released new patch... again :).

Sorry for lot of spam, but I still learn systemtap in deep.

fche and mjw: lot of thanks.

On Mon, Dec 02, 2013 at 03:03:43PM +0100, Robin Hack wrote:
> Patch is attached here. Sorry. I'm still fighting with mutt.
> 
> On Mon, Dec 02, 2013 at 02:40:13PM +0100, Robin Hack wrote:
> > 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 -----

> 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);
> +}


[-- Attachment #2: uaddr_ip-v4.patch --]
[-- Type: text/plain, Size: 18783 bytes --]

diff --git a/runtime/common_probe_context.h b/runtime/common_probe_context.h
index 96499d8..1d49173 100644
--- a/runtime/common_probe_context.h
+++ b/runtime/common_probe_context.h
@@ -74,6 +74,15 @@ char *tok_start;
 char *tok_end;
 #endif
 
+/* Only used in file tapset/linux/aux_syscalls.stp
+ * function: _struct_sockaddr_u_impl.
+ * We need bigger buffers than is frame limit of function.
+ */
+#ifdef STAP_NEED_CONTEXT_SOCKADDR_BIG_BUFFERS
+char buf[128];
+string_t out_str;
+#endif
+
 /* Only used when stap script needs regexp subexpressions. */
 #ifdef STAP_NEED_CONTEXT_SUBEXPRESSION
 struct stapregex_match {
diff --git a/tapset/linux/aux_syscalls.stp b/tapset/linux/aux_syscalls.stp
index 0f9c9e4..ad61a81 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,91 @@ 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 %});
+}
+
+%{
+#define STAP_NEED_CONTEXT_SOCKADDR_BIG_BUFFERS 1
+%}
+
+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;
+    size_t len = STAP_ARG_len < 128 ? STAP_ARG_len: 128;
+    struct sockaddr *sa = (struct sockaddr *)CONTEXT->buf;
+
+    char *stap_retvalue = (char *)(unsigned long)STAP_RETVALUE;
+    int maxstringlen = MAXSTRINGLEN;
+    size_t n;
 
 	if (ptr == NULL)
 	{
-		strlcpy (STAP_RETVALUE, "NULL", MAXSTRINGLEN);
+		strlcpy(STAP_RETVALUE, "NULL", MAXSTRINGLEN);
 		return;
 	}
 
-	if (_stp_copy_from_user(buf, ptr, len))
+    // This helps handle variable lenght sockaddr_un.
+    // Some application - like systemd - sends path string
+    // without ending null character. Kernel will handle this
+    // but we need pretty output without random memory stuff.
+    memset(CONTEXT->buf, 0, 128);
+
+    if (_stp_copy_from_user(CONTEXT->buf, ptr, len))
 	{
-		strlcpy (STAP_RETVALUE, "[...]", MAXSTRINGLEN);
+		strlcpy(STAP_RETVALUE, "[...]", MAXSTRINGLEN);
 		return;
 	}
 
@@ -325,55 +389,198 @@ 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));
+		struct sockaddr_in *sin = (struct sockaddr_in *)CONTEXT->buf;
+
+        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 *)CONTEXT->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. 
+                // TODO: We need byte oriented conversion function.
+                _stp_text_str(CONTEXT->out_str, &sun->sun_path[1],
+                    len - sizeof(sa_family_t), MAXSTRINGLEN - 1, 0, 0);
+                snprintf(STAP_RETVALUE, MAXSTRINGLEN, "{AF_UNIX, \\000%s}",
+                    CONTEXT->out_str);
+            } else
+			{
+                // Just cut path if is too long
+                CONTEXT->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);
-	}
+		struct sockaddr_nl *nl = (struct sockaddr_nl *)CONTEXT->buf;
+
+        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;
+		struct sockaddr_in6 *sin = (struct sockaddr_in6 *)CONTEXT->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));
+		struct sockaddr_ll *sll = (struct sockaddr_ll *)CONTEXT->buf;
+
+        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);
+}

^ permalink raw reply	[flat|nested] 6+ messages in thread

end of thread, other threads:[~2013-12-04 14:44 UTC | newest]

Thread overview: 6+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2013-11-13 14:47 [PATCH] - DRAFT - Easy access to IP address in struct sockaddr in syscall.bind probe (for now) Robin Hack
2013-11-13 22:18 ` Frank Ch. Eigler
2013-11-17 10:18   ` Robin Hack
2013-12-02 13:40   ` [PATCH] - DRAFT - Easy access to IP address in struct sockaddr in syscall.bind probe (for now)] Robin Hack
2013-12-02 14:04     ` Robin Hack
2013-12-04 14:44       ` Robin Hack

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).