# execveat ______________________________________________
# SYSCALL_DEFINE5(execveat,
#		int, fd, const char __user *, filename,
#		const char __user *const __user *, argv,
#		const char __user *const __user *, envp,
#		int, flags)
#

@define _SYSCALL_EXECVEAT_NAME
%(
	name = "execveat"
%)

@define _SYSCALL_EXECVEAT_ARGSTR
%(
	argstr = sprintf("%s, %s, %s, %s, %s", dirfd_str, filename, args,
	                 env_str, flags_str)
%)

@define _SYSCALL_EXECVEAT_REGARGS
%(
	dirfd = int_arg(1)
	dirfd_str = _dfd_str(dirfd)
%(systemtap_v <= "2.8" %?
	# All other "at" syscalls (faccessat, fchmodat, fchownat,
	# etc.) name their file descriptor argument 'dirfd', so let's
	# do the same.
        fd = dirfd
        fd_str = dirfd_str
%)
	filename = user_string_quoted(pointer_arg(2))
	args = __get_argv(pointer_arg(3), 0)
	env_str = __get_argv(pointer_arg(4), 0)
	flags = int_arg(5)
	flags_str = _at_flag_str(flags)
%)

@define _SYSCALL_COMPAT_EXECVEAT_REGARGS
%(
	dirfd = int_arg(1)
	dirfd_str = _dfd_str(dirfd)
%(systemtap_v <= "2.8" %?
	# All other "at" syscalls (faccessat, fchmodat, fchownat,
	# etc.) name their file descriptor argument 'dirfd', so let's
	# do the same.
        fd = dirfd
        fd_str = dirfd_str
%)
	filename = user_string_quoted(pointer_arg(2))
	args = __get_compat_argv(pointer_arg(3), 0)
	env_str = __get_compat_argv(pointer_arg(4), 0)
	flags = int_arg(5)
	flags_str = _at_flag_str(flags)
%)

probe syscall.execveat = dw_syscall.execveat !, nd_syscall.execveat ? {}
probe syscall.execveat.return = dw_syscall.execveat.return !,
                                nd_syscall.execveat.return ? {}

probe syscall.compat_execveat = dw_syscall.compat_execveat !,
                                nd_syscall.compat_execveat ? {}
probe syscall.compat_execveat.return = dw_syscall.compat_execveat.return !,
                                       nd_syscall.compat_execveat.return ? {}

# dw_execveat _____________________________________________________

probe dw_syscall.execveat = kernel.function("sys_execveat").call ?
{
        @_SYSCALL_EXECVEAT_NAME
        dirfd = __int32($fd)
        dirfd_str = _dfd_str(__int32($fd))
%(systemtap_v <= "2.8" %?
	# All other "at" syscalls (faccessat, fchmodat, fchownat,
	# etc.) name their file descriptor argument 'dirfd', so let's
	# do the same.
        fd = dirfd
        fd_str = dirfd_str
%)
        filename = user_string_quoted(@__pointer($filename))
        flags = __int32($flags)
	flags_str = _at_flag_str(__int32($flags))
        __argv = @choose_defined($__argv, $argv)
        args = __get_argv(__argv, 0)
	__envp = @choose_defined($__envp, $envp)
	env_str = __get_argv(__envp, 0)
        @_SYSCALL_EXECVEAT_ARGSTR
}
probe dw_syscall.execveat.return = kernel.function("sys_execveat").return ?
{
        @_SYSCALL_EXECVEAT_NAME
        @SYSC_RETVALSTR($return)
}

probe dw_syscall.compat_execveat = kernel.function("compat_sys_execveat").call ?
{
        @_SYSCALL_EXECVEAT_NAME
        dirfd = __int32($fd)
        dirfd_str = _dfd_str(__int32($fd))
%(systemtap_v <= "2.8" %?
	# All other "at" syscalls (faccessat, fchmodat, fchownat,
	# etc.) name their file descriptor argument 'dirfd', so let's
	# do the same.
        fd = dirfd
        fd_str = dirfd_str
%)
        filename = user_string_quoted(@__pointer($filename))
        flags = __int32($flags)
	flags_str = _at_flag_str(__int32($flags))
        __argv = @__pointer(@choose_defined($__argv, $argv))
        args = __get_compat_argv(__argv, 0)
	__envp = @__pointer(@choose_defined($__envp, $envp))
	env_str = __get_compat_argv(__envp, 0)
        @_SYSCALL_EXECVEAT_ARGSTR
}
probe dw_syscall.compat_execveat.return =
	kernel.function("compat_sys_execveat").return ?
{
        @_SYSCALL_EXECVEAT_NAME
        @SYSC_RETVALSTR($return)
}

# nd_execveat _____________________________________________________

probe nd_syscall.execveat = nd1_syscall.execveat!, nd2_syscall.execveat!, tp_syscall.execveat
  { }

probe nd1_syscall.execveat = kprobe.function("sys_execveat").call ?
{
	asmlinkage()
	@_SYSCALL_EXECVEAT_NAME
	@_SYSCALL_EXECVEAT_REGARGS
	@_SYSCALL_EXECVEAT_ARGSTR
}

/* kernel 4.17+ */
probe nd2_syscall.execveat = kprobe.function(@arch_syscall_prefix "sys_execveat") ?
{
	__set_syscall_pt_regs(pointer_arg(1))
	@_SYSCALL_EXECVEAT_NAME
	@_SYSCALL_EXECVEAT_REGARGS
	@_SYSCALL_EXECVEAT_ARGSTR
}

/* kernel 3.5+, but undesirable because it affects all syscalls */
probe tp_syscall.execveat = kernel.trace("sys_enter")
{
	__set_syscall_pt_regs($regs)
	@__syscall_gate(@const("__NR_execveat"))
	@_SYSCALL_EXECVEAT_NAME
	@_SYSCALL_EXECVEAT_REGARGS
	@_SYSCALL_EXECVEAT_ARGSTR
}

probe nd_syscall.execveat.return = nd1_syscall.execveat.return!, nd2_syscall.execveat.return!, tp_syscall.execveat.return
  { }
  
probe nd1_syscall.execveat.return = kprobe.function("sys_execveat").return ?
{
	@_SYSCALL_EXECVEAT_NAME
	@SYSC_RETVALSTR(returnval())
}

/* kernel 4.17+ */
probe nd2_syscall.execveat.return = kprobe.function(@arch_syscall_prefix "sys_execveat").return ?
{
	@_SYSCALL_EXECVEAT_NAME
	@SYSC_RETVALSTR(returnval())
}
 
/* kernel 3.5+, but undesirable because it affects all syscalls */
probe tp_syscall.execveat.return = kernel.trace("sys_exit")
{
	__set_syscall_pt_regs($regs)
	@__syscall_gate(@const("__NR_execveat"))
	@_SYSCALL_EXECVEAT_NAME
	@SYSC_RETVALSTR($ret)
}

probe nd_syscall.compat_execveat = nd1_syscall.compat_execveat!, nd2_syscall.compat_execveat!, tp_syscall.compat_execveat
  { }

probe nd1_syscall.compat_execveat = kprobe.function("compat_sys_execveat").call ?
{
	@_SYSCALL_EXECVEAT_NAME
	@_SYSCALL_COMPAT_EXECVEAT_REGARGS
	@_SYSCALL_EXECVEAT_ARGSTR

}

/* kernel 4.17+ */
probe nd2_syscall.compat_execveat = kprobe.function(@arch_syscall_prefix "compat_sys_execveat") ?
{
	__set_syscall_pt_regs(pointer_arg(1))
	@_SYSCALL_EXECVEAT_NAME
	@_SYSCALL_COMPAT_EXECVEAT_REGARGS
	@_SYSCALL_EXECVEAT_ARGSTR
}

/* kernel 3.5+, but undesirable because it affects all syscalls */
probe tp_syscall.compat_execveat = kernel.trace("sys_enter")
{
	__set_syscall_pt_regs($regs)
	@__compat_syscall_gate(@const("__NR_compat_execveat"))
	@_SYSCALL_EXECVEAT_NAME
	@_SYSCALL_COMPAT_EXECVEAT_REGARGS
	@_SYSCALL_EXECVEAT_ARGSTR
}

probe nd_syscall.compat_execveat.return = nd1_syscall.compat_execveat.return!, nd2_syscall.compat_execveat.return!, tp_syscall.compat_execveat.return
  { }
  
probe nd1_syscall.compat_execveat.return =
	kprobe.function("compat_sys_execveat").return ?
{
	@_SYSCALL_EXECVEAT_NAME
	@SYSC_RETVALSTR(returnval())
}

/* kernel 4.17+ */
probe nd2_syscall.compat_execveat.return = kprobe.function(@arch_syscall_prefix "compat_sys_execveat").return ?
{
	@_SYSCALL_EXECVEAT_NAME
	@SYSC_RETVALSTR(returnval())
}
 
/* kernel 3.5+, but undesirable because it affects all syscalls */
probe tp_syscall.compat_execveat.return = kernel.trace("sys_exit")
{
	__set_syscall_pt_regs($regs)
	@__compat_syscall_gate(@const("__NR_compat_execveat"))
	@_SYSCALL_EXECVEAT_NAME
	@SYSC_RETVALSTR($ret)
}
