From c4557941eef03e1eb289164253f34e36da25534a Mon Sep 17 00:00:00 2001 From: Lin Runze Date: Sun, 14 Apr 2024 16:33:32 +0800 Subject: [PATCH] loongarch: add loongarch64 support for proot --- src/arch.h | 22 ++- src/loader/assembly-loongarch64.h | 98 +++++++++++ src/loader/loader.c | 2 + src/ptrace/ptrace.c | 4 + src/syscall/sysnums-loongarch64.h | 268 ++++++++++++++++++++++++++++++ src/tracee/reg.c | 29 +++- test/ptrace-2.c | 21 +++ 7 files changed, 441 insertions(+), 3 deletions(-) create mode 100644 src/loader/assembly-loongarch64.h create mode 100644 src/syscall/sysnums-loongarch64.h diff --git a/src/arch.h b/src/arch.h index 9218f690..a06d5566 100644 --- a/src/arch.h +++ b/src/arch.h @@ -38,7 +38,7 @@ typedef unsigned char byte_t; #define OFFSETOF_STATX_UID 20 #define OFFSETOF_STATX_GID 24 -#if !defined(ARCH_X86_64) && !defined(ARCH_ARM_EABI) && !defined(ARCH_X86) && !defined(ARCH_SH4) +#if !defined(ARCH_X86_64) && !defined(ARCH_ARM_EABI) && !defined(ARCH_X86) && !defined(ARCH_SH4) && !defined(ARCH_LOONGARCH64) # if defined(__x86_64__) # define ARCH_X86_64 1 # elif defined(__ARM_EABI__) @@ -51,6 +51,8 @@ typedef unsigned char byte_t; # define ARCH_X86 1 # elif defined(__SH4__) # define ARCH_SH4 1 +# elif defined(__loongarch_lp64) +# define ARCH_LOONGARCH64 1 # else # error "Unsupported architecture" # endif @@ -170,6 +172,24 @@ typedef unsigned char byte_t; #define OFFSETOF_STAT_GID_32 0 #define NO_MISALIGNED_ACCESS 1 +#elif defined(ARCH_LOONGARCH64) + + #define SYSNUMS_HEADER1 "syscall/sysnums-loongarch64.h" + #define SYSNUMS_ABI1 sysnums_loongarch64 + + #define SYSTRAP_SIZE 4 + + #define SECCOMP_ARCHS { { .value = AUDIT_ARCH_LOONGARCH64, .nb_abis = 1, .abis = { ABI_DEFAULT } } } + + #define HOST_ELF_MACHINE {258, 0}; + #define RED_ZONE_SIZE 0 + #define OFFSETOF_STAT_UID_32 0 + #define OFFSETOF_STAT_GID_32 0 + + #define LOADER_ADDRESS 0x2000000000 + #define EXEC_PIC_ADDRESS 0x3000000000 + #define INTERP_PIC_ADDRESS 0x3f00000000 + #else #error "Unsupported architecture" diff --git a/src/loader/assembly-loongarch64.h b/src/loader/assembly-loongarch64.h new file mode 100644 index 00000000..179b16bd --- /dev/null +++ b/src/loader/assembly-loongarch64.h @@ -0,0 +1,98 @@ +/* -*- c-set-style: "K&R"; c-basic-offset: 8 -*- + * + * This file is part of PRoot. + * + * Copyright (C) 2015 STMicroelectronics + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 of the + * License, or (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, but + * WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA + * 02110-1301 USA. + */ + +/* According to the LoongArch ABI, all registers have undefined values at + * program startup except: + * + * - the instruction pointer (pc) + * - the stack pointer (sp) + * - the rtld_fini pointer (a0) + */ +#define BRANCH(stack_pointer, destination) do { \ + asm volatile ( \ + "# Restore initial stack pointer. \n\t" \ + "move $sp, %0 \n\t" \ + " \n\t" \ + "# Clear rtld_fini. \n\t" \ + "move $a0, $zero \n\t" \ + " \n\t" \ + "# Start the program. \n\t" \ + "jr %1 \n" \ + : /* no output */ \ + : "r" (stack_pointer), "r" (destination) \ + : "memory", "$sp", "$a0"); \ + __builtin_unreachable(); \ + } while (0) + +#define PREPARE_ARGS_1(arg1_) \ + register word_t arg1 asm("$a0") = arg1_; \ + +#define PREPARE_ARGS_3(arg1_, arg2_, arg3_) \ + PREPARE_ARGS_1(arg1_) \ + register word_t arg2 asm("$a1") = arg2_; \ + register word_t arg3 asm("$a2") = arg3_; \ + +#define PREPARE_ARGS_4(arg1_, arg2_, arg3_, arg4_) \ + PREPARE_ARGS_3(arg1_, arg2_, arg3_) \ + register word_t arg4 asm("$a3") = arg4_; \ + +#define PREPARE_ARGS_6(arg1_, arg2_, arg3_, arg4_, arg5_, arg6_) \ + PREPARE_ARGS_4(arg1_, arg2_, arg3_, arg4_) \ + register word_t arg5 asm("$a4") = arg5_; \ + register word_t arg6 asm("$a5") = arg6_; + +#define OUTPUT_CONTRAINTS_1 \ + "r" (arg1) + +#define OUTPUT_CONTRAINTS_3 \ + OUTPUT_CONTRAINTS_1, \ + "r" (arg2), "r" (arg3) + +#define OUTPUT_CONTRAINTS_4 \ + OUTPUT_CONTRAINTS_3, \ + "r" (arg4) + +#define OUTPUT_CONTRAINTS_6 \ + OUTPUT_CONTRAINTS_4, \ + "r" (arg5), "r" (arg6) + +#define SYSCALL(number_, nb_args, args...) \ + ({ \ + register word_t number asm("$a7") = number_; \ + register word_t result asm("$a0"); \ + PREPARE_ARGS_##nb_args(args) \ + asm volatile ( \ + "syscall 0 \n\t" \ + : "=r" (result) \ + : "r" (number), \ + OUTPUT_CONTRAINTS_##nb_args \ + : "memory"); \ + result; \ + }) + +#define OPENAT 56 +#define CLOSE 57 +#define MMAP 222 +#define EXECVE 221 +#define EXIT 93 +#define PRCTL 167 +#define MPROTECT 226 diff --git a/src/loader/loader.c b/src/loader/loader.c index 79e15f56..a8c51be3 100644 --- a/src/loader/loader.c +++ b/src/loader/loader.c @@ -43,6 +43,8 @@ # include "loader/assembly-x86.h" #elif defined(ARCH_ARM64) # include "loader/assembly-arm64.h" +#elif defined(ARCH_LOONGARCH64) +# include "loader/assembly-loongarch64.h" #else # error "Unsupported architecture" #endif diff --git a/src/ptrace/ptrace.c b/src/ptrace/ptrace.c index 8085b311..9ef4ff31 100644 --- a/src/ptrace/ptrace.c +++ b/src/ptrace/ptrace.c @@ -58,6 +58,10 @@ #define user_fpregs_struct user_fpsimd_struct #endif +#if defined(ARCH_LOONGARCH64) +#define user_fpregs_struct user_fp_struct +#endif + static const char *stringify_ptrace(PTRACE_REQUEST_TYPE request) { #define CASE_STR(a) case a: return #a; break; diff --git a/src/syscall/sysnums-loongarch64.h b/src/syscall/sysnums-loongarch64.h new file mode 100644 index 00000000..ebb338be --- /dev/null +++ b/src/syscall/sysnums-loongarch64.h @@ -0,0 +1,268 @@ +#include "syscall/sysnum.h" + +static const Sysnum sysnums_loongarch64[] = { + [ 0 ] = PR_io_setup, + [ 1 ] = PR_io_destroy, + [ 2 ] = PR_io_submit, + [ 3 ] = PR_io_cancel, + [ 4 ] = PR_io_getevents, + [ 5 ] = PR_setxattr, + [ 6 ] = PR_lsetxattr, + [ 7 ] = PR_fsetxattr, + [ 8 ] = PR_getxattr, + [ 9 ] = PR_lgetxattr, + [ 10 ] = PR_fgetxattr, + [ 11 ] = PR_listxattr, + [ 12 ] = PR_llistxattr, + [ 13 ] = PR_flistxattr, + [ 14 ] = PR_removexattr, + [ 15 ] = PR_lremovexattr, + [ 16 ] = PR_fremovexattr, + [ 17 ] = PR_getcwd, + [ 18 ] = PR_lookup_dcookie, + [ 19 ] = PR_eventfd2, + [ 20 ] = PR_epoll_create1, + [ 21 ] = PR_epoll_ctl, + [ 22 ] = PR_epoll_pwait, + [ 23 ] = PR_dup, + [ 24 ] = PR_dup3, + [ 25 ] = PR_fcntl, + [ 26 ] = PR_inotify_init1, + [ 27 ] = PR_inotify_add_watch, + [ 28 ] = PR_inotify_rm_watch, + [ 29 ] = PR_ioctl, + [ 30 ] = PR_ioprio_set, + [ 31 ] = PR_ioprio_get, + [ 32 ] = PR_flock, + [ 33 ] = PR_mknodat, + [ 34 ] = PR_mkdirat, + [ 35 ] = PR_unlinkat, + [ 36 ] = PR_symlinkat, + [ 37 ] = PR_linkat, + [ 38 ] = PR_renameat, + [ 39 ] = PR_umount2, + [ 40 ] = PR_mount, + [ 41 ] = PR_pivot_root, + [ 42 ] = PR_nfsservctl, + [ 43 ] = PR_statfs, + [ 44 ] = PR_fstatfs, + [ 45 ] = PR_truncate, + [ 46 ] = PR_ftruncate, + [ 47 ] = PR_fallocate, + [ 48 ] = PR_faccessat, + [ 49 ] = PR_chdir, + [ 50 ] = PR_fchdir, + [ 51 ] = PR_chroot, + [ 52 ] = PR_fchmod, + [ 53 ] = PR_fchmodat, + [ 54 ] = PR_fchownat, + [ 55 ] = PR_fchown, + [ 56 ] = PR_openat, + [ 57 ] = PR_close, + [ 58 ] = PR_vhangup, + [ 59 ] = PR_pipe2, + [ 60 ] = PR_quotactl, + [ 61 ] = PR_getdents64, + [ 62 ] = PR_lseek, + [ 63 ] = PR_read, + [ 64 ] = PR_write, + [ 65 ] = PR_readv, + [ 66 ] = PR_writev, + [ 67 ] = PR_pread64, + [ 68 ] = PR_pwrite64, + [ 69 ] = PR_preadv, + [ 70 ] = PR_pwritev, + [ 71 ] = PR_sendfile, + [ 72 ] = PR_pselect6, + [ 73 ] = PR_ppoll, + [ 74 ] = PR_signalfd4, + [ 75 ] = PR_vmsplice, + [ 76 ] = PR_splice, + [ 77 ] = PR_tee, + [ 78 ] = PR_readlinkat, + [ 79 ] = PR_fstatat64, + [ 80 ] = PR_fstat, + [ 81 ] = PR_sync, + [ 82 ] = PR_fsync, + [ 83 ] = PR_fdatasync, + [ 84 ] = PR_sync_file_range, + [ 85 ] = PR_timerfd_create, + [ 86 ] = PR_timerfd_settime, + [ 87 ] = PR_timerfd_gettime, + [ 88 ] = PR_utimensat, + [ 89 ] = PR_acct, + [ 90 ] = PR_capget, + [ 91 ] = PR_capset, + [ 92 ] = PR_personality, + [ 93 ] = PR_exit, + [ 94 ] = PR_exit_group, + [ 95 ] = PR_waitid, + [ 96 ] = PR_set_tid_address, + [ 97 ] = PR_unshare, + [ 98 ] = PR_futex, + [ 99 ] = PR_set_robust_list, + [ 100 ] = PR_get_robust_list, + [ 101 ] = PR_nanosleep, + [ 102 ] = PR_getitimer, + [ 103 ] = PR_setitimer, + [ 104 ] = PR_kexec_load, + [ 105 ] = PR_init_module, + [ 106 ] = PR_delete_module, + [ 107 ] = PR_timer_create, + [ 108 ] = PR_timer_gettime, + [ 109 ] = PR_timer_getoverrun, + [ 110 ] = PR_timer_settime, + [ 111 ] = PR_timer_delete, + [ 112 ] = PR_clock_settime, + [ 113 ] = PR_clock_gettime, + [ 114 ] = PR_clock_getres, + [ 115 ] = PR_clock_nanosleep, + [ 116 ] = PR_syslog, + [ 117 ] = PR_ptrace, + [ 118 ] = PR_sched_setparam, + [ 119 ] = PR_sched_setscheduler, + [ 120 ] = PR_sched_getscheduler, + [ 121 ] = PR_sched_getparam, + [ 122 ] = PR_sched_setaffinity, + [ 123 ] = PR_sched_getaffinity, + [ 124 ] = PR_sched_yield, + [ 125 ] = PR_sched_get_priority_max, + [ 126 ] = PR_sched_get_priority_min, + [ 127 ] = PR_sched_rr_get_interval, + [ 128 ] = PR_restart_syscall, + [ 129 ] = PR_kill, + [ 130 ] = PR_tkill, + [ 131 ] = PR_tgkill, + [ 132 ] = PR_sigaltstack, + [ 133 ] = PR_rt_sigsuspend, + [ 134 ] = PR_rt_sigaction, + [ 135 ] = PR_rt_sigprocmask, + [ 136 ] = PR_rt_sigpending, + [ 137 ] = PR_rt_sigtimedwait, + [ 138 ] = PR_rt_sigqueueinfo, + [ 139 ] = PR_rt_sigreturn, + [ 140 ] = PR_setpriority, + [ 141 ] = PR_getpriority, + [ 142 ] = PR_reboot, + [ 143 ] = PR_setregid, + [ 144 ] = PR_setgid, + [ 145 ] = PR_setreuid, + [ 146 ] = PR_setuid, + [ 147 ] = PR_setresuid, + [ 148 ] = PR_getresuid, + [ 149 ] = PR_setresgid, + [ 150 ] = PR_getresgid, + [ 151 ] = PR_setfsuid, + [ 152 ] = PR_setfsgid, + [ 153 ] = PR_times, + [ 154 ] = PR_setpgid, + [ 155 ] = PR_getpgid, + [ 156 ] = PR_getsid, + [ 157 ] = PR_setsid, + [ 158 ] = PR_getgroups, + [ 159 ] = PR_setgroups, + [ 160 ] = PR_uname, + [ 161 ] = PR_sethostname, + [ 162 ] = PR_setdomainname, + [ 163 ] = PR_getrlimit, + [ 164 ] = PR_setrlimit, + [ 165 ] = PR_getrusage, + [ 166 ] = PR_umask, + [ 167 ] = PR_prctl, + [ 168 ] = PR_getcpu, + [ 169 ] = PR_gettimeofday, + [ 170 ] = PR_settimeofday, + [ 171 ] = PR_adjtimex, + [ 172 ] = PR_getpid, + [ 173 ] = PR_getppid, + [ 174 ] = PR_getuid, + [ 175 ] = PR_geteuid, + [ 176 ] = PR_getgid, + [ 177 ] = PR_getegid, + [ 178 ] = PR_gettid, + [ 179 ] = PR_sysinfo, + [ 180 ] = PR_mq_open, + [ 181 ] = PR_mq_unlink, + [ 182 ] = PR_mq_timedsend, + [ 183 ] = PR_mq_timedreceive, + [ 184 ] = PR_mq_notify, + [ 185 ] = PR_mq_getsetattr, + [ 186 ] = PR_msgget, + [ 187 ] = PR_msgctl, + [ 188 ] = PR_msgrcv, + [ 189 ] = PR_msgsnd, + [ 190 ] = PR_semget, + [ 191 ] = PR_semctl, + [ 192 ] = PR_semtimedop, + [ 193 ] = PR_semop, + [ 194 ] = PR_shmget, + [ 195 ] = PR_shmctl, + [ 196 ] = PR_shmat, + [ 197 ] = PR_shmdt, + [ 198 ] = PR_socket, + [ 199 ] = PR_socketpair, + [ 200 ] = PR_bind, + [ 201 ] = PR_listen, + [ 202 ] = PR_accept, + [ 203 ] = PR_connect, + [ 204 ] = PR_getsockname, + [ 205 ] = PR_getpeername, + [ 206 ] = PR_sendto, + [ 207 ] = PR_recvfrom, + [ 208 ] = PR_setsockopt, + [ 209 ] = PR_getsockopt, + [ 210 ] = PR_shutdown, + [ 211 ] = PR_sendmsg, + [ 212 ] = PR_recvmsg, + [ 213 ] = PR_readahead, + [ 214 ] = PR_brk, + [ 215 ] = PR_munmap, + [ 216 ] = PR_mremap, + [ 217 ] = PR_add_key, + [ 218 ] = PR_request_key, + [ 219 ] = PR_keyctl, + [ 220 ] = PR_clone, + [ 221 ] = PR_execve, + [ 222 ] = PR_mmap, + [ 223 ] = PR_fadvise64, + [ 224 ] = PR_swapon, + [ 225 ] = PR_swapoff, + [ 226 ] = PR_mprotect, + [ 227 ] = PR_msync, + [ 228 ] = PR_mlock, + [ 229 ] = PR_munlock, + [ 230 ] = PR_mlockall, + [ 231 ] = PR_munlockall, + [ 232 ] = PR_mincore, + [ 233 ] = PR_madvise, + [ 234 ] = PR_remap_file_pages, + [ 235 ] = PR_mbind, + [ 236 ] = PR_get_mempolicy, + [ 237 ] = PR_set_mempolicy, + [ 238 ] = PR_migrate_pages, + [ 239 ] = PR_move_pages, + [ 240 ] = PR_rt_tgsigqueueinfo, + [ 241 ] = PR_perf_event_open, + [ 242 ] = PR_accept4, + [ 243 ] = PR_recvmmsg, + [ 244 ] = PR_arch_specific_syscall, + [ 260 ] = PR_wait4, + [ 261 ] = PR_prlimit64, + [ 262 ] = PR_fanotify_init, + [ 263 ] = PR_fanotify_mark, + [ 264 ] = PR_name_to_handle_at, + [ 265 ] = PR_open_by_handle_at, + [ 266 ] = PR_clock_adjtime, + [ 267 ] = PR_syncfs, + [ 268 ] = PR_setns, + [ 269 ] = PR_sendmmsg, + [ 270 ] = PR_process_vm_readv, + [ 271 ] = PR_process_vm_writev, + [ 272 ] = PR_kcmp, + [ 273 ] = PR_finit_module, + [ 274 ] = PR_sched_setattr, + [ 275 ] = PR_sched_getattr, + [ 276 ] = PR_renameat2, + [ 291 ] = PR_statx, + [ 435 ] = PR_clone3, +}; diff --git a/src/tracee/reg.c b/src/tracee/reg.c index a0c1784e..625aec46 100644 --- a/src/tracee/reg.c +++ b/src/tracee/reg.c @@ -34,7 +34,7 @@ #include "arch.h" -#if defined(ARCH_ARM64) +#if defined(ARCH_ARM64) || defined(ARCH_LOONGARCH64) #include /* NT_PRSTATUS */ #endif @@ -165,6 +165,25 @@ [RTLD_FINI] = USER_REGS_OFFSET(r4), }; +#elif defined(ARCH_LOONGARCH64) + + #undef USER_REGS_OFFSET + #define USER_REGS_OFFSET(reg_name) offsetof(struct user_regs_struct, reg_name) + + static off_t reg_offset[] = { + [SYSARG_NUM] = USER_REGS_OFFSET(regs[11]), + [SYSARG_1] = USER_REGS_OFFSET(orig_a0), + [SYSARG_2] = USER_REGS_OFFSET(regs[5]), + [SYSARG_3] = USER_REGS_OFFSET(regs[6]), + [SYSARG_4] = USER_REGS_OFFSET(regs[7]), + [SYSARG_5] = USER_REGS_OFFSET(regs[8]), + [SYSARG_6] = USER_REGS_OFFSET(regs[9]), + [SYSARG_RESULT] = USER_REGS_OFFSET(regs[4]), + [STACK_POINTER] = USER_REGS_OFFSET(regs[3]), + [INSTR_POINTER] = USER_REGS_OFFSET(csr_era), + [USERARG_1] = USER_REGS_OFFSET(regs[4]), + }; + #else #error "Unsupported architecture" @@ -246,7 +265,7 @@ int fetch_regs(Tracee *tracee) { int status; -#if defined(ARCH_ARM64) +#if defined(ARCH_ARM64) || defined(ARCH_LOONGARCH64) struct iovec regs; regs.iov_base = &tracee->_regs[CURRENT]; @@ -319,6 +338,12 @@ int push_regs(Tracee *tracee) regs.iov_len = sizeof(tracee->_regs[CURRENT]); status = ptrace(PTRACE_SETREGSET, tracee->pid, NT_PRSTATUS, ®s); +#elif defined(ARCH_LOONGARCH64) + struct iovec regs; + regs.iov_base = &tracee->_regs[CURRENT]; + regs.iov_len = sizeof(tracee->_regs[CURRENT]); + + status = ptrace(PTRACE_SETREGSET, tracee->pid, NT_PRSTATUS, ®s); #else # if defined(ARCH_ARM_EABI) /* On ARM, a special ptrace request is required to diff --git a/test/ptrace-2.c b/test/ptrace-2.c index 9d1339d4..afc45cff 100644 --- a/test/ptrace-2.c +++ b/test/ptrace-2.c @@ -50,6 +50,8 @@ # define ARCH_X86 1 # elif defined(__SH4__) # define ARCH_SH4 1 +# elif defined(__loongarch_lp64) +# define ARCH_LOONGARCH64 1 # else # error "Unsupported architecture" # endif @@ -177,6 +179,25 @@ typedef enum { [INSTR_POINTER] = USER_REGS_OFFSET(pc), }; +#elif defined(ARCH_LOONGARCH64) + + #undef USER_REGS_OFFSET + #define USER_REGS_OFFSET(reg_name) offsetof(struct user_regs_struct, reg_name) + + static off_t reg_offset[] = { + [SYSARG_NUM] = USER_REGS_OFFSET(regs[11]), + [SYSARG_1] = USER_REGS_OFFSET(orig_a0), + [SYSARG_2] = USER_REGS_OFFSET(regs[5]), + [SYSARG_3] = USER_REGS_OFFSET(regs[6]), + [SYSARG_4] = USER_REGS_OFFSET(regs[7]), + [SYSARG_5] = USER_REGS_OFFSET(regs[8]), + [SYSARG_6] = USER_REGS_OFFSET(regs[9]), + [SYSARG_RESULT] = USER_REGS_OFFSET(regs[4]), + [STACK_POINTER] = USER_REGS_OFFSET(regs[3]), + [INSTR_POINTER] = USER_REGS_OFFSET(csr_era), + [USERARG_1] = USER_REGS_OFFSET(regs[4]), + }; + #else #error "Unsupported architecture"