%{
#ifdef CONFIG_COMPAT
#include <linux/compat.h>

#ifndef STAPCONF_SIGSET_FROM_COMPAT_EXPORTED
void
sigset_from_compat(sigset_t *set, compat_sigset_t *compat)
{
	switch (_NSIG_WORDS) {
	case 4: set->sig[3] = compat->sig[6] | (((long)compat->sig[7]) << 32 );
	case 3: set->sig[2] = compat->sig[4] | (((long)compat->sig[5]) << 32 );
	case 2: set->sig[1] = compat->sig[2] | (((long)compat->sig[3]) << 32 );
	case 1: set->sig[0] = compat->sig[0] | (((long)compat->sig[1]) << 32 );
	}
}
#endif /* STAPCONF_SIGSET_FROM_COMPAT_EXPORTED */
#endif /* CONFIG_COMPAT */

%}

#
# Given a userspace pointer to a timeval,
# copy and decode it and return a string.
#
function _struct_timeval_u:string(uaddr:long, n:long)
%{ /* pure */
	int n = (int)STAP_ARG_n;
	struct timeval tv[n];
	char *ptr = (char *)(unsigned long)STAP_ARG_uaddr;
	
	if (ptr == NULL || n > 2)
		strlcpy (STAP_RETVALUE, "NULL", MAXSTRINGLEN);
	else {
		if(_stp_copy_from_user((char*)&tv, ptr, n*sizeof(struct timeval)) == 0) {
			if (n == 2)
				snprintf(STAP_RETVALUE, MAXSTRINGLEN, "[%ld.%06ld][%ld.%.06ld]", 
					tv[0].tv_sec, tv[0].tv_usec, tv[1].tv_sec, tv[1].tv_usec);
			else
				snprintf(STAP_RETVALUE, MAXSTRINGLEN, "[%ld.%06ld]", tv[0].tv_sec, tv[0].tv_usec);
	   	} else
			strlcpy (STAP_RETVALUE, "UNKNOWN", MAXSTRINGLEN);
	}
%}

function _struct_compat_timeval_u:string(uaddr:long, n:long)
%{ /* pure */
#ifdef CONFIG_COMPAT
	int n = (int)STAP_ARG_n;
	struct compat_timeval tv[n];
	char *ptr = (char *)(unsigned long)STAP_ARG_uaddr;

	if (ptr == NULL || n > 2)
		strlcpy (STAP_RETVALUE, "NULL", MAXSTRINGLEN);
	else {
		if(_stp_copy_from_user((char*)&tv, ptr, 	n*sizeof(struct compat_timeval)) == 0)
			if (n == 2)
				snprintf(STAP_RETVALUE, MAXSTRINGLEN, "[%ld.%06ld][%ld.%.06ld]", 
					(long)tv[0].tv_sec, (long)tv[0].tv_usec, (long)tv[1].tv_sec, (long)tv[1].tv_usec);
			else
				snprintf(STAP_RETVALUE, MAXSTRINGLEN, "[%ld.%06ld]", (long)tv[0].tv_sec, (long)tv[0].tv_usec);
	   	else
			strlcpy (STAP_RETVALUE, "UNKNOWN", MAXSTRINGLEN);
	}
#endif
%}

function _struct_timezone_u:string(uaddr:long)
%{ /* pure */
	struct timezone tz;
	char *ptr = (char *)(unsigned long)STAP_ARG_uaddr;
	
	if (ptr == NULL)
		strlcpy (STAP_RETVALUE, "NULL", MAXSTRINGLEN);
	else {
		if(_stp_copy_from_user((char*)&tz,ptr,sizeof(struct timezone)) == 0)
			snprintf(STAP_RETVALUE, MAXSTRINGLEN, "[%d, %d]", tz.tz_minuteswest, tz.tz_dsttime);
		else
			strlcpy (STAP_RETVALUE, "UNKNOWN", MAXSTRINGLEN);
	}
%} 

%{
// Needed for the following four functions
// _struct_utimbuf_actime, _struct_utimbuf_modtime,
// _struct_compat_utimbuf_actime, _struct_compat_utimbuf_modtime
#include <linux/utime.h>
%}

// Returns the value of the actime field of a utimbuf in user space
// at the given address, or zero on when userspace data is not accessible.
function _struct_utimbuf_actime:long(uaddr:long)
%{ /* pure */
	struct utimbuf ubuf;
	char *ptr = (char *)(unsigned long)STAP_ARG_uaddr;
	
	if (ptr == NULL)
	  STAP_RETVALUE = 0;
	else
	  if(_stp_copy_from_user((char*)&ubuf,ptr,sizeof(ubuf)) == 0)
	    STAP_RETVALUE = ubuf.actime;
	  else
	    STAP_RETVALUE = 0;
%} 

// Returns the value of the modtime field of a utimbuf in user space
// at the given address, or zero on when userspace data is not accessible.
function _struct_utimbuf_modtime:long(uaddr:long)
%{ /* pure */
	struct utimbuf ubuf;
	char *ptr = (char *)(unsigned long)STAP_ARG_uaddr;
	
	if (ptr == NULL)
	  STAP_RETVALUE = 0;
	else
	  if(_stp_copy_from_user((char*)&ubuf,ptr,sizeof(ubuf)) == 0)
	    STAP_RETVALUE = ubuf.modtime;
	  else
	    STAP_RETVALUE = 0;
%} 

// Returns the value of the actime field of a compat_utimbuf in user space
// at the given address, or zero on when userspace data is not accessible.
function _struct_compat_utimbuf_actime:long(uaddr:long)
%{ /* pure */
#ifdef CONFIG_COMPAT
	struct compat_utimbuf ubuf;
	char *ptr = (char *)(unsigned long)STAP_ARG_uaddr;
	
	if (ptr == NULL)
	  STAP_RETVALUE = 0;
	else
	  if(_stp_copy_from_user((char*)&ubuf,ptr,sizeof(ubuf)) == 0)
	    STAP_RETVALUE = ubuf.actime;
	  else
	    STAP_RETVALUE = 0;
#endif
%} 

// Returns the value of the modtime field of a compat_utimbuf in user space
// at the given address, or zero on when userspace data is not accessible.
function _struct_compat_utimbuf_modtime:long(uaddr:long)
%{ /* pure */
#ifdef CONFIG_COMPAT
	struct compat_utimbuf ubuf;
	char *ptr = (char *)(unsigned long)STAP_ARG_uaddr;
	
	if (ptr == NULL)
	  STAP_RETVALUE = 0;
	else
	  if(_stp_copy_from_user((char*)&ubuf,ptr,sizeof(ubuf)) == 0)
	    STAP_RETVALUE = ubuf.modtime;
	  else
	    STAP_RETVALUE = 0;
#endif
%} 

function _struct_timespec_u:string(uaddr:long, n:long)
%{ /* pure */
#define STP_UTIME_NOW  ((1l << 30) - 1l)
#define STP_UTIME_OMIT ((1l << 30) - 2l)
	int n = (int)STAP_ARG_n;
	struct timespec ts[n];
	char *ptr = (char *)(unsigned long)STAP_ARG_uaddr;

	if (ptr == NULL || n > 2)
		strlcpy (STAP_RETVALUE, "NULL", MAXSTRINGLEN);
	else {
		if(_stp_copy_from_user((char *)&ts, ptr, n*sizeof(struct timespec)))  {
			strlcpy (STAP_RETVALUE, "UNKNOWN", MAXSTRINGLEN);
		} else {
			char *str;
			int len, i = 0;
			ptr = STAP_RETVALUE;
			while (i < n) {
				str = NULL;
				if (ts[i].tv_nsec == STP_UTIME_NOW)
					str = "UTIME_NOW";
				else if (ts[i].tv_nsec == STP_UTIME_OMIT)
					str = "UTIME_OMIT";
				if (str)
					len = snprintf(ptr, MAXSTRINGLEN, "[%s]", str);
				else
					len = snprintf(ptr, MAXSTRINGLEN, "[%ld.%09ld]", (long)ts[i].tv_sec, ts[i].tv_nsec);
				ptr += len; i++;
			}
		}
	}
#undef STP_UTIME_NOW
#undef STP_UTIME_OMIT
%}
function _struct_compat_timespec_u:string(uaddr:long, n:long)
%{ /* pure */
#ifdef CONFIG_COMPAT
#define STP_UTIME_NOW  ((1l << 30) - 1l)
#define STP_UTIME_OMIT ((1l << 30) - 2l)
	int n = (int)STAP_ARG_n;
	struct compat_timespec ts[n];
	char *ptr = (char *)(unsigned long)STAP_ARG_uaddr;

	if (ptr == NULL || n > 2)
		strlcpy (STAP_RETVALUE, "NULL", MAXSTRINGLEN);
	else {
		if(_stp_copy_from_user((char *)&ts, ptr, n*sizeof(struct compat_timespec)))  {
			strlcpy (STAP_RETVALUE, "UNKNOWN", MAXSTRINGLEN);
		} else {
			char *str;
			int len, i = 0;
			ptr = STAP_RETVALUE;
			while (i < n) {
				str = NULL;
				if (ts[i].tv_nsec == STP_UTIME_NOW)
					str = "UTIME_NOW";
				else if (ts[i].tv_nsec == STP_UTIME_OMIT)
					str = "UTIME_OMIT";
				if (str)
					len = snprintf(ptr, MAXSTRINGLEN, "[%s]", str);
				else
					len = snprintf(ptr, MAXSTRINGLEN, "[%ld.%09ld]", (long)ts[i].tv_sec, (long)ts[i].tv_nsec);
				ptr += len; i++;
			}
		}
	}
#undef STP_UTIME_NOW
#undef STP_UTIME_OMIT
#endif
%}


function _struct_itimerspec_u:string(uaddr:long)
%{ /* pure */
	struct itimerspec its;
	char *ptr = (char *)(unsigned long)STAP_ARG_uaddr;
	
	if (ptr == NULL)
		strlcpy (STAP_RETVALUE, "NULL", MAXSTRINGLEN);
	else {
		if(_stp_copy_from_user((char *)&its, ptr,sizeof(struct itimerspec)))
			strlcpy (STAP_RETVALUE, "UNKNOWN", MAXSTRINGLEN);
		else
			snprintf(STAP_RETVALUE, MAXSTRINGLEN, "[%d.%06d,%d.%06d]",
				(int)its.it_interval.tv_sec, (int)its.it_interval.tv_nsec,
				(int)its.it_value.tv_sec, (int)its.it_value.tv_nsec);
	}	
%}

function _struct_itimerval_u:string(uaddr:long)
%{ /* pure */
	struct itimerval itv;
	char *ptr = (char *)(unsigned long)STAP_ARG_uaddr;

	if (ptr == NULL)
		strlcpy (STAP_RETVALUE, "NULL", MAXSTRINGLEN);
	else {
		if(_stp_copy_from_user((char *)&itv,ptr,sizeof(struct itimerval)))
			strlcpy (STAP_RETVALUE, "UNKNOWN", MAXSTRINGLEN);
		else
			snprintf(STAP_RETVALUE, MAXSTRINGLEN, "[%d.%06d,%d.%06d]", 
				(int)itv.it_interval.tv_sec, (int)itv.it_interval.tv_usec,
				(int)itv.it_value.tv_sec, (int)itv.it_value.tv_usec);
	}
%}

function _struct_compat_itimerval_u:string(uaddr:long)
%{ /* pure */
#ifdef CONFIG_COMPAT
	struct compat_itimerval itv;
	char *ptr = (char *)(unsigned long)STAP_ARG_uaddr;

	if (ptr == NULL)
		strlcpy (STAP_RETVALUE, "NULL", MAXSTRINGLEN);
	else {
		if(_stp_copy_from_user((char *)&itv,ptr,sizeof(struct compat_itimerval)))
			strlcpy (STAP_RETVALUE, "UNKNOWN", MAXSTRINGLEN);
		else
			snprintf(STAP_RETVALUE, MAXSTRINGLEN, "[%d.%06d,%d.%06d]", 
				(int)itv.it_interval.tv_sec, (int)itv.it_interval.tv_usec,
				(int)itv.it_value.tv_sec, (int)itv.it_value.tv_usec);
	}
#endif
%}

%{
// Needed for function _struct_sockaddr_u. Unfortunately cannot be
// inlined into the function since these header files define static
// functions themselves.
#include <linux/socket.h>
#include <linux/in.h>
#include <linux/netlink.h>
%}

function _struct_sockaddr_u:string(uaddr:long, len: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;

	if (ptr == NULL)
	{
		strlcpy (STAP_RETVALUE, "NULL", MAXSTRINGLEN);
		return;
	}

	if (_stp_copy_from_user(buf, ptr, len))
	{
		strlcpy (STAP_RETVALUE, "[...]", MAXSTRINGLEN);
		return;
	}

#if LINUX_VERSION_CODE < KERNEL_VERSION(2,6,11)
#define LPORT   (inet->inet.num)
#define DADDR   (&inet->inet.daddr)
#else
#define LPORT   (inet->num)
#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));
#else
		snprintf(STAP_RETVALUE, MAXSTRINGLEN,
			 "{AF_INET, " NIPQUAD_FMT ", %d}",
			 NIPQUAD(sin->sin_addr), _stp_ntohs(sin->sin_port));
#endif
	}
	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); 
	}
	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);
	}
	else if ((sa->sa_family == AF_INET6)
		 && (len == sizeof(struct sockaddr_in6)))
	{
		struct sockaddr_in6 *sin = (struct sockaddr_in6 *)buf;
#ifndef NIP6_FMT			// kver >= 2.6.36
		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
	}
	else if ((sa->sa_family == AF_PACKET)
		 && (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));
	}
	else
	{
		if (len >= sizeof(sa_family_t))
		{
			snprintf(STAP_RETVALUE, MAXSTRINGLEN,
				 "{unknown sockaddr with sa=%d, salen=%d}",
				 sa->sa_family, (int) len);
		}
		else
		{
			snprintf(STAP_RETVALUE, MAXSTRINGLEN,
				 "{unknown sockaddr with salen=%d}", (int)len);
		}
	}
%}

function _struct_rlimit_u:string(uaddr:long)
%{ /* pure */
	struct rlimit rl;
	char *ptr = (char *)(unsigned long)STAP_ARG_uaddr;

	if (ptr == NULL)
		strlcpy (STAP_RETVALUE, "NULL", MAXSTRINGLEN);
	else {
		if (_stp_copy_from_user((char *)&rl, ptr, sizeof(struct rlimit)) == 0)
			snprintf(STAP_RETVALUE, MAXSTRINGLEN, "[%ld,%ld]",
				rl.rlim_cur, rl.rlim_max);
		else
			strlcpy (STAP_RETVALUE, "UNKNOWN", MAXSTRINGLEN);
	}
%}

function _fildes_index_u:long (uaddr:long, index:long)
%{ /* pure */
	int fd[2];
	char *ptr = (char *)(unsigned long)STAP_ARG_uaddr;

	if (ptr == NULL || !(STAP_ARG_index == 0 || STAP_ARG_index == 1))
		STAP_RETVALUE = 0;
	else {
		if (_stp_copy_from_user((char *)&fd, ptr, 2*sizeof(int)) == 0)
			STAP_RETVALUE = fd[STAP_ARG_index];
		else
			STAP_RETVALUE = 0;
	}
%}


function __sem_flags:string(semflg:long)
%{ /* pure */
	long semflg = STAP_ARG_semflg;
	char *str = STAP_RETVALUE;
	int mode = semflg & S_IRWXUGO;
	int len;

	str[0] = '\0';
	if (mode)
		snprintf(str, MAXSTRINGLEN, "%#o|", mode); 
	if (semflg & IPC_CREAT)
		strlcat(str, "IPC_CREAT|", MAXSTRINGLEN);
	if (semflg & IPC_EXCL)
		strlcat(str, "IPC_EXCL|", MAXSTRINGLEN);

	len = strlen(str);
	if (len)
		str[len-1] = 0;
%}


/* This function copies an argv from userspace. */
function __get_argv:string(argv:long, first:long)
{
%( CONFIG_64BIT == "y" %?
	if (first && argv)
		argv += 8
	while (argv) {
		vstr = user_long(argv)
		if (!vstr)
			break
		if (len)
			str .= " "
		str .= user_string_quoted(vstr)

		newlen = strlen(str)
		if (newlen == len)
			break
		len = newlen
		argv += 8
	}

	return str
%:
	return __get_compat_argv(argv, first)
%)
}
/* This function copies an argv from userspace. */
function __get_compat_argv:string(argv:long, first:long)
{
	if (first && argv)
		argv += 4
	while (argv) {
		vstr = user_int(argv) & 0xffffffff
		if (!vstr)
			break
		if (len)
			str .= " "
		str .= user_string_quoted(vstr)

		newlen = strlen(str)
		if (newlen == len)
			break
		len = newlen
		argv += 4
	}

	return str
}

/*
 * Return the  symbolic string  representation
 * of the struct timex.mode member of adjtimex
 * consult `man adjtimex` for more information
 * CALLERS:
 *    syscall.adjtimex
 */
function _adjtx_mode_str(f) {
   if((f & 32769) == 32769) bs="ADJ_OFFSET_SINGLESHOT|".bs
   if(f  & 16384) bs="ADJ_TICK|".bs
   if(f  & 32)    bs="ADJ_TIMECONST|".bs
   if(f  & 16)    bs="ADJ_STATUS|".bs
   if(f  & 8)     bs="ADJ_ESTERROR|".bs
   if(f  & 4)     bs="ADJ_MAXERROR|".bs
   if(f  & 2)     bs="ADJ_FREQUENCY|".bs
   if(f & 1 && ((f & 32769) != 32769)) bs="ADJ_OFFSET|".bs
   return substr(bs,0,strlen(bs)-1)
}

function _inotify_watch_mask_str(f) {
	if (f & 0x00000001) bs="IN_ACCESS|"
	if (f & 0x00000002) bs=bs."IN_MODIFY|"
	if (f & 0x00000004) bs=bs."IN_ATTRIB|"
	if (f & 0x00000008) bs=bs."IN_CLOSE_WRITE|"
	if (f & 0x00000010) bs=bs."IN_CLOSE_NOWRITE|"
	if (f & 0x00000020) bs=bs."IN_OPEN|"
	if (f & 0x00000040) bs=bs."IN_MOVED_FROM|"
	if (f & 0x00000080) bs=bs."IN_MOVED_TO|"
	if (f & 0x00000100) bs=bs."IN_CREATE|"
	if (f & 0x00000200) bs=bs."IN_DELETE|"
	if (f & 0x00000400) bs=bs."IN_DELETE_SELF|"
	if (f & 0x00000800) bs=bs."IN_MOVE_SELF|"
	return substr(bs,0,strlen(bs)-1)
}

/*
 * Return the symbolic string representation
 * of the how argument given in *sigprocmask
 * consult  `man sigprocmask`  for more info
 * CALLERS:
 *    syscall.sigprocmask
 *    syscall.rt_sigprocmask
 */
function _sigprocmask_how_str:string(how:long)
%{ /* pure */
	int len;
	char *str = STAP_RETVALUE;
	switch (STAP_ARG_how) {
	case SIG_BLOCK:
		strlcpy(str, "SIG_BLOCK", MAXSTRINGLEN);
		break;
	case SIG_UNBLOCK:
		strlcpy(str, "SIG_UNBLOCK", MAXSTRINGLEN);
		break;
	case SIG_SETMASK:
		strlcpy(str, "SIG_SETMASK", MAXSTRINGLEN);
		break;
	default:
		snprintf(str, MAXSTRINGLEN, "0x%lx", (long)STAP_ARG_how);
	}	
%}

/*
 * Return the symbolic string representation
 * of the which argument  given to setitimer
 * consult  `man setitimer`  for  more  info
 * CALLERS:
 *    syscall.getitimer
 *    syscall.setitimer
 * INCLUDE: <linux/time.h>
 */
function _itimer_which_str(which) {
   if(which==0) return "ITIMER_REAL"
   if(which==1) return "ITIMER_VIRTUAL"
   if(which==2) return "ITIMER_PROF"
   return sprintf("BAD VALUE: %d", which)
}

/*
 * Return the command name for nfsservctl()
 * nfsservctl was removed in kernel 3.0/2.6.40.
 */
%( kernel_v < "2.6.40" && CONFIG_NFSD == "[ym]" %?
function _nfsctl_cmd_str(cmd) {
	if(cmd == 0) return "NFSCTL_SVC"
	if(cmd == 1) return "NFSCTL_ADDCLIENT"
	if(cmd == 2) return "NFSCTL_DELCLIENT"
	if(cmd == 3) return "NFSCTL_EXPORT"
	if(cmd == 4) return "NFSCTL_UNEXPORT"
	if(cmd == 5) return "NFSCTL_UGIDUPDATE"
	if(cmd == 6) return "NFSCTL_GETFH" 
	if(cmd == 7) return "NFSCTL_GETFD"
	if(cmd == 8) return "NFSCTL_GETFS"
	return sprintf("UNRECOGNIZED VALUE: %d", cmd)
}
%)

/*
 * Return  the  symbolic   string  representation
 * of the clockid argument  given to create_timer
 * consult  `man create_timer`  for  more  info
 * CALLERS:
 *    syscall.timer_create
 *    syscall.clock_settime
 *    syscall.clock_gettime
 *    syscall.clock_getres
 *    syscall.clock_nanosleep
 */
function _get_wc_str(wc) {
   if(wc==0) return "CLOCK_REALTIME"
   if(wc==1) return "CLOCK_MONOTONIC"
   if(wc==2) return "CLOCK_PROCESS_CPUTIME_ID"
   if(wc==3) return "CLOCK_THREAD_CPUTIME_ID"
   if(wc==4) return "CLOCK_REALTIME_HR"
   if(wc==5) return "CLOCK_MONOTONIC_HR"
   return sprintf("BAD VALUE: %d", wc)
}

function _flock_cmd_str(c) {
   if(c & 1) bs="LOCK_SH|".bs
   if(c & 2) bs="LOCK_EX|".bs
   if(c & 8) bs="LOCK_UN|".bs
   if(c & 4) bs="LOCK_NB|".bs
   return substr(bs,0,strlen(bs)-1)
}

/* `man 2 pipe2` for more information */
function _sys_pipe2_flag_str:string (f:long)
%{ /* pure */ /* unprivileged */
  long flags = STAP_ARG_f;
  char *str = STAP_RETVALUE;
  int len;

  str[0] = '\0';
#if defined(O_NONBLOCK)
  if (flags & O_NONBLOCK)
    strlcat(str, "O_NONBLOCK|", MAXSTRINGLEN);
#endif
#if defined(O_CLOEXEC)
  if (flags & O_CLOEXEC)
    strlcat(str, "O_CLOEXEC|", MAXSTRINGLEN);
#endif

  len = strlen(str);
  if (len)
    str[strlen(str)-1] = 0;
%}

/* `man 2 open` for more information */
function _sys_open_flag_str:string (f:long)
%{ /* pure */
	int flags = (int)STAP_ARG_f;
	int acc = flags & O_ACCMODE;

	switch (acc) {
	case O_WRONLY:
		strlcpy (STAP_RETVALUE, "O_WRONLY", MAXSTRINGLEN);
		break;
	case O_RDWR:
		strlcpy (STAP_RETVALUE, "O_RDWR", MAXSTRINGLEN);
		break;
	default:
		strlcpy (STAP_RETVALUE, "O_RDONLY", MAXSTRINGLEN);
	}

#ifdef O_APPEND
	if (flags & O_APPEND)
		strlcat (STAP_RETVALUE, "|O_APPEND", MAXSTRINGLEN);
#endif
#ifdef O_ASYNC
	if (flags & O_ASYNC)
		strlcat (STAP_RETVALUE, "|O_ASYNC", MAXSTRINGLEN);
#elif defined(FASYNC)
	if (flags & FASYNC)
		strlcat (STAP_RETVALUE, "|O_ASYNC", MAXSTRINGLEN);
#endif
#ifdef O_CLOEXEC
	if (flags & O_CLOEXEC)
		strlcat (STAP_RETVALUE, "|O_CLOEXEC", MAXSTRINGLEN);
#endif
#ifdef O_CREAT
	if (flags & O_CREAT)
		strlcat (STAP_RETVALUE, "|O_CREAT", MAXSTRINGLEN);
#endif
#ifdef O_DIRECT
	if (flags & O_DIRECT)
		strlcat (STAP_RETVALUE, "|O_DIRECT", MAXSTRINGLEN);
#endif
#ifdef O_DIRECTORY
	if (flags & O_DIRECTORY)
		strlcat (STAP_RETVALUE, "|O_DIRECTORY", MAXSTRINGLEN);
#endif
#ifdef O_EXCL
	if (flags & O_EXCL)
		strlcat (STAP_RETVALUE, "|O_EXCL", MAXSTRINGLEN);
#endif
#ifdef O_LARGEFILE
	if (flags & O_LARGEFILE)
		strlcat (STAP_RETVALUE, "|O_LARGEFILE", MAXSTRINGLEN);
#endif
#ifdef O_NOATIME
	if (flags & O_NOATIME)
		strlcat (STAP_RETVALUE, "|O_NOATIME", MAXSTRINGLEN);
#endif
#ifdef O_NOCTTY
	if (flags & O_NOCTTY)
		strlcat (STAP_RETVALUE, "|O_NOCTTY", MAXSTRINGLEN);
#endif
#ifdef O_NOFOLLOW
	if (flags & O_NOFOLLOW)
		strlcat (STAP_RETVALUE, "|O_NOFOLLOW", MAXSTRINGLEN);
#endif
#ifdef O_NONBLOCK
	if (flags & O_NONBLOCK)
		strlcat (STAP_RETVALUE, "|O_NONBLOCK", MAXSTRINGLEN);
#endif
#ifdef O_SYNC
	if (flags & O_SYNC)
		strlcat (STAP_RETVALUE, "|O_SYNC", MAXSTRINGLEN);
#endif
#ifdef O_TRUNC
	if (flags & O_TRUNC)
		strlcat (STAP_RETVALUE, "|O_TRUNC", MAXSTRINGLEN);
#endif
%}


/* `man 2 open` for more information */
function _access_mode_str(m) {
	if((m & 7) == 0) return "F_OK"	
	if(m & 4) bs="R_OK |".bs
	if(m & 2) bs="W_OK |".bs
	if(m & 1) bs="X_OK |".bs
	return substr(bs,0,strlen(bs)-2)
}

/* `man 2 open` for more information */
function _sys_open_mode_str(f) {
   if((f & 448) == 448) bs="S_IRWXU|".bs
   else {
        if(f & 256) bs="S_IRUSR|".bs
        if(f & 128) bs="S_IWUSR|".bs
        if(f & 64) bs="S_IXUSR|".bs
   }
   if((f & 56) == 56) bs="S_IRWXG|".bs
   else {
        if(f & 32) bs="S_IRGRP|".bs
        if(f & 16) bs="S_IWGRP|".bs
        if(f & 8) bs="S_IXGRP|".bs
   }
   if((f & 7) == 7) bs="S_IRWXO|".bs
   else {
        if(f & 4) bs="S_IROTH|".bs
        if(f & 2) bs="S_IWOTH|".bs
        if(f & 1) bs="S_IXOTH|".bs
   }
   return substr(bs,0,strlen(bs)-1)
}

/* `man 2 mknod` for more information */
function _mknod_mode_str(mode) {
   if((mode & 0xF000)==0x8000)
        return "S_IFREG|"._sys_open_mode_str(mode)
   if((mode & 0xF000)==0x2000)
        return "S_IFCHR|"._sys_open_mode_str(mode)
   if((mode & 0xF000)==0x6000)
        return "S_IFBLK|"._sys_open_mode_str(mode)
   if((mode & 0xF000)==0x1000)
        return "S_IFIFO|"._sys_open_mode_str(mode)
   if((mode & 0xF000)==0xC000)
        return "S_IFSOCK|"._sys_open_mode_str(mode)
   return ""
}

/* `man msync` for more information */
function _msync_flag_str(f) {
	if (f & 7 == 0) return ""
	if(f & 4) bs="MS_SYNC|".bs
	if(f & 2) bs="MS_INVALIDATE|".bs
	if(f & 1) bs="MS_ASYNC|".bs
	return substr(bs,0,strlen(bs)-1)
}

function _internal_wait_opt_str(f,bit_num,bit_str) {
  retval=""
  if (f & %{ WNOHANG %})
    {
      f&=%{ ~WNOHANG %}
      retval=retval."|WNOHANG"
    }
  if (f & bit_num)
    {
      f&=~bit_num
      retval=retval."|".bit_str
    }
  if (f & %{ WEXITED %})
    {
      f&=%{ ~WEXITED %}
      retval=retval."|WEXITED"
    }
  if (f & %{ WCONTINUED %})
    {
      f&=%{ ~WCONTINUED %}
      retval=retval."|WCONTINUED"
    }
  if (f & %{ WNOWAIT %})
    {
      f&=%{ ~WNOWAIT %}
      retval=retval."|WNOWAIT"
    }
  if (f & %{ __WNOTHREAD %})
    {
      f&=%{ ~__WNOTHREAD %}
      retval=retval."|__WNOTHREAD"
    }
  if (f & %{ __WALL %})
    {
      f&=%{ ~__WALL %}
      retval=retval."|__WALL"
    }
  if (f & %{ __WCLONE %})
    {
      f&=%{ ~__WCLONE %}
      retval=retval."|__WCLONE"
    }
  if (f != 0)
    retval=retval.sprintf ("|0x%x", f)
  else if (retval == "")
    return "0"
  return substr(retval,1,strlen(retval)-1)
}

/* `man wait4` for more information */
function _wait4_opt_str(f) {
   return _internal_wait_opt_str(f,%{ WUNTRACED %},"WUNTRACED")
}

/* `man waitid` for more information */
function _waitid_opt_str(f) {
   return _internal_wait_opt_str(f,%{ WSTOPPED %},"WSTOPPED")
}

function WIFEXITED(f) {
  return (f & 0x7f) == 0
}

function WEXITSTATUS(f) {
  return (f & 0xff00) >> 8
}

function WIFSIGNALED(f) {
  return (f & 0x7f) != 0 && (f & 0x7f) != 0x7f
}

function WCOREDUMP(f) {
  return f & 0x80
}

function WTERMSIG(f) {
  return f & 0x7f
}

function WIFSTOPPED(f) {
  return (f & 0xff) == 0x7f
}

function WSTOPSIG(f) {
  return (f & 0xff00) >> 8
}

function WIFCONTINUED(f) {
  return f == 0xffff
}

function _ptrace_event_name(f)
{
  if (f == %{ PTRACE_EVENT_FORK %})
    return "PTRACE_EVENT_FORK"
  if (f == %{ PTRACE_EVENT_VFORK %})
    return "PTRACE_EVENT_VFORK"
  if (f == %{ PTRACE_EVENT_CLONE %})
    return "PTRACE_EVENT_CLONE"
  if (f == %{ PTRACE_EVENT_EXEC %})
    return "PTRACE_EVENT_EXEC"
  if (f == %{ PTRACE_EVENT_VFORK_DONE %})
    return "PTRACE_EVENT_VFORK_DONE"
  if (f == %{ PTRACE_EVENT_EXIT %})
    return "PTRACE_EVENT_EXIT"
  return ""
}

/* `man 2 wait` for more information */
function _wait_status_str(f) {
  if ((f >> 16) != 0)
    tail = sprintf (" | 0x%x", f & ~0xffff)
  else
    tail = ""

  if (WIFEXITED(f))
    return sprintf ("WEXITSTATUS=%d", WEXITSTATUS(f)).tail
  if (WIFSIGNALED(f)) {
      if (WCOREDUMP(f))
        return "WCOREDUMP".tail
      return sprintf ("WTERMSIG=%s", _signal_name(WTERMSIG(f))).tail
    }
  if (WIFSTOPPED(f))
    {
      if (WSTOPSIG(f) == %{ SIGTRAP %})
	{
	  event = _ptrace_event_name (f >> 16)
	  if (event != "")
	    tail = " | ".event." << 8"
	}
      return sprintf ("WSTOPSIG=%s", _signal_name(WSTOPSIG(f))).tail
    }
  if (WIFCONTINUED(f))
    return "WIFCONTINUED".tail
  return sprintf ("?=0x%x", f)
}

/* `man sendmsg` for more information */
function _sendflags_str(f) {
   if(f & 0x0001) bs="MSG_OOB|".bs
   if(f & 0x0080) bs="MSG_EOR|".bs
   if(f & 0x0004) bs="MSG_DONTROUTE|".bs
   if(f & 0x0040) bs="MSG_DONTWAIT|".bs
   if(f & 0x4000) bs="MSG_NOSIGNAL|".bs
   if(f & 0x0800) bs="MSG_CONFIRM|".bs
   if(f & 0x8000) bs="MSG_MORE|".bs
   return substr(bs,0,strlen(bs)-1)
}

/* `man recv` for more information */
function _recvflags_str(f) {
   if(f & 1) bs="MSG_OOB|".bs
   if(f & 2) bs="MSG_PEEK|".bs
   if(f & 32) bs="MSG_TRUNC|".bs
   if(f & 64) bs="MSG_DONTWAIT|".bs
   if(f & 256) bs="MSG_WAITALL|".bs
   if(f & 8192) bs="MSG_ERRQUEUE|".bs
   if(f & 0x40000000) bs="MSG_CMSG_CLOEXEC|".bs
   return substr(bs,0,strlen(bs)-1)
}

/* `man mlockall` for more information */
function _mlockall_flags_str:string(flags:long)
%{ /* pure */
	#include <linux/mman.h>
	int len;
	long f = STAP_ARG_flags;
	char *str = STAP_RETVALUE;
	str[0] = '\0';
	if (f & MCL_CURRENT)
		strlcat(str, "MCL_CURRENT|", MAXSTRINGLEN);
	if (f & MCL_FUTURE)
		strlcat(str, "MCL_FUTURE|", MAXSTRINGLEN);
	len = strlen(str);
	if (len)
		str[strlen(str)-1] = '\0';
	else	
		snprintf(str, MAXSTRINGLEN, "0x%lx", f);
%}

/* used by sys_delete_module */
function _module_flags_str:string(flags:long)
%{ /* pure */
	int len;
	long flags = STAP_ARG_flags;
	char *str = STAP_RETVALUE;
	str[0] = '\0';
	if (flags & O_TRUNC)
		strlcat(str,"O_TRUNC|", MAXSTRINGLEN);
	if (flags & O_NONBLOCK)
		strlcat(str,"O_NONBLOCK|", MAXSTRINGLEN);
	len = strlen(str);
	if (len)
		str[strlen(str)-1] = '\0';
%}

function _sched_policy_str(policy) {
   if(policy==0) return "SCHED_OTHER"
   if(policy==1) return "SCHED_FIFO"
   if(policy==2) return "SCHED_RR"
   if(policy==3) return "SCHED_BATCH"
   return sprintf("UNKNOWN VALUE: %d", policy)
}

function _priority_which_str(which) {
   if(which==0) return "PRIO_PROCESS"
   if(which==1) return "PRIO_PGRP"
   if(which==2) return "PRIO_USER"
   return sprintf("UNKNOWN VALUE: %d", which)
}

function _shutdown_how_str(how) {
   if(how==0) return "SHUT_RD"
   if(how==1) return "SHUT_WR"
   if(how==2) return "SHUT_RDWR"
   return sprintf("UNKNOWN VALUE: %d", how)
}

%{
// Needed for function __reboot_magic_str:string. Unfortunately cannot
// be inlined into the function since these header file defines static
// functions on some architectures.
#include <linux/reboot.h>
%}

function _reboot_magic_str:string(magic:long)
%{ /* pure */
	int magic = (int)STAP_ARG_magic;
	switch (magic) {
	case LINUX_REBOOT_MAGIC1:
		strlcpy(STAP_RETVALUE, "LINUX_REBOOT_MAGIC1", MAXSTRINGLEN);
		break;
	case LINUX_REBOOT_MAGIC2:
		strlcpy(STAP_RETVALUE, "LINUX_REBOOT_MAGIC2", MAXSTRINGLEN);
		break;
	case LINUX_REBOOT_MAGIC2A:
		strlcpy(STAP_RETVALUE, "LINUX_REBOOT_MAGIC2A", MAXSTRINGLEN);
		break;
	case LINUX_REBOOT_MAGIC2B:
		strlcpy(STAP_RETVALUE, "LINUX_REBOOT_MAGIC2B", MAXSTRINGLEN);
		break;
/*
	LINUX_REBOOT_MAGIC2C is supported from kernel 2.6
*/
#ifdef LINUX_REBOOT_MAGIC2C
	case LINUX_REBOOT_MAGIC2C:
		strlcpy(STAP_RETVALUE, "LINUX_REBOOT_MAGIC2C", MAXSTRINGLEN);
		break;
#endif
	default:
		snprintf(STAP_RETVALUE, MAXSTRINGLEN, "UNKNOWN VALUE: %d", magic);
	}
%}

function _reboot_flag_str(flag) {
   if(flag==0x01234567) return "LINUX_REBOOT_CMD_RESTART"
   if(flag==0xCDEF0123) return "LINUX_REBOOT_CMD_HALT"
   if(flag==0x4321FEDC) return "LINUX_REBOOT_CMD_POWER_OFF"
   if(flag==0xA1B2C3D4) return "LINUX_REBOOT_CMD_RESTART2"
   if(flag==0x89ABCDEF) return "LINUX_REBOOT_CMD_CAD_ON"
   if(flag==0x00000000) return "LINUX_REBOOT_CMD_CAD_OFF"
   if(flag==0xD000FCE2) return "LINUX_REBOOT_CMD_SW_SUSPEND"
   if(flag==0x45584543) return "LINUX_REBOOT_CMD_KEXEC"
   return sprintf("UNKNOWN VALUE: %d", flag)
}

function _waitid_which_str(flag) {
   if(flag==0) return "P_ALL"
   if(flag==1) return "P_PID"
   if(flag==2) return "P_PGID"
   return sprintf("UNKNOWN VALUE: %d", flag)
}

function _futex_op_str(op) {
   if(op==0) return "FUTEX_WAIT"
   if(op==1) return "FUTEX_WAKE"
   if(op==2) return "FUTEX_FD"
   if(op==3) return "FUTEX_REQUEUE"
   if(op==4) return "FUTEX_CMP_REQUEUE"
   if(op==5) return "FUTEX_WAKE_OP"
   if(op==6) return "FUTEX_LOCK_PI"
   if(op==7) return "FUTEX_UNLOCK_PI"
   if(op==8) return "FUTEX_TRYLOCK_PI"
   if(op==128) return "FUTEX_WAIT_PRIVATE"
   if(op==129) return "FUTEX_WAKE_PRIVATE"
   if(op==131) return "FUTEX_REQUEUE_PRIVATE"
   if(op==132) return "FUTEX_CMP_REQUEUE_PRIVATE"
   if(op==133) return "FUTEX_WAKE_OP_PRIVATE"
   if(op==134) return "FUTEX_LOCK_PI_PRIVATE"
   if(op==135) return "FUTEX_UNLOCK_PI_PRIVATE"
   if(op==136) return "FUTEX_TRYLOCK_PI_PRIVATE"
   return sprintf("UNKNOWN VALUE: %d", op)
}

function _mountflags_str:string(op:long) 
%{ /* pure */
	int len, op = STAP_ARG_op;
	char *str = STAP_RETVALUE;
	str[0] = '\0';
	if (op & MS_BIND)
		strlcat(str,"MS_BIND|",MAXSTRINGLEN);
	if (op & MS_DIRSYNC)
		strlcat(str,"MS_DIRSYNC|",MAXSTRINGLEN);
	if (op & MS_MANDLOCK)
		strlcat(str,"MS_MANDLOCK|",MAXSTRINGLEN);
	if (op & MS_MOVE)
		strlcat(str,"MS_MOVE|",MAXSTRINGLEN);
	if (op & MS_NOATIME)
		strlcat(str,"MS_NOATIME|",MAXSTRINGLEN);
	if (op & MS_NODEV)
		strlcat(str,"MS_NODEV|",MAXSTRINGLEN);
	if (op & MS_NODIRATIME)
		strlcat(str,"MS_NODIRATIME|",MAXSTRINGLEN);
	if (op & MS_NOEXEC)
		strlcat(str,"MS_NOEXEC|",MAXSTRINGLEN);
	if (op & MS_NOSUID)
		strlcat(str,"MS_NOSUID|",MAXSTRINGLEN);
	if (op & MS_RDONLY)
		strlcat(str,"MS_RDONLY|",MAXSTRINGLEN);
	if (op & MS_REC)
		strlcat(str,"MS_REC|",MAXSTRINGLEN);
	if (op & MS_REMOUNT)
		strlcat(str,"MS_REMOUNT|",MAXSTRINGLEN);
	if (op & MS_SYNCHRONOUS)
		strlcat(str,"MS_SYNCHRONOUS|",MAXSTRINGLEN);
	if (op & MS_VERBOSE)
		strlcat(str,"MS_VERBOSE|",MAXSTRINGLEN);
	len = strlen(str);
	if (len)
		str[strlen(str)-1] = '\0';
%}

function _umountflags_str:string(op:long) 
%{ /* pure */
	int len, op = STAP_ARG_op;
	char *str = STAP_RETVALUE;
	if (op == 0)
		strlcpy(str,"0",MAXSTRINGLEN);
	else {
		str[0] = '\0';
		if (op & MNT_FORCE)
			strlcat(str,"MNT_FORCE|",MAXSTRINGLEN);
		if (op & MNT_DETACH)
			strlcat(str,"MNT_DETACH|",MAXSTRINGLEN);
		if (op & MNT_EXPIRE)
			strlcat(str,"MNT_EXPIRE|",MAXSTRINGLEN);
		len = strlen(str);
		if (len)
			str[strlen(str)-1] = '\0';
	}
%}

function _statfs_f_type_str(f) {
   if(f==0xadf5)     return "ADFS_SUPER_MAGIC"
   if(f==0xADFF)     return "AFFS_SUPER_MAGIC"
   if(f==0x42465331) return "BEFS_SUPER_MAGIC"
   if(f==0x1BADFACE) return "BFS_MAGIC"
   if(f==0xFF534D42) return "CIFS_MAGIC_NUMBER"
   if(f==0x73757245) return "CODA_SUPER_MAGIC"
   if(f==0x012FF7B7) return "COH_SUPER_MAGIC"
   if(f==0x28cd3d45) return "CRAMFS_MAGIC"
   if(f==0x1373)     return "DEVFS_SUPER_MAGIC"
   if(f==0x00414A53) return "EFS_SUPER_MAGIC"
   if(f==0x137D)     return "EXT_SUPER_MAGIC"
   if(f==0xEF51)     return "EXT2_OLD_SUPER_MAGIC"
   if(f==0xEF53)     return "EXT2_SUPER_MAGIC"
   if(f==0xEF53)     return "EXT3_SUPER_MAGIC"
   if(f==0x4244)     return "HFS_SUPER_MAGIC"
   if(f==0xF995E849) return "HPFS_SUPER_MAGIC"
   if(f==0x958458f6) return "HUGETLBFS_MAGIC"
   if(f==0x9660)     return "ISOFS_SUPER_MAGIC"
   if(f==0x72b6)     return "JFFS2_SUPER_MAGIC"
   if(f==0x3153464a) return "JFS_SUPER_MAGIC"
   if(f==0x137F)     return "MINIX_SUPER_MAGIC"
   if(f==0x138F)     return "MINIX_SUPER_MAGIC2"
   if(f==0x2468)     return "MINIX2_SUPER_MAGIC"
   if(f==0x2478)     return "MINIX2_SUPER_MAGIC2"
   if(f==0x4d44)     return "MSDOS_SUPER_MAGIC"
   if(f==0x564c)     return "NCP_SUPER_MAGIC"
   if(f==0x6969)     return "NFS_SUPER_MAGIC"
   if(f==0x5346544e) return "NTFS_SB_MAGIC"
   if(f==0x9fa1)     return "OPENPROM_SUPER_MAGIC"
   if(f==0x9fa0)     return "PROC_SUPER_MAGIC"
   if(f==0x002f)     return "QNX4_SUPER_MAGIC"
   if(f==0x52654973) return "REISERFS_SUPER_MAGIC"
   if(f==0x7275)     return "ROMFS_MAGIC"
   if(f==0x517B)     return "SMB_SUPER_MAGIC"
   if(f==0x012FF7B6) return "SYSV2_SUPER_MAGIC"
   if(f==0x012FF7B5) return "SYSV4_SUPER_MAGIC"
   if(f==0x01021994) return "TMPFS_MAGIC"
   if(f==0x15013346) return "UDF_SUPER_MAGIC"
   if(f==0x00011954) return "UFS_MAGIC"
   if(f==0x9fa2)     return "USBDEVICE_SUPER_MAGIC"
   if(f==0xa501FCF5) return "VXFS_SUPER_MAGIC"
   if(f==0x012FF7B4) return "XENIX_SUPER_MAGIC"
   if(f==0x58465342) return "XFS_SUPER_MAGIC"
   if(f==0x012FD16D) return "_XIAFS_SUPER_MAGIC"
   return sprintf("UNKNOWN VALUE: %d", f)
}

function _mremap_flags(flags) {
	if (flags & 1) msg="MREMAP_MAYMOVE|"
	if (flags & 2) msg="MREMAP_FIXED|".msg
	return substr(msg,0,strlen(msg)-1)
}

function _madvice_advice_str(behavior) {
   if(behavior==0x00000000) return "MADV_NORMAL"
   if(behavior==0x00000001) return "MADV_RANDOM"
   if(behavior==0x00000002) return "MADV_SEQUENTIAL"
   if(behavior==0x00000003) return "MADV_WILLNEED"
   if(behavior==0x00000004) return "MADV_DONTNEED"
   return sprintf("UNKNOWN VALUE: %d", behavior)
}

function _fadvice_advice_str(behavior) {
   if(behavior==0x00000000) return "FADV_NORMAL"
   if(behavior==0x00000001) return "FADV_RANDOM"
   if(behavior==0x00000002) return "FADV_SEQUENTIAL"
   if(behavior==0x00000003) return "FADV_WILLNEED"
   if(behavior==0x00000004) return "FADV_DONTNEED"
   return sprintf("UNKNOWN VALUE: %d", behavior)
}

function _fcntl_cmd_str(cmd) {
   if(cmd==0) return "F_DUPFD"
   if(cmd==1) return "F_GETFD"
   if(cmd==2) return "F_SETFD"
   if(cmd==3) return "F_GETFL"
   if(cmd==4) return "F_SETFL"
   if(cmd==5) return "F_GETLK"
   if(cmd==6) return "F_SETLK"
   if(cmd==7) return "F_SETLKW"
   if(cmd==8) return "F_SETOWN"
   if(cmd==9) return "F_GETOWN"
   if(cmd==10) return "F_SETSIG"
   if(cmd==11) return "F_GETSIG"
   if(cmd==12) return "F_GETLK64"
   if(cmd==13) return "F_SETLK64"
   if(cmd==14) return "F_SETLKW64"
   if(cmd==1030) return "F_DUPFD_CLOEXEC"
   return sprintf("UNKNOWN VALUE: %d", cmd)
}

%{
#include <linux/fs.h>
#ifndef SEEK_SET
#define SEEK_SET	0
#endif
#ifndef SEEK_CUR
#define SEEK_CUR	1
#endif
#ifndef SEEK_END
#define SEEK_END	2
#endif
#ifndef SEEK_DATA
#define SEEK_DATA	3
#endif
#ifndef SEEK_HOLE
#define SEEK_HOLE	4
#endif
%}
function _seek_whence_str(w) {
   if (w == %{ SEEK_SET %}) return "SEEK_SET"
   if (w == %{ SEEK_CUR %}) return "SEEK_CUR"
   if (w == %{ SEEK_END %}) return "SEEK_END"
   if (w == %{ SEEK_DATA %}) return "SEEK_DATA"
   if (w == %{ SEEK_HOLE %}) return "SEEK_HOLE"
   return sprintf("UNKNOWN VALUE: %d", w)
}

function _quotactl_cmd_str(cmd) {
   if(cmd==0x800002) return "Q_QUOTAON"
   if(cmd==0x800003) return "Q_QUOTAOFF"
   if(cmd==0x800007) return "Q_GETQUOTA"
   if(cmd==0x800008) return "Q_SETQUOTA"
   if(cmd==0x800005) return "Q_GETINFO"
   if(cmd==0x800006) return "Q_SETINFO"
   if(cmd==0x800004) return "Q_GETFMT"
   if(cmd==0x800001) return "Q_SYNC"
   /* XFS Quota Manager (XQM) Codes */
   if(cmd==0x5801) return "Q_XQUOTAON"
   if(cmd==0x5802) return "Q_XQUOTAOFF"
   if(cmd==0x5803) return "Q_XGETQUOTA"
   if(cmd==0x5804) return "Q_XSETQLIM"
   if(cmd==0x5805) return "Q_XGETQSTAT"
   if(cmd==0x5806) return "Q_XQUOTARM"
   if(cmd==0x5807) return "Q_XQUOTASYNC"
   return sprintf("UNKNOWN VALUE: %d", cmd)
}

/* see sys/socket.h (for setsockopt) */
function _sockopt_optname_str(opt) {
   if(opt==1) return "SO_DEBUG"
   if(opt==2) return "SO_REUSEADDR"
   if(opt==3) return "SO_TYPE"
   if(opt==4) return "SO_ERROR"
   if(opt==5) return "SO_DONTROUTE"
   if(opt==6) return "SO_BROADCAST"
   if(opt==7) return "SO_SNDBUF"
   if(opt==8) return "SO_RCVBUF"
   if(opt==9) return "SO_KEEPALIVE"
   if(opt==10) return "SO_OOBINLINE"
   if(opt==11) return "SO_NO_CHECK"
   if(opt==12) return "SO_PRIORITY"
   if(opt==13) return "SO_LINGER"
   if(opt==14) return "SO_BSDCOMPAT"

   if(opt==16) return "SO_PASSCRED"
   if(opt==17) return "SO_PEERCRED"
   if(opt==18) return "SO_RCVLOWAT"
   if(opt==19) return "SO_SNDLOWAT"
   if(opt==20) return "SO_RCVTIMEO"
   if(opt==21) return "SO_SNDTIMEO"
   if(opt==32) return "SO_SNDBUFFORCE"
   if(opt==33) return "SO_RCVBUFFORCE"
   return sprintf("UNKNOWN VALUE: %d", opt)
}

/* `man 2 setsockopt` for more information */
function _sockopt_level_str(l) {
   if(l==0) return "IP"
   if(l==1) return "SOL_SOCKET" # not ICMP
   if(l==2) return "IGMP"
   if(l==3) return "GGP"
   if(l==4) return "IP-ENCAP"
   if(l==5) return "ST"
   if(l==6) return "TCP"
   if(l==7) return "CBT"
   if(l==8) return "EGP"
   if(l==9) return "IGP"
   if(l==10) return "BBN-RCC-MON"
   if(l==11) return "NVP-II"
   if(l==12) return "PUP"
   if(l==13) return "ARGUS"
   if(l==14) return "EMCON"
   if(l==15) return "XNET"
   if(l==16) return "CHAOS"
   if(l==17) return "UDP"
   if(l==18) return "MUX"
   if(l==19) return "DCN-MEAS"
   if(l==20) return "HMP"
   if(l==21) return "PRM"
   if(l==22) return "XNS-IDP"
   if(l==23) return "TRUNK-1"
   if(l==24) return "TRUNK-2"
   if(l==25) return "LEAF-1"
   if(l==26) return "LEAF-2"
   if(l==27) return "RDP"
   if(l==28) return "IRTP"
   if(l==29) return "ISO-TP4"
   if(l==30) return "NETBLT"
   if(l==31) return "MFE-NSP"
   if(l==32) return "MERIT-INP"
   if(l==33) return "SEP"
   if(l==34) return "3PC"
   if(l==35) return "IDPR"
   if(l==36) return "XTP"
   if(l==37) return "DDP"
   if(l==38) return "IDPR-CMTP"
   if(l==39) return "TP++"
   if(l==40) return "IL"
   if(l==41) return "IPv6"
   if(l==42) return "SDRP"
   if(l==43) return "IPv6-Route"
   if(l==44) return "IPv6-Frag"
   if(l==45) return "IDRP"
   if(l==46) return "RSVP"
   if(l==47) return "GRE"
   if(l==48) return "MHRP"
   if(l==49) return "BNA"
   if(l==50) return "IPv6-Crypt"
   if(l==51) return "IPv6-Auth"
   if(l==52) return "I-NLSP"
   if(l==53) return "SWIPE"
   if(l==54) return "NARP"
   if(l==55) return "MOBILE"
   if(l==56) return "TLSP"
   if(l==57) return "SKIP"
   if(l==58) return "IPv6-ICMP"
   if(l==59) return "IPv6-NoNxt"
   if(l==60) return "IPv6-Opts"
   if(l==62) return "CFTP"
   if(l==64) return "SAT-EXPAK"
   if(l==65) return "KRYPTOLAN"
   if(l==66) return "RVD"
   if(l==67) return "IPPC"
   if(l==69) return "SAT-MON"
   if(l==70) return "VISA"
   if(l==71) return "IPCV"
   if(l==72) return "CPNX"
   if(l==73) return "CPHB"
   if(l==74) return "WSN"
   if(l==75) return "PVP"
   if(l==76) return "BR-SAT-MON"
   if(l==77) return "SUN-ND"
   if(l==78) return "WB-MON"
   if(l==79) return "WB-EXPAK"
   if(l==80) return "ISO-IP"
   if(l==81) return "VMTP"
   if(l==82) return "SECURE-VMTP"
   if(l==83) return "VINES"
   if(l==84) return "TTP"
   if(l==85) return "NSFNET-IGP"
   if(l==86) return "DGP"
   if(l==87) return "TCF"
   if(l==88) return "EIGRP"
   if(l==89) return "OSPFIGP"
   if(l==90) return "Sprite-RPC"
   if(l==91) return "LARP"
   if(l==92) return "MTP"
   if(l==93) return "AX.25"
   if(l==94) return "IPIP"
   if(l==95) return "MICP"
   if(l==96) return "SCC-SP"
   if(l==97) return "ETHERIP"
   if(l==98) return "ENCAP"
   if(l==100) return "GMTP"
   if(l==101) return "IFMP"
   if(l==102) return "PNNI"
   if(l==103) return "PIM"
   if(l==104) return "ARIS"
   if(l==105) return "SCPS"
   if(l==106) return "QNX"
   if(l==107) return "A/N"
   if(l==108) return "IPComp"
   if(l==109) return "SNP"
   if(l==110) return "Compaq-Peer"
   if(l==111) return "IPX-in-IP"
   if(l==112) return "VRRP"
   if(l==113) return "PGM"
   if(l==115) return "L2TP"
   if(l==116) return "DDX"
   if(l==117) return "IATP"
   if(l==118) return "STP"
   if(l==119) return "SRP"
   if(l==120) return "UTI"
   if(l==121) return "SMP"
   if(l==122) return "SM"
   if(l==123) return "PTP"
   if(l==124) return "ISIS"
   if(l==125) return "FIRE"
   if(l==126) return "CRTP"
   if(l==127) return "CRUDP"
   if(l==128) return "SSCOPMCE"
   if(l==129) return "IPLT"
   if(l==130) return "SPS"
   if(l==131) return "PIPE"
   if(l==132) return "SCTP"
   if(l==133) return "FC"
   if(l==134) return "RSVP-E2E-IGNORE"
   if(l==135) return "Mobility-Header"
   if(l==136) return "UDPLite"
   if(l==137) return "MPLS-IN-IP"
   return sprintf("UNKNOWN VALUE: %d", l)
}

function _sock_family_str(f) {
   if(f==0) return "PF_UNSPEC"
   if(f==1) return "PF_LOCAL"
   if(f==2) return "PF_INET"
   if(f==3) return "PF_AX25"
   if(f==4) return "PF_IPX"
   if(f==5) return "PF_APPLETALK"
   if(f==6) return "PF_NETROM"
   if(f==7) return "PF_BRIDGE"
   if(f==8) return "PF_ATMPVC"
   if(f==9) return "PF_X25"
   if(f==10) return "PF_INET6"
   if(f==11) return "PF_ROSE"
   if(f==12) return "PF_DECnet"
   if(f==13) return "PF_NETBEUI"
   if(f==14) return "PF_SECURITY"
   if(f==15) return "PF_KEY"
   if(f==16) return "PF_NETLINK"
   if(f==17) return "PF_PACKET"
   if(f==18) return "PF_ASH"
   if(f==19) return "PF_ECONET"
   if(f==20) return "PF_ATMSVC"
   if(f==22) return "PF_SNA"
   if(f==23) return "PF_IRDA"
   if(f==24) return "PF_PPPOX"
   if(f==25) return "PF_WANPIPE"
   if(f==26) return "PF_LLC"
   if(f==30) return "PF_TIPC"
   if(f==31) return "PF_BLUETOOTH"
   if(f==32) return "PF_IUCV"
   if(f==33) return "PF_RXRPC"
   return sprintf("UNKNOWN VALUE: %d", f)
}

function _sock_type_str:string(type:long)
%{ /* pure */
#ifdef SOCK_TYPE_MASK
	int flags = (int)STAP_ARG_type & ~SOCK_TYPE_MASK;
	int t = (int)STAP_ARG_type & SOCK_TYPE_MASK;
#else
	int t = (int)STAP_ARG_type;
#endif

	switch (t) {
	case SOCK_STREAM:
		strlcpy (STAP_RETVALUE, "SOCK_STREAM", MAXSTRINGLEN);
		break;
	case SOCK_DGRAM:
		strlcpy (STAP_RETVALUE, "SOCK_DGRAM", MAXSTRINGLEN);
		break;
	case SOCK_RAW:
		strlcpy (STAP_RETVALUE, "SOCK_RAW", MAXSTRINGLEN);
		break;
	case SOCK_RDM:
		strlcpy (STAP_RETVALUE, "SOCK_RDM", MAXSTRINGLEN);
		break;
	case SOCK_SEQPACKET:
		strlcpy (STAP_RETVALUE, "SOCK_SEQPACKET", MAXSTRINGLEN);
		break;
#ifdef SOL_DCCP
	case SOCK_DCCP:
		strlcpy (STAP_RETVALUE, "SOCK_DCCP", MAXSTRINGLEN);
		break;
#endif
	case SOCK_PACKET:
		strlcpy (STAP_RETVALUE, "SOCK_PACKET", MAXSTRINGLEN);
		break;
	default:
		snprintf (STAP_RETVALUE, MAXSTRINGLEN, "UNKNOWN VALUE: %d", t);
		break;
	}

#ifdef SOCK_TYPE_MASK
	if (flags & SOCK_CLOEXEC) {
		strlcat (STAP_RETVALUE, "|SOCK_CLOEXEC", MAXSTRINGLEN);
	}
	if (flags & SOCK_NONBLOCK) {
		strlcat (STAP_RETVALUE, "|SOCK_NONBLOCK", MAXSTRINGLEN);
	}
#endif
%}

function _sock_flags_str:string(f:long)
%{ /* pure */
#ifdef SOCK_TYPE_MASK
	int flags = (int)STAP_ARG_f;
	int len;

	STAP_RETVALUE[0] = '\0';
	if (flags & SOCK_CLOEXEC) {
		strlcat (STAP_RETVALUE, "SOCK_CLOEXEC|", MAXSTRINGLEN);
	}
	if (flags & SOCK_NONBLOCK) {
		strlcat (STAP_RETVALUE, "SOCK_NONBLOCK|", MAXSTRINGLEN);
	}
	len = strlen(STAP_RETVALUE);
	if (len) {
		STAP_RETVALUE[len - 1] = '\0';
	}
	else {
		strlcat (STAP_RETVALUE, "0", MAXSTRINGLEN);
	}
#endif
%}

function _opoll_op_str(o) {
   if(o==1) return "EPOLL_CTL_ADD"
   if(o==3) return "EPOLL_CTL_MOD"
   if(o==2) return "EPOLL_CTL_DEL"
   return sprintf("UNKNOWN VALUE: %d", o)
}

function _epoll_events_str(e) {
   if(e==1) return "EPOLLIN"
   if(e==4) return "EPOLLOUT"
   if(e==2) return "EPOLLPRI"
   if(e==8) return "EPOLLERR"
   if(e==16) return "EPOLLHUP"
   if(e==-2147483648) return "EPOLLET"
   if(e==1073741824) return "EPOLLONESHOT"
   return sprintf("UNKNOWN VALUE: %d", e)
}

function _rlimit_resource_str(r) {
   if(r==-1) return "RLIM_INFINITY"
   if(r==9) return "RLIMIT_AS"
   if(r==4) return "RLIMIT_CORE"
   if(r==0) return "RLIMIT_CPU"
   if(r==2) return "RLIMIT_DATA"
   if(r==1) return "RLIMIT_FSIZE"
   if(r==10) return "RLIMIT_LOCKS"
   if(r==8) return "RLIMIT_MEMLOCK"
   if(r==7) return "RLIMIT_NOFILE"
   if(r==6) return "RLIMIT_NPROC"
   if(r==5) return "RLIMIT_RSS"
   if(r==3) return "RLIMIT_STACK"
%( kernel_v >= "2.6.8" %?
   if(r==11) return "RLIMIT_SIGPENDING"
   if(r==12) return "RLIMIT_MSGQUEUE"
%)
%( kernel_v >= "2.6.12" %?
   if(r==13) return "RLIMIT_NICE"
   if(r==14) return "RLIMIT_RTPRIO"
%)
   return sprintf("UNKNOWN VALUE: %d", r)
}

function _rusage_who_str(w) {
   if(w==0) return "RUSAGE_SELF"
   if(w==-1) return "RUSAGE_CHILDREN"
   if(w==-2) return "RUSAGE_BOTH"
   return sprintf("UNKNOWN VALUE: %d", w)
}

/* for accessing 16-bit values encoded in a long */
function __short:long(val:long) %{ /* pure */
	STAP_RETVALUE = (short)STAP_ARG_val;
%}

/* uid_t is unsigned, but calling functions take "-1" as a parameter */
/* so this hack is necessary to correct that mismatch. */
function __int32:long(val:long) %{ /* pure */
	STAP_RETVALUE = (int32_t)STAP_ARG_val;
%}

/* Unsigned values can get get sign-extended and become negative. */
function __ulong:long(val:long) %{ /* pure */
	STAP_RETVALUE = (unsigned long)STAP_ARG_val;
%}

# For utimensat and futimesat, the directory fd can have a special value
function _dfd_str(d) {
	# 0xffffff9c is a 32-bit -100, for compatability mode.
	if((d == -100) || (d == 0xffffff9c)) return "AT_FDCWD"
	return sprint(d)
}

function _adjtimex_return_str(ret) {
	if (ret == 0)
		val = "OK"
	else if (ret == 1)
		val = "INS"
	else if (ret == 2)
		val = "DEL"
	else if (ret == 3)
		val = "OOP"
	else if (ret == 4)
		val = "WAIT"
	else if (ret == 5)
		val = "BAD"

	if (val != "")
		return sprintf("%d (TIME_%s)", ret, val)
	else
		return return_str(1, ret)
}

%{
/*
* Simple lookup functions for mapping values to names
* using embedded C. Use these functions to create safe,
* consistent lookups.
*/

/* Convenient macro to add defines to an array */
#define V(a) {a,#a}

typedef struct {
	long val;
	char *name;
} _stp_val_array;

static void _stp_lookup_str(const _stp_val_array * const array, long val, char *ptr, int len)
{
	int i = 0, slen;
	while (array[i].name) {
		if (array[i].val == val) {
			strlcat (ptr, array[i].name, len);
			return;
		}
		i++;
	}
	slen = strlen(ptr);
	_stp_snprintf(ptr + slen, len - slen, "0x%lx", val);
}
static void _stp_lookup_or_str(const _stp_val_array * const array, long val, char *ptr, int len)
{
	int i = 0, flag = 0, slen;

	if (val == 0) {
		_stp_lookup_str(array, val, ptr, len);
		return;
	}

	while (array[i].name) {
		if (array[i].val & val) {
			if (flag)
				strlcat(ptr, "|", len);
			strlcat(ptr, array[i].name, len);
			val &= (~array[i].val);
			flag = 1;
		}
		i++;
	}
	if (val) {
		if (flag)
			strlcat(ptr, "|", len);
		slen = strlen(ptr);
		_stp_snprintf(ptr + slen, len - slen, "0x%lx", val);
	}
}
%}

%{
static const _stp_val_array const _stp_signal_list[] = {
	{0, "SIG_0"},
	V(SIGHUP),
	V(SIGINT),
	V(SIGQUIT),
	V(SIGILL),
	V(SIGTRAP),
	V(SIGABRT),
	V(SIGBUS),
	V(SIGFPE),
	V(SIGKILL),
	V(SIGUSR1),
	V(SIGSEGV),
	V(SIGPIPE),
	V(SIGUSR2),
	V(SIGALRM),
	V(SIGTERM),
	V(SIGCHLD),
	V(SIGCONT),
	V(SIGSTOP),
	V(SIGTSTP),
	V(SIGTTIN),
	V(SIGTTOU),
	V(SIGURG),
	V(SIGPROF),
	V(SIGWINCH),
	V(SIGVTALRM),
	{SIGIO,"SIGIO/SIGPOLL"},
	V(SIGPWR),
	{SIGTRAP|0x80,"TRACESYSGOOD"},
	{0, NULL}
};

static void _stp_sigset_str(sigset_t *mask, char *ptr, int len)
{
	const _stp_val_array * const array = _stp_signal_list;
	int i = 0, flag = 0;
	while (array[i].name) {
		if (array[i].val && sigismember(mask, array[i].val)) {
			if (flag)
				strlcat(ptr, "|", len);
			strlcat(ptr, array[i].name, len);
			flag = 1;
		}
		i++;
	}
	if (flag == 0)
		strlcat(ptr, "EMPTY", len);
}
%}

function _signal_name:string(sig:long)
%{ /* pure */
	_stp_lookup_str(_stp_signal_list, STAP_ARG_sig, STAP_RETVALUE, MAXSTRINGLEN);
%}

%{
static const _stp_val_array const _stp_semctl_list[] = {
	V(IPC_INFO),
	V(SEM_INFO),
	V(SEM_STAT),
	V(GETALL),
	V(GETVAL),
	V(GETPID),
	V(GETNCNT),
	V(GETZCNT),
	V(IPC_STAT),
	V(SETVAL),
	V(SETALL),
	V(IPC_RMID),
	V(IPC_SET),
	{0, NULL}
};
%}

function _semctl_cmd:string(cmd:long)
%{ /* pure */
	_stp_lookup_str(_stp_semctl_list, STAP_ARG_cmd, STAP_RETVALUE, MAXSTRINGLEN);
%}

function _stp_sigset_u:string(setptr:long)
%{ /* pure */
	char *ptr = (char *)(unsigned long)STAP_ARG_setptr;
	sigset_t set;

	if (ptr == NULL)
		strlcpy (STAP_RETVALUE, "NULL", MAXSTRINGLEN);
	else {
		if(_stp_copy_from_user((char*)&set,ptr,sizeof(sigset_t)) == 0)
			_stp_sigset_str(&set, STAP_RETVALUE, MAXSTRINGLEN);			
		else
			strlcpy (STAP_RETVALUE, "UNKNOWN", MAXSTRINGLEN);
	}
%}

function _stp_compat_sigset_u:string(setptr:long)
%{ /* pure */
#ifdef CONFIG_COMPAT
	char *ptr = (char *)(unsigned long)STAP_ARG_setptr;

	if (ptr == NULL)
		strlcpy (STAP_RETVALUE, "NULL", MAXSTRINGLEN);
	else {
		compat_sigset_t set;

		if (_stp_copy_from_user((char*)&set, ptr,
					sizeof(compat_sigset_t)) == 0) {
			sigset_t new_set;
			sigset_from_compat(&new_set, &set);
			_stp_sigset_str(&new_set, STAP_RETVALUE, MAXSTRINGLEN);
		}
		else
			strlcpy (STAP_RETVALUE, "UNKNOWN", MAXSTRINGLEN);
	}
#endif
%}

%{
static const _stp_val_array const _stp_fork_list[] = {
	V(CLONE_VM),
	V(CLONE_FS),
	V(CLONE_FILES),
	V(CLONE_SIGHAND),
	V(CLONE_PTRACE),
	V(CLONE_VFORK),
	V(CLONE_PARENT),
	V(CLONE_THREAD),
	V(CLONE_NEWNS),
	V(CLONE_SYSVSEM),
	V(CLONE_SETTLS),
	V(CLONE_PARENT_SETTID),
	V(CLONE_CHILD_CLEARTID),
	V(CLONE_DETACHED),
	V(CLONE_UNTRACED),
	V(CLONE_CHILD_SETTID),
#ifdef CLONE_STOPPED
	V(CLONE_STOPPED),
#endif
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,19)
	V(CLONE_NEWUTS),
	V(CLONE_NEWIPC),
#endif
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,23)
	V(CLONE_NEWUSER),
#endif
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,24)
	V(CLONE_NEWPID),
	V(CLONE_NEWNET),
#endif
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,25)
	V(CLONE_IO),
#endif
	{0, NULL}
};
%}

function __fork_flags:string(flags:long)
%{ /* pure */
	_stp_lookup_or_str(_stp_fork_list, STAP_ARG_flags & ~0xff, STAP_RETVALUE, MAXSTRINGLEN);
	if ( STAP_ARG_flags & 0xff ) {
		/* flags contains the termination signal */
		if (*STAP_RETVALUE)
			strlcat(STAP_RETVALUE, "|", MAXSTRINGLEN);
		_stp_lookup_str(_stp_signal_list, STAP_ARG_flags & 0xff, STAP_RETVALUE, MAXSTRINGLEN);
	}
%}

%{
static const _stp_val_array const _stp_atflag_list[] = {
#ifdef AT_SYMLINK_NOFOLLOW
	V(AT_SYMLINK_NOFOLLOW),
#endif
#ifdef AT_REMOVEDIR
	V(AT_REMOVEDIR),
#endif
#ifdef AT_SYMLINK_FOLLOW
	V(AT_SYMLINK_FOLLOW),
#endif
	{0, NULL}
};
%}

function _at_flag_str:string(f:long)
%{ /* pure */
	_stp_lookup_str(_stp_atflag_list, STAP_ARG_f, STAP_RETVALUE, MAXSTRINGLEN);
%}

%{
#include <linux/eventpoll.h>
%}
function _epoll_create1_flag_str:string(f:long)
%{ /* pure */
#ifdef EPOLL_CLOEXEC
	if (STAP_ARG_f == EPOLL_CLOEXEC)
		strlcpy (STAP_RETVALUE, "EPOLL_CLOEXEC", MAXSTRINGLEN);
#endif
%}

%{
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,22)
#include <linux/eventfd.h>
#endif
%}
function _eventfd2_flag_str:string(f:long)
%{ /* pure */
  long flags = STAP_ARG_f;
  char *str = STAP_RETVALUE;
  int len;

  str[0] = '\0';
#if defined(EFD_CLOEXEC) && defined(EFD_NONBLOCK)
  if (flags & EFD_NONBLOCK)
    strlcat(str, "EFD_NONBLOCK|", MAXSTRINGLEN);
  if (flags & EFD_CLOEXEC)
    strlcat(str, "EFD_CLOEXEC|", MAXSTRINGLEN);
#endif

  len = strlen(str);
  if (len)
    str[strlen(str)-1] = '\0';
%}

%{
#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,22)
#include <linux/signalfd.h>
#endif
%}
function _signalfd4_flags_str:string(f:long)
%{ /* pure */
  long flags = STAP_ARG_f;
  char *str = STAP_RETVALUE;
  int len;

  str[0] = '\0';
#if defined(SFD_CLOEXEC) && defined(SFD_NONBLOCK)
  if (flags & SFD_NONBLOCK)
    strlcat(str, "SFD_NONBLOCK|", MAXSTRINGLEN);
  if (flags & SFD_CLOEXEC)
    strlcat(str, "SFD_CLOEXEC|", MAXSTRINGLEN);
#endif

  len = strlen(str);
  if (len)
    str[strlen(str)-1] = '\0';
%}

%{
#if (defined(CONFIG_INOTIFY) || defined(CONFIG_INOTIFY_USER))
#include <linux/inotify.h>
#endif
%}
function _inotify_init1_flag_str:string(f:long)
%{ /* pure */
  long flags = STAP_ARG_f;
  char *str = STAP_RETVALUE;
  int len;

  str[0] = '\0';
#if defined(IN_CLOEXEC) && defined(IN_NONBLOCK)
  if (flags & IN_NONBLOCK)
    strlcat(str, "IN_NONBLOCK|", MAXSTRINGLEN);
  if (flags & IN_CLOEXEC)
    strlcat(str, "IN_CLOEXEC|", MAXSTRINGLEN);
#endif

  len = strlen(str);
  if (len)
    str[strlen(str)-1] = '\0';
%}

function _dup3_flag_str:string(f:long)
%{ /* pure */
#ifdef O_CLOEXEC
	if (STAP_ARG_f == O_CLOEXEC)
		strlcpy (STAP_RETVALUE, "O_CLOEXEC", MAXSTRINGLEN);
	else
#endif
		strlcpy (STAP_RETVALUE, "UNKNOWN", MAXSTRINGLEN);
%}

%{
#include <linux/shm.h>
static const _stp_val_array const _stp_shmat_list[] = {
	V(SHM_RDONLY),
	V(SHM_RND),
	V(SHM_REMAP),
	V(SHM_EXEC),
	{0, NULL}
};
%}

function _shmat_flags_str:string(f:long)
%{ /* pure */
	_stp_lookup_or_str(_stp_shmat_list, STAP_ARG_f, STAP_RETVALUE, MAXSTRINGLEN);
%}


%{
#include <linux/mman.h>
static const _stp_val_array const _stp_mprotect_list[] = {
	{0, "PROT_NONE"},
	V(PROT_READ),
	V(PROT_WRITE),
	V(PROT_EXEC),
	V(PROT_SEM),
	{0, NULL}
};
%}

function _mprotect_prot_str:string(prot:long) 
%{ /* pure */
	_stp_lookup_or_str(_stp_mprotect_list, STAP_ARG_prot, STAP_RETVALUE, MAXSTRINGLEN);
%}

%{
#include <linux/mman.h>
static const _stp_val_array const _stp_mmap_list[] = {
	V(MAP_SHARED),
	V(MAP_PRIVATE),
	V(MAP_FIXED),
	V(MAP_ANONYMOUS),
	V(MAP_GROWSDOWN),
	V(MAP_DENYWRITE),
	V(MAP_EXECUTABLE),
	V(MAP_LOCKED),
	V(MAP_NORESERVE),
	V(MAP_POPULATE),
	V(MAP_NONBLOCK),
	{0, NULL}
};
%}

function _mmap_flags:string(flags:long) 
%{ /* pure */
	_stp_lookup_or_str(_stp_mmap_list, STAP_ARG_flags, STAP_RETVALUE, MAXSTRINGLEN);
%}

# old mmap functions passed in a struct like this.
#
function get_mmap_args:string (args:long)
%{ /* pure */
#if defined (__x86_64__) || defined (__ia64__)
	struct mmap_arg_struct {
		unsigned int addr;
		unsigned int len;
		unsigned int prot;
		unsigned int flags;
		int fd;
		unsigned int offset;
	} a;
#else
	struct mmap_arg_struct {
		unsigned long addr;
		unsigned long len;
		unsigned long prot;
		unsigned long flags;
		long fd;
		unsigned long offset;
	} a;
#endif

	if(_stp_copy_from_user((char *)&a,(char *)(unsigned long)STAP_ARG_args, sizeof(a))== 0) {
		int len;
		_stp_snprintf(STAP_RETVALUE, MAXSTRINGLEN, "0x%lx, %ld, ", (long)a.addr, (long)a.len);
		_stp_lookup_or_str(_stp_mprotect_list, a.prot, STAP_RETVALUE, MAXSTRINGLEN);
		strlcat (STAP_RETVALUE, ", ", MAXSTRINGLEN);
		_stp_lookup_or_str(_stp_mmap_list, a.flags, STAP_RETVALUE, MAXSTRINGLEN);
		strlcat (STAP_RETVALUE, ", ", MAXSTRINGLEN);
		len = strlen(STAP_RETVALUE);
		_stp_snprintf(STAP_RETVALUE + len, MAXSTRINGLEN - len, "%ld, %ld", (long)a.fd, (long)a.offset);
	} else
		strlcpy (STAP_RETVALUE, "UNKNOWN", MAXSTRINGLEN);
%}


function _sighandler_str:string(uaddr:long)
%{ /* pure */
	static const _stp_val_array const _stp_sa_handler_list[] = {
		{0, "SIG_DFL"},
		{1, "SIG_IGN"},
		{0, NULL}
	};
	_stp_lookup_str(_stp_sa_handler_list, (long)STAP_ARG_uaddr, STAP_RETVALUE, MAXSTRINGLEN);
%}

%{
static void _stp_sigaction_str(struct sigaction *act, char *ptr, int len)
{
  static const _stp_val_array const _stp_sa_handler_list[] = {
    {0, "SIG_DFL"},
    {1, "SIG_IGN"},
    {0, NULL}
  };

  static const _stp_val_array const _stp_sa_flags_list[] = {
    V(SA_NOCLDSTOP),
    V(SA_NOCLDWAIT),
    V(SA_RESETHAND),
    V(SA_ONSTACK),
    V(SA_RESTART),
    V(SA_NODEFER),
    V(SA_SIGINFO),
    V(SA_RESTORER),
    {0, NULL}
  };
  
  int slen;
  _stp_lookup_str(_stp_sa_handler_list, (long)act->sa_handler,
		  ptr, len);
  if (act->sa_handler != SIG_IGN && act->sa_handler != SIG_DFL)
    {
      strlcat (ptr, ", ", len);
      _stp_lookup_or_str(_stp_sa_flags_list, act->sa_flags, ptr, len);
      strlcat (ptr, ", ", len);
#if !defined (__ia64__)
      slen = strlen(ptr);
      _stp_snprintf(ptr + slen, len - slen,
		    "0x%lx, [", (long)act->sa_restorer);
#else
      strlcat (ptr, "[", len);
#endif
      _stp_sigset_str(&act->sa_mask, ptr, len);
      strlcat (ptr, "]", len);
    }
}
%}

function _struct_sigaction_u:string(uaddr:long)
%{ /* pure */
  struct sigaction act;
  char *ptr = (char *)(unsigned long)STAP_ARG_uaddr;
  
  if (ptr == NULL)
    strlcpy (STAP_RETVALUE, "NULL", MAXSTRINGLEN);
  else
    {
      if(_stp_copy_from_user((char*)&act, ptr,
			     sizeof(struct sigaction)) == 0)
	_stp_sigaction_str(&act, STAP_RETVALUE, MAXSTRINGLEN);
      else
	strlcpy (STAP_RETVALUE, "UNKNOWN", MAXSTRINGLEN);
    }
%}

function _struct_sigaction32_u:string(uaddr:long)
%{ /* pure */
#ifdef CONFIG_COMPAT
#include <linux/compat.h>
  
#ifdef AUTOCONF_COMPAT_SIGACTION
  struct compat_sigaction act32;
#else
  // There seems to be no public cross arch header that defines this.
  // For x86, you can find it in asm/ia32.h.  For s390x, it is defined
  // in a private header.
  struct sigaction32 {
    compat_uptr_t  sa_handler;
    unsigned int sa_flags;
    unsigned int sa_restorer;       /* Another 32 bit pointer */
    compat_sigset_t sa_mask;        /* A 32 bit mask */
  };
  
  struct sigaction32 act32;
#endif

  char *ptr = (char *)(unsigned long)STAP_ARG_uaddr;
  
  if (ptr == NULL)
    strlcpy (STAP_RETVALUE, "NULL", MAXSTRINGLEN);
  else
    {
      if(_stp_copy_from_user((char*)&act32, ptr,
			     sizeof(act32)) == 0)
	{
	  struct sigaction act;

	  act.sa_handler = (void *)compat_ptr(act32.sa_handler);
	  act.sa_flags = (unsigned long)act32.sa_flags;
	  act.sa_restorer = (void *)compat_ptr(act32.sa_restorer);

	  /* swap words around to get right endian order. */
	  switch (_NSIG_WORDS)
	    {
	    case 4: act.sa_mask.sig[3] = act32.sa_mask.sig[6]
		| (((long)act32.sa_mask.sig[7]) << 32);
	    case 3: act.sa_mask.sig[2] = act32.sa_mask.sig[4]
		| (((long)act32.sa_mask.sig[5]) << 32);
	    case 2: act.sa_mask.sig[1] = act32.sa_mask.sig[2]
		| (((long)act32.sa_mask.sig[3]) << 32);
	    case 1: act.sa_mask.sig[0] = act32.sa_mask.sig[0]
		| (((long)act32.sa_mask.sig[1]) << 32);
	    }

	  _stp_sigaction_str(&act, STAP_RETVALUE, MAXSTRINGLEN);	  
	}
      else
	strlcpy (STAP_RETVALUE, "UNKNOWN", MAXSTRINGLEN);
    }
#endif
%}

function _struct_old_sigaction32_u:string(uaddr:long)
%{ /* pure */
#ifdef CONFIG_COMPAT
#include <linux/compat.h>

#ifdef CONFIG_COMPAT_OLD_SIGACTION
  struct compat_old_sigaction act32;
#else
  // There seems to be no public cross arch header that defines this.
  // For x86, you can find it in asm/ia32.h.  For s390x, it is defined
  // in a private header.
  struct old_sigaction32 {
    compat_uptr_t  sa_handler;
    compat_old_sigset_t sa_mask;    /* A 32 bit mask */
    unsigned int sa_flags;
    unsigned int sa_restorer;       /* Another 32 bit pointer */
  };

  struct old_sigaction32 act32;
#endif
  char *ptr = (char *)(unsigned long)STAP_ARG_uaddr;
  
  if (ptr == NULL)
    strlcpy (STAP_RETVALUE, "NULL", MAXSTRINGLEN);
  else
    {
      if(_stp_copy_from_user((char*)&act32, ptr, sizeof(act32)) == 0)
	{
	  struct sigaction act;

	  act.sa_handler = (void *)compat_ptr(act32.sa_handler);
	  act.sa_restorer = (void *)compat_ptr(act32.sa_restorer);
	  act.sa_flags = (unsigned long)act32.sa_flags;
	  siginitset(&act.sa_mask, act32.sa_mask);
	  _stp_sigaction_str(&act, STAP_RETVALUE, MAXSTRINGLEN);	  
	}
      else
	strlcpy (STAP_RETVALUE, "UNKNOWN", MAXSTRINGLEN);
    }
#endif
%}

/*
 * Function irqflags_str :
 * 	Returns the symbolic string representation of the IRQ flags.
 *
 */

%{
#include <linux/interrupt.h>
#ifndef IRQF_ONESHOT
#define IRQF_ONESHOT 0x00002000
#endif
static const _stp_val_array const _stp_irq_list[] = {
#ifdef IRQF_DISABLED
	V(IRQF_DISABLED),
#endif
#ifdef IRQF_SAMPLE_RANDOM
	V(IRQF_SAMPLE_RANDOM),
#endif
#ifdef IRQF_SHARED
	V(IRQF_SHARED),
#endif
#ifdef IRQF_PROBE_SHARED
	V(IRQF_PROBE_SHARED),
#endif
#ifdef IRQF_TIMER
	V(IRQF_TIMER),
#endif
#ifdef IRQF_PERCPU
	V(IRQF_PERCPU),
#endif
#ifdef IRQF_NOBALANCING
	V(IRQF_NOBALANCING),
#endif
#ifdef IRQF_IRQPOLL
	V(IRQF_IRQPOLL),
#endif
	V(IRQF_ONESHOT),
	{0, NULL}
};
%}

function irqflags_str:string(f:long)
%{ /* pure */
	_stp_lookup_or_str(_stp_irq_list, STAP_ARG_f, STAP_RETVALUE, MAXSTRINGLEN);
%}

/* PTRACE_SETOPTIONS parser of the DATA parameter. */
function _ptrace_options_str(f)
{
	retval=""
	if (f & %{ PTRACE_O_TRACESYSGOOD %}) {
		f&=%{ ~PTRACE_O_TRACESYSGOOD %}
		retval=retval."|PTRACE_O_TRACESYSGOOD"
	}
	if (f & %{ PTRACE_O_TRACEFORK %}) {
		f&=%{ ~PTRACE_O_TRACEFORK %}
		retval=retval."|PTRACE_O_TRACEFORK"
	}
	if (f & %{ PTRACE_O_TRACEVFORK %}) {
		f&=%{ ~PTRACE_O_TRACEVFORK %}
		retval=retval."|PTRACE_O_TRACEVFORK"
	}
	if (f & %{ PTRACE_O_TRACECLONE %}) {
		f&=%{ ~PTRACE_O_TRACECLONE %}
		retval=retval."|PTRACE_O_TRACECLONE"
	}
	if (f & %{ PTRACE_O_TRACEEXEC %}) {
		f&=%{ ~PTRACE_O_TRACEEXEC %}
		retval=retval."|PTRACE_O_TRACEEXEC"
	}
	if (f & %{ PTRACE_O_TRACEVFORKDONE %}) {
		f&=%{ ~PTRACE_O_TRACEVFORKDONE %}
		retval=retval."|PTRACE_O_TRACEVFORKDONE"
	}
	if (f & %{ PTRACE_O_TRACEEXIT %}) {
		f&=%{ ~PTRACE_O_TRACEEXIT %}
		retval=retval."|PTRACE_O_TRACEEXIT"
	}
	if (f != 0)
		retval=retval.sprintf("|0x%x",f)
	else if (retval == "")
		return "0"
	return substr(retval,1,strlen(retval)-1)
}

/* ptrace syscall provisioning of argstr. */
%{
#ifndef PTRACE_GETREGSET
# define PTRACE_GETREGSET 0x4204
#endif
#ifndef PTRACE_SETREGSET
# define PTRACE_SETREGSET 0x4205
#endif
%}
function _ptrace_argstr(request, pid, addr, data)
{
	retval=_arch_ptrace_argstr(request, pid, addr, data)
	if (retval != "")
		return retval
	if (request == %{ PTRACE_TRACEME %})
		return "PTRACE_TRACEME"
	if (request == %{ PTRACE_PEEKTEXT %})
		return sprintf ("PTRACE_PEEKTEXT, %d, addr=%p", pid, addr)
	if (request == %{ PTRACE_PEEKDATA %})
		return sprintf ("PTRACE_PEEKDATA, %d, addr=%p", pid, addr)
	if (request == %{ PTRACE_PEEKUSR %})
		return sprintf ("PTRACE_PEEKUSR, %d, addr=%p", pid, addr)
	if (request == %{ PTRACE_POKETEXT %})
		return sprintf ("PTRACE_POKETEXT, %d, addr=%p, data=%p", pid, addr, data)
	if (request == %{ PTRACE_POKEDATA %})
		return sprintf ("PTRACE_POKEDATA, %d, addr=%p, data=%p", pid, addr, data)
	if (request == %{ PTRACE_POKEUSR %})
		return sprintf ("PTRACE_POKEUSR, %d, addr=%p, data=%p", pid, addr, data)
	if (request == %{ PTRACE_CONT %})
		return sprintf ("PTRACE_CONT, %d, %s", pid, _signal_name (data))
	if (request == %{ PTRACE_KILL %})
		return sprintf ("PTRACE_KILL, %d", pid)
	if (request == %{ PTRACE_SINGLESTEP %})
		return sprintf ("PTRACE_SINGLESTEP, %d, %s", pid, _signal_name (data))
	if (request == %{ PTRACE_ATTACH %})
		return sprintf ("PTRACE_ATTACH, %d", pid)
	if (request == %{ PTRACE_DETACH %})
		return sprintf ("PTRACE_DETACH, %d, %s", pid, _signal_name (data))
	if (request == %{ PTRACE_SYSCALL %})
		return sprintf ("PTRACE_SYSCALL, %d, %s", pid, _signal_name (data))
	if (request == %{ PTRACE_SETOPTIONS %})
		return sprintf ("PTRACE_SETOPTIONS, %d, %s", pid, _ptrace_options_str (data))
	if (request == %{ PTRACE_GETEVENTMSG %})
		return sprintf ("PTRACE_GETEVENTMSG, %d, data=%p", pid, data)
	if (request == %{ PTRACE_GETSIGINFO %})
		// TODO: Retrieve *data in .return
		return sprintf ("PTRACE_GETSIGINFO, %d, data=%p", pid, data)
	if (request == %{ PTRACE_SETSIGINFO %})
		// TODO: Retrieve *data here
		return sprintf ("PTRACE_SETSIGINFO, %d, data=%p", pid, data)
	if (request == %{ PTRACE_GETREGSET %})
		// TODO
		return sprintf ("PTRACE_GETREGSET, %d, addr=%p, data=%p", pid, addr, data)
	if (request == %{ PTRACE_SETREGSET %})
		// TODO
		return sprintf ("PTRACE_SETREGSET, %d, addr=%p, data=%p", pid, addr, data)
	return sprintf("?=%d, %d, %p, %p", request, pid, addr, data)
}

/* ptrace.return syscall decoder for PTRACE_GETEVENTMSG. */
function _ptrace_return_geteventmsg_data(request,data)
{
	if (request == %{ PTRACE_GETEVENTMSG %})
		return user_long(data)
}

/* do_fork helper function to determine fork type. */
function __is_user_regs:long (regs:long)
%{
	/* pure */
	struct pt_regs * regs = (void *)((unsigned long)STAP_ARG_regs);
/* copied from asm/ptrace.h */
#if defined(__i386__)
#ifdef STAPCONF_X86_UNIREGS
	int cs = kread(&regs->cs);
#else
	int cs = kread(&regs->xcs);
#endif
	STAP_RETVALUE = (!!((cs & 3)));
#elif defined(__x86_64__)
	unsigned long cs = kread(&regs->cs);
	STAP_RETVALUE = (!!((cs & 3)));
#elif defined(__ia64__)
	unsigned long psr = kread(&regs->cr_ipsr);
	STAP_RETVALUE = (((struct ia64_psr *) &psr)->cpl != 0);
#elif defined(__powerpc64__)
	unsigned long msr = kread(&regs->msr);
	STAP_RETVALUE = ((msr >> MSR_PR_LG) & 0x1);
#elif defined(__powerpc__)
	unsigned long msr = kread(&regs->msr);
	STAP_RETVALUE = ((msr >> MSR_PR) != 0);
#elif defined(__arm__)
	long cpsr = kread(&regs->ARM_cpsr);
	STAP_RETVALUE = ((cpsr & 0xf) == 0);
#elif defined(__s390__) || defined(__s390x__)
	unsigned long mask = kread(&regs->psw.mask);
	STAP_RETVALUE = ((mask & PSW_MASK_PSTATE) != 0);
#else
#error "Unimplemented architecture"
#endif
CATCH_DEREF_FAULT();
%}
