# x86_64-specific system calls

# arch_prctl _________________________________________________
# long sys_arch_prctl(int code, unsigned long addr)
#
# NOTE: x86_64 only.
#
probe syscall.arch_prctl = kernel.function("sys_arch_prctl")
{
	name = "arch_prctl"
	code = $code
	addr = $addr
	argstr = sprintf("%d, %p", $code, $addr)
}
probe syscall.arch_prctl.return = kernel.function("sys_arch_prctl").return
{
	name = "arch_prctl"
	retstr = return_str(1, $return)
}

# iopl _______________________________________________________
# long sys_iopl(unsigned int level, struct pt_regs *regs);
# NOTE. This function is only in i386 and x86_64 and its args vary
# between those two archs.
#
probe syscall.iopl = kernel.function("sys_iopl")
{
	name = "iopl"
	level = @choose_defined($level, $new_iopl)
	argstr = sprint(level)
}
probe syscall.iopl.return = kernel.function("sys_iopl").return
{
	name = "iopl"
	retstr = return_str(1, $return)
}

%( CONFIG_GENERIC_SIGALTSTACK == "n" || kernel_v < "3.8" %?
# sigaltstack ________________________________________________
# long sys_sigaltstack(const stack_t __user *uss, stack_t __user *uoss,
#		struct pt_regs *regs)
#
# NOTE: args vary between archs.
#
probe syscall.sigaltstack = kernel.function("sys_sigaltstack")
{
	name = "sigaltstack"
	uss_uaddr = $uss
	uoss_uaddr = $uoss
# 'regs_uaddr' should have been 'regs'.  Deprecate the old name.
%(systemtap_v <= "1.4" %?
	regs_uaddr = $regs
%)
%(systemtap_v < "2.3" %?
	regs = $regs
%)
	argstr = sprintf("%p, %p", $uss, $uoss)
}
probe syscall.sigaltstack.return = kernel.function("sys_sigaltstack").return
{
	name = "sigaltstack"
	retstr = return_str(1, $return)
}
%)

# sysctl _____________________________________________________
#
# long sys32_sysctl(struct sysctl_ia32 __user *args32)
#
probe syscall.sysctl32 = kernel.function("sys32_sysctl") ?
{
	name = "sysctl"
	argstr = sprintf("%p", $args32)
}
probe syscall.sysctl32.return = kernel.function("sys32_sysctl").return ?
{
	name = "sysctl"
	retstr = return_str(1, $return)
}

# In kernels < 2.6.33, mmap()/mmap2() was handled by arch-specific
# code.  In kernels >= 2.6.33, the arch-specific code just calls
# generic sys_mmap_pgoff().
%( kernel_v < "2.6.33" %?
# mmap
# long sys_mmap(unsigned long addr, unsigned long len,
#          unsigned long prot, unsigned long flags,
#          unsigned long fd, unsigned long off)
probe syscall.mmap = kernel.function("sys_mmap") ?
{
	name = "mmap"
	start = $addr
	len = $len
	prot = $prot
	flags = $flags
	# Although the kernel gets an unsigned long fd, on the
	# user-side it is a signed int.  Fix this.
	fd = __int32($fd)
	offset = $off
	argstr = sprintf("%p, %d, %s, %s, %d, %d", $addr, $len,
		_mprotect_prot_str($prot), _mmap_flags($flags),
		__int32($fd), $off)
}

probe syscall.mmap.return = kernel.function("sys_mmap").return ?
{
	name = "mmap"
	retstr = return_str(2, $return)
}
#
# sys32_mmap(struct mmap_arg_struct32 __user *arg)
# sys32_mmap(struct mmap_arg_struct __user *arg)
#
probe syscall.mmap32 = kernel.function("sys32_mmap")
{
	name = "mmap"
	if (@defined(@cast($arg, "mmap_arg_struct32")->addr)) {
		start = user_long(&@cast($arg, "mmap_arg_struct32")->addr)
		len = user_long(&@cast($arg, "mmap_arg_struct32")->len)
		prot = user_long(&@cast($arg, "mmap_arg_struct32")->prot)
		flags = user_long(&@cast($arg, "mmap_arg_struct32")->flags)
		fd = user_long(&@cast($arg, "mmap_arg_struct32")->fd)
		offset = user_long(&@cast($arg, "mmap_arg_struct32")->offset)
	}
	else {
		start = user_long(&@cast($arg, "mmap_arg_struct")->addr)
		len = user_long(&@cast($arg, "mmap_arg_struct")->len)
		prot = user_long(&@cast($arg, "mmap_arg_struct")->prot)
		flags = user_long(&@cast($arg, "mmap_arg_struct")->flags)
		fd = user_long(&@cast($arg, "mmap_arg_struct")->fd)
		offset = user_long(&@cast($arg, "mmap_arg_struct")->offset)
	}
	argstr = sprintf("%p, %d, %s, %s, %d, %d", start, len,
			 _mprotect_prot_str(prot), _mmap_flags(flags),
			 fd, offset)
}

probe syscall.mmap32.return = kernel.function("sys32_mmap").return
{
        name = "mmap"
        retstr = return_str(2, $return)
}

# sys32_mmap2(unsigned long addr, unsigned long len,
#	unsigned long prot, unsigned long flags,
#	unsigned long fd, unsigned long pgoff)
# The function is removed since 2.6.33
probe syscall.mmap2 = __syscall.mmap2 ?, __syscall.mmap_pgoff ?
{
	name = "mmap2"
        start = $addr
        length = $len
        prot = $prot
        flags = $flags
	# Although the kernel gets an unsigned long fd, on the
	# user-side it is a signed int.  Fix this.
        fd = __int32($fd)
	argstr = sprintf("%p, %d, %s, %s, %d, %d", $addr, $len,
		_mprotect_prot_str($prot), _mmap_flags($flags),
		__int32($fd), pgoffset)
}
probe __syscall.mmap2 = kernel.function("sys32_mmap2")
{
        pgoffset = $pgoff
}
probe __syscall.mmap_pgoff = kernel.function("sys_mmap_pgoff")
{
        pgoffset = $pgoff * %{ PAGE_SIZE %}
}

probe syscall.mmap2.return = kernel.function("sys_mmap2").return ?,
	kernel.function("sys_mmap_pgoff").return ?
{
	name = "mmap2"
	retstr = return_str(2, $return)
}
%)

# vm86_warning _____________________________________________________
#
# long sys32_vm86_warning(void)
#
probe syscall.vm86_warning = kernel.function("sys32_vm86_warning")
{
	name = "vm86_warning"
	argstr = ""
}
probe syscall.vm86_warning.return = kernel.function("sys32_vm86_warning").return
{
	name = "wm86_warning"
	retstr = return_str(1, $return)
}
# pipe _______________________________________________________
#
# long sys32_pipe(int __user *fd)
# Not available in newer kernels.
probe syscall.pipe32 = kernel.function("sys32_pipe")?
{
	name = "pipe"
	flags = 0;
	flag_str = ""
	if (@defined($fd)) {
		fildes_uaddr = $fd
		if (fildes_uaddr == 0) {
			pipe0 = 0;
			pipe1 = 0;
			argstr = "NULL"
		} else {
			pipe0 = user_int(&$fd[0]);
			pipe1 = user_int(&$fd[1]);
			argstr = sprintf("[%d, %d]", pipe0, pipe1);
		}
	} else {
		fildes_uaddr = 0;
		pipe0 = 0;
		pipe1 = 0;
		argstr = "[0, 0]";
	}
}
probe syscall.pipe32.return = kernel.function("sys32_pipe").return?
{
	name = "pipe"
	flags = 0;
	if (@defined($fd)) {
		fildes_uaddr = $fd
		if (fildes_uaddr == 0) {
			pipe0 = 0;
			pipe1 = 0;
		} else {
			pipe0 = user_int(&$fd[0]);
			pipe1 = user_int(&$fd[1]);
		}
	} else {
		fildes_uaddr = 0;
		pipe0 = 0;
		pipe1 = 0;
	}
	retstr = return_str(1, $return)
}
