Files
mckernel/executer/user/arch/arm64/arch_args.h
Takehiro Shiratori d4d78e9c61 Following arm64-support to development branch
This includes the following fixes:
* fix build of arch/arm64/kernel/vdso

Change-Id: I73b05034d29f7f8731ac17f9736edbba4fb2c639
2019-02-01 15:14:45 +09:00

304 lines
5.7 KiB
C

/* arch_args.h COPYRIGHT FUJITSU LIMITED 2017-2018 */
#ifndef ARCH_ARGS_H
#define ARCH_ARGS_H
#include <asm/ptrace.h>
#ifndef NT_ARM_SYSTEM_CALL
#define NT_ARM_SYSTEM_CALL 0x404 /* ARM system call number */
#endif /* !NT_ARM_SYSTEM_CALL */
typedef struct {
struct user_pt_regs regs;
unsigned long orig_x0;
unsigned long ret_value;
pid_t target_pid;
int bypass;
} syscall_args;
enum ptrace_syscall_dir {
PTRACE_SYSCALL_ENTER = 0,
PTRACE_SYSCALL_EXIT,
};
static inline int
syscall_enter(syscall_args *args)
{
if (!args) {
printf("%s: input args is NULL.\n", __func__);
return -1;
}
switch (args->regs.regs[7]) {
case PTRACE_SYSCALL_ENTER:
return 1;
case PTRACE_SYSCALL_EXIT:
return 0;
default:
printf("%s: x7 is neither SYSCALL_ENTER nor SYSCALL_EXIT.\n",
__func__);
return -1;
}
}
static inline int
get_syscall_args(int pid, syscall_args *args)
{
struct iovec iov;
long ret = -1;
if (!args) {
printf("%s: input args is NULL.\n", __func__);
return -1;
}
args->target_pid = pid;
args->bypass = 0;
memset(&iov, 0, sizeof(iov));
iov.iov_base = &args->regs;
iov.iov_len = sizeof(args->regs);
ret = ptrace(PTRACE_GETREGSET, pid, NT_PRSTATUS, &iov);
if (!ret) {
if (syscall_enter(args)) {
args->orig_x0 = args->regs.regs[0];
args->ret_value = 0;
}
else {
/* orig_x0 is saved */
args->ret_value = args->regs.regs[0];
}
}
return ret;
}
static inline int
set_syscall_args(int pid, syscall_args *args)
{
struct iovec iov;
if (!args) {
printf("%s: input args is NULL.\n", __func__);
return -1;
}
memset(&iov, 0, sizeof(iov));
iov.iov_base = &args->regs;
iov.iov_len = sizeof(args->regs);
return ptrace(PTRACE_SETREGSET, pid, NT_PRSTATUS, &iov);
}
static inline unsigned long
get_syscall_number(syscall_args *args)
{
int sysno = -1;
long ret = -1;
struct iovec iov;
if (!args) {
printf("%s: input args is NULL.\n", __func__);
return -1;
}
memset(&iov, 0, sizeof(iov));
iov.iov_base = &sysno;
iov.iov_len = sizeof(sysno);
ret = ptrace(PTRACE_GETREGSET, args->target_pid, NT_ARM_SYSTEM_CALL,
&iov);
if (ret) {
printf("%s: ptrace(PTRACE_GETREGSET) failed. (%d)",
__func__, errno);
}
return sysno;
}
static inline unsigned long
get_syscall_arg1(syscall_args *args)
{
if (!args) {
printf("%s: input args is NULL.\n", __func__);
return 0;
}
return args->orig_x0;
}
static inline unsigned long
get_syscall_arg2(syscall_args *args)
{
if (!args) {
printf("%s: input args is NULL.\n", __func__);
return 0;
}
return args->regs.regs[1];
}
static inline unsigned long
get_syscall_arg3(syscall_args *args)
{
if (!args) {
printf("%s: input args is NULL.\n", __func__);
return 0;
}
return args->regs.regs[2];
}
static inline unsigned long
get_syscall_arg4(syscall_args *args)
{
if (!args) {
printf("%s: input args is NULL.\n", __func__);
return 0;
}
return args->regs.regs[3];
}
static inline unsigned long
get_syscall_arg5(syscall_args *args)
{
if (!args) {
printf("%s: input args is NULL.\n", __func__);
return 0;
}
return args->regs.regs[4];
}
static inline unsigned long
get_syscall_arg6(syscall_args *args)
{
if (!args) {
printf("%s: input args is NULL.\n", __func__);
return 0;
}
return args->regs.regs[5];
}
static inline void
set_syscall_number(syscall_args *args, unsigned long value)
{
int sysno = (int)value;
long ret = -1;
struct iovec iov;
if (!args) {
printf("%s: input args is NULL.\n", __func__);
return;
}
memset(&iov, 0, sizeof(iov));
iov.iov_base = &sysno;
iov.iov_len = sizeof(sysno);
ret = ptrace(PTRACE_SETREGSET, args->target_pid, NT_ARM_SYSTEM_CALL,
&iov);
if (ret) {
printf("%s: ptrace(PTRACE_GETREGSET) failed. (%d)",
__func__, errno);
}
else {
if (value == (unsigned long)-1) {
args->bypass = 1;
}
}
}
static inline void
set_syscall_ret_or_arg1(syscall_args *args, unsigned long value, int ret_flag)
{
/* called by set_syscall_return() */
if (ret_flag == 1) {
/* stopped syscall-enter */
if (syscall_enter(args) == 1) {
/* syscall no bypass */
if (args->bypass != 1) {
/* no effect */
goto out;
}
}
}
/* called by set_syscall_arg1() */
else if (ret_flag == 0) {
/* stopped syscall-return */
if (syscall_enter(args) == 0) {
/* no effect */
goto out;
}
/* set original arg1 */
args->orig_x0 = value;
}
/* illegal ret_flag */
else {
/* no effect */
goto out;
}
/* set value */
args->regs.regs[0] = value;
out:
return;
}
static inline void
set_syscall_return(syscall_args *args, unsigned long value)
{
if (!args) {
printf("%s: input args is NULL.\n", __func__);
return;
}
set_syscall_ret_or_arg1(args, value, 1);
}
static inline void
set_syscall_arg1(syscall_args *args, unsigned long value)
{
if (!args) {
printf("%s: input args is NULL.\n", __func__);
return;
}
set_syscall_ret_or_arg1(args, value, 0);
}
static inline void
set_syscall_arg2(syscall_args *args, unsigned long value)
{
if (!args) {
printf("%s: input args is NULL.\n", __func__);
return;
}
args->regs.regs[1] = value;
}
static inline void
set_syscall_arg3(syscall_args *args, unsigned long value)
{
if (!args) {
printf("%s: input args is NULL.\n", __func__);
return;
}
args->regs.regs[2] = value;
}
static inline void
set_syscall_arg4(syscall_args *args, unsigned long value)
{
if (!args) {
printf("%s: input args is NULL.\n", __func__);
return;
}
args->regs.regs[3] = value;
}
static inline void
set_syscall_arg5(syscall_args *args, unsigned long value)
{
if (!args) {
printf("%s: input args is NULL.\n", __func__);
return;
}
args->regs.regs[4] = value;
}
static inline void
set_syscall_arg6(syscall_args *args, unsigned long value)
{
if (!args) {
printf("%s: input args is NULL.\n", __func__);
return;
}
args->regs.regs[5] = value;
}
#endif /* !ARCH_ARGS_H */