diff --git a/doc/changelog.rst b/doc/changelog.rst index d181d3d..c8a3955 100644 --- a/doc/changelog.rst +++ b/doc/changelog.rst @@ -3,6 +3,13 @@ Changelog ========= +python-ptrace 0.9.8 +------------------- + +* Added Arm 64bit (AArch64) support. +* Implemented PTRACE_GETREGSET and PTRACE_SETREGSET required on AArch64 and + available on Linux. + python-ptrace 0.9.7 (2020-08-10) -------------------------------- diff --git a/doc/conf.py b/doc/conf.py index 0923dc1..2bbe8c0 100644 --- a/doc/conf.py +++ b/doc/conf.py @@ -41,7 +41,7 @@ copyright = u'2014, Victor Stinner' # built documents. # # The short X.Y version. -version = release = '0.9.7' +version = release = '0.9.8' # The language for content autogenerated by Sphinx. Refer to documentation # for a list of supported languages. diff --git a/ptrace/binding/__init__.py b/ptrace/binding/__init__.py index 497c5af..eb0374c 100644 --- a/ptrace/binding/__init__.py +++ b/ptrace/binding/__init__.py @@ -1,7 +1,7 @@ from ptrace.binding.func import ( # noqa HAS_PTRACE_SINGLESTEP, HAS_PTRACE_EVENTS, HAS_PTRACE_IO, HAS_PTRACE_SIGINFO, HAS_PTRACE_GETREGS, - REGISTER_NAMES, + HAS_PTRACE_GETREGSET, REGISTER_NAMES, ptrace_attach, ptrace_traceme, ptrace_detach, ptrace_kill, ptrace_cont, ptrace_syscall, @@ -24,5 +24,5 @@ if HAS_PTRACE_IO: ptrace_io_desc, PIOD_READ_D, PIOD_WRITE_D, PIOD_READ_I, PIOD_WRITE_I) -if HAS_PTRACE_GETREGS: +if HAS_PTRACE_GETREGS or HAS_PTRACE_GETREGSET: from ptrace.binding.func import ptrace_getregs # noqa diff --git a/ptrace/binding/cpu.py b/ptrace/binding/cpu.py index 19fde86..d4d8053 100644 --- a/ptrace/binding/cpu.py +++ b/ptrace/binding/cpu.py @@ -1,5 +1,5 @@ from ptrace.cpu_info import ( - CPU_POWERPC, CPU_INTEL, CPU_X86_64, CPU_I386, CPU_ARM) + CPU_POWERPC, CPU_INTEL, CPU_X86_64, CPU_I386, CPU_ARM32, CPU_AARCH64) CPU_INSTR_POINTER = None CPU_STACK_POINTER = None @@ -10,10 +10,14 @@ if CPU_POWERPC: CPU_INSTR_POINTER = "nip" # FIXME: Is it the right register? CPU_STACK_POINTER = 'gpr1' -elif CPU_ARM: +elif CPU_ARM32: CPU_INSTR_POINTER = 'r15' CPU_STACK_POINTER = 'r14' CPU_FRAME_POINTER = 'r11' +elif CPU_AARCH64: + CPU_INSTR_POINTER = 'pc' + CPU_STACK_POINTER = 'sp' + CPU_FRAME_POINTER = 'r29' elif CPU_X86_64: CPU_INSTR_POINTER = "rip" CPU_STACK_POINTER = "rsp" diff --git a/ptrace/binding/func.py b/ptrace/binding/func.py index 612bc75..bc4bf4d 100644 --- a/ptrace/binding/func.py +++ b/ptrace/binding/func.py @@ -1,9 +1,9 @@ from os import strerror -from ctypes import addressof, c_int, get_errno, set_errno +from ctypes import addressof, c_int, get_errno, set_errno, sizeof from ptrace import PtraceError from ptrace.ctypes_tools import formatAddress from ptrace.os_tools import RUNNING_LINUX, RUNNING_BSD, RUNNING_OPENBSD -from ptrace.cpu_info import CPU_64BITS, CPU_WORD_SIZE, CPU_POWERPC +from ptrace.cpu_info import CPU_64BITS, CPU_WORD_SIZE, CPU_POWERPC, CPU_AARCH64 if RUNNING_OPENBSD: from ptrace.binding.openbsd_struct import ( @@ -17,7 +17,7 @@ elif RUNNING_BSD: elif RUNNING_LINUX: from ptrace.binding.linux_struct import ( user_regs_struct as ptrace_registers_t, - user_fpregs_struct, siginfo) + user_fpregs_struct, siginfo, iovec_struct) if not CPU_64BITS: from ptrace.binding.linux_struct import user_fpxregs_struct else: @@ -29,6 +29,9 @@ HAS_PTRACE_EVENTS = False HAS_PTRACE_IO = False HAS_PTRACE_SIGINFO = False HAS_PTRACE_GETREGS = False +HAS_PTRACE_GETREGSET = False +HAS_PTRACE_SETREGS = False +HAS_PTRACE_SETREGSET = False # Special flags that are required to wait for cloned processes (threads) # See wait(2) @@ -79,9 +82,18 @@ elif RUNNING_BSD: PTRACE_IO = 12 else: # Linux - HAS_PTRACE_GETREGS = True - PTRACE_GETREGS = 12 - PTRACE_SETREGS = 13 + if not CPU_AARCH64: + HAS_PTRACE_GETREGS = True + HAS_PTRACE_SETREGS = True + PTRACE_GETREGS = 12 + PTRACE_SETREGS = 13 + + HAS_PTRACE_GETREGSET = True + HAS_PTRACE_SETREGSET = True + PTRACE_GETREGSET = 0x4204 + PTRACE_SETREGSET = 0x4205 + NT_PRSTATUS = 1 + PTRACE_ATTACH = 16 PTRACE_DETACH = 17 PTRACE_SYSCALL = 24 @@ -263,8 +275,25 @@ if RUNNING_LINUX: ptrace(PTRACE_GETREGS, pid, 0, addressof(regs)) return regs - def ptrace_setregs(pid, regs): - ptrace(PTRACE_SETREGS, pid, 0, addressof(regs)) + elif HAS_PTRACE_GETREGSET: + def ptrace_getregs(pid): + regs = ptrace_registers_t() + iov = iovec_struct() + setattr(iov, "buf", addressof(regs)) + setattr(iov, "len", sizeof(regs)) + ptrace(PTRACE_GETREGSET, pid, NT_PRSTATUS, addressof(iov)) + return regs + + if HAS_PTRACE_SETREGS: + def ptrace_setregs(pid, regs): + ptrace(PTRACE_SETREGS, pid, 0, addressof(regs)) + + elif HAS_PTRACE_SETREGSET: + def ptrace_setregs(pid, regs): + iov = iovec_struct() + setattr(iov, "buf", addressof(regs)) + setattr(iov, "len", sizeof(regs)) + ptrace(PTRACE_SETREGSET, pid, NT_PRSTATUS, addressof(iov)) if HAS_PTRACE_SINGLESTEP: def ptrace_singlestep(pid): diff --git a/ptrace/binding/linux_struct.py b/ptrace/binding/linux_struct.py index 728b30a..1bcc20c 100644 --- a/ptrace/binding/linux_struct.py +++ b/ptrace/binding/linux_struct.py @@ -1,7 +1,7 @@ from ctypes import (Structure, Union, sizeof, c_char, c_ushort, c_int, c_uint, c_ulong, c_void_p, - c_uint16, c_uint32, c_uint64) -from ptrace.cpu_info import CPU_64BITS, CPU_PPC32, CPU_PPC64, CPU_ARM + c_uint16, c_uint32, c_uint64, c_size_t) +from ptrace.cpu_info import CPU_64BITS, CPU_PPC32, CPU_PPC64, CPU_ARM32, CPU_AARCH64 pid_t = c_int uid_t = c_ushort @@ -12,7 +12,15 @@ clock_t = c_uint # arch/$ARCH/include/uapi/asm/ptrace.h -class user_regs_struct(Structure): +class register_structure(Structure): + def __str__(self): + regs = {} + for reg in self.__class__._fields_: + regs.update({reg[0]: getattr(self, reg[0])}) + return str(regs) + + +class user_regs_struct(register_structure): if CPU_PPC32: _fields_ = ( ("gpr0", c_ulong), @@ -107,8 +115,14 @@ class user_regs_struct(Structure): ("dsisr", c_ulong), ("result", c_ulong), ) - elif CPU_ARM: + elif CPU_ARM32: _fields_ = tuple(("r%i" % reg, c_ulong) for reg in range(18)) + elif CPU_AARCH64: + _fields_ = tuple([*[("r%i" % reg, c_ulong) for reg in range(31)], + ('sp', c_ulong), + ('pc', c_ulong), + ('pstate', c_ulong)] + ) elif CPU_64BITS: _fields_ = ( ("r15", c_ulong), @@ -167,7 +181,7 @@ class user_regs_struct(Structure): ) -class user_fpregs_struct(Structure): +class user_fpregs_struct(register_structure): if CPU_64BITS: _fields_ = ( ("cwd", c_uint16), @@ -196,7 +210,7 @@ class user_fpregs_struct(Structure): if not CPU_64BITS: - class user_fpxregs_struct(Structure): + class user_fpxregs_struct(register_structure): _fields_ = ( ("cwd", c_ushort), ("swd", c_ushort), @@ -252,3 +266,10 @@ class siginfo(Structure): ("_sifields", _sifields_t) ) _anonymous_ = ("_sifields",) + + +class iovec_struct(Structure): + _fields_ = ( + ("buf", c_void_p), + ("len", c_size_t) + ) diff --git a/ptrace/cpu_info.py b/ptrace/cpu_info.py index 810effe..e8cd7b2 100644 --- a/ptrace/cpu_info.py +++ b/ptrace/cpu_info.py @@ -39,7 +39,8 @@ if HAS_UNAME: CPU_PPC64 = (_machine in ('ppc64', 'ppc64le')) CPU_I386 = (_machine in ("i386", "i686")) # compatible Intel 32 bits CPU_X86_64 = (_machine in ("x86_64", "amd64")) # compatible Intel 64 bits - CPU_ARM = _machine.startswith('arm') + CPU_ARM32 = _machine.startswith('arm') + CPU_AARCH64 = (_machine == 'aarch64') del _machine else: # uname() fallback for Windows @@ -48,7 +49,8 @@ else: CPU_PPC64 = False CPU_I386 = False CPU_X86_64 = False - CPU_ARM = False + CPU_ARM32 = False + CPU_AARCH64 = False bits, linkage = architecture() if bits == '32bit': CPU_I386 = True @@ -59,3 +61,4 @@ else: CPU_INTEL = (CPU_I386 or CPU_X86_64) CPU_POWERPC = (CPU_PPC32 or CPU_PPC64) +CPU_ARM = (CPU_ARM32 or CPU_AARCH64) diff --git a/ptrace/debugger/process.py b/ptrace/debugger/process.py index 12f4431..e3e2906 100644 --- a/ptrace/debugger/process.py +++ b/ptrace/debugger/process.py @@ -1,6 +1,7 @@ from ptrace.binding import ( HAS_PTRACE_SINGLESTEP, HAS_PTRACE_EVENTS, HAS_PTRACE_SIGINFO, HAS_PTRACE_IO, HAS_PTRACE_GETREGS, + HAS_PTRACE_GETREGSET, ptrace_attach, ptrace_detach, ptrace_cont, ptrace_syscall, ptrace_setregs, @@ -45,7 +46,7 @@ if HAS_PTRACE_EVENTS: PTRACE_EVENT_EXEC) NEW_PROCESS_EVENT = ( PTRACE_EVENT_FORK, PTRACE_EVENT_VFORK, PTRACE_EVENT_CLONE) -if HAS_PTRACE_GETREGS: +if HAS_PTRACE_GETREGS or HAS_PTRACE_GETREGSET: from ptrace.binding import ptrace_getregs else: from ptrace.binding import ptrace_peekuser, ptrace_registers_t @@ -411,7 +412,7 @@ class PtraceProcess(object): raise ProcessError(self, "Unknown ptrace event: %r" % event) def getregs(self): - if HAS_PTRACE_GETREGS: + if HAS_PTRACE_GETREGS or HAS_PTRACE_GETREGSET: return ptrace_getregs(self.pid) else: # FIXME: Optimize getreg() when used with this function diff --git a/ptrace/syscall/linux/aarch64.py b/ptrace/syscall/linux/aarch64.py new file mode 100644 index 0000000..8e522fb --- /dev/null +++ b/ptrace/syscall/linux/aarch64.py @@ -0,0 +1,317 @@ +# From https://github.com/hrw/syscalls-table/ + +SYSCALL_NAMES = { + 0: "io_setup", + 1: "io_destroy", + 2: "io_submit", + 3: "io_cancel", + 4: "io_getevents", + 5: "setxattr", + 6: "lsetxattr", + 7: "fsetxattr", + 8: "getxattr", + 9: "lgetxattr", + 10: "fgetxattr", + 11: "listxattr", + 12: "llistxattr", + 13: "flistxattr", + 14: "removexattr", + 15: "lremovexattr", + 16: "fremovexattr", + 17: "getcwd", + 18: "lookup_dcookie", + 19: "eventfd2", + 20: "epoll_create1", + 21: "epoll_ctl", + 22: "epoll_pwait", + 23: "dup", + 24: "dup3", + 25: "fcntl", + 26: "inotify_init1", + 27: "inotify_add_watch", + 28: "inotify_rm_watch", + 29: "ioctl", + 30: "ioprio_set", + 31: "ioprio_get", + 32: "flock", + 33: "mknodat", + 34: "mkdirat", + 35: "unlinkat", + 36: "symlinkat", + 37: "linkat", + 38: "renameat", + 39: "umount2", + 40: "mount", + 41: "pivot_root", + 42: "nfsservctl", + 43: "statfs", + 44: "fstatfs", + 45: "truncate", + 46: "ftruncate", + 47: "fallocate", + 48: "faccessat", + 49: "chdir", + 50: "fchdir", + 51: "chroot", + 52: "fchmod", + 53: "fchmodat", + 54: "fchownat", + 55: "fchown", + 56: "openat", + 57: "close", + 58: "vhangup", + 59: "pipe2", + 60: "quotactl", + 61: "getdents64", + 62: "lseek", + 63: "read", + 64: "write", + 65: "readv", + 66: "writev", + 67: "pread64", + 68: "pwrite64", + 69: "preadv", + 70: "pwritev", + 71: "sendfile", + 72: "pselect6", + 73: "ppoll", + 74: "signalfd4", + 75: "vmsplice", + 76: "splice", + 77: "tee", + 78: "readlinkat", + 79: "newfstatat", + 80: "fstat", + 81: "sync", + 82: "fsync", + 83: "fdatasync", + 84: "sync_file_range", + 85: "timerfd_create", + 86: "timerfd_settime", + 87: "timerfd_gettime", + 88: "utimensat", + 89: "acct", + 90: "capget", + 91: "capset", + 92: "personality", + 93: "exit", + 94: "exit_group", + 95: "waitid", + 96: "set_tid_address", + 97: "unshare", + 98: "futex", + 99: "set_robust_list", + 100: "get_robust_list", + 101: "nanosleep", + 102: "getitimer", + 103: "setitimer", + 104: "kexec_load", + 105: "init_module", + 106: "delete_module", + 107: "timer_create", + 108: "timer_gettime", + 109: "timer_getoverrun", + 110: "timer_settime", + 111: "timer_delete", + 112: "clock_settime", + 113: "clock_gettime", + 114: "clock_getres", + 115: "clock_nanosleep", + 116: "syslog", + 117: "ptrace", + 118: "sched_setparam", + 119: "sched_setscheduler", + 120: "sched_getscheduler", + 121: "sched_getparam", + 122: "sched_setaffinity", + 123: "sched_getaffinity", + 124: "sched_yield", + 125: "sched_get_priority_max", + 126: "sched_get_priority_min", + 127: "sched_rr_get_interval", + 128: "restart_syscall", + 129: "kill", + 130: "tkill", + 131: "tgkill", + 132: "sigaltstack", + 133: "rt_sigsuspend", + 134: "rt_sigaction", + 135: "rt_sigprocmask", + 136: "rt_sigpending", + 137: "rt_sigtimedwait", + 138: "rt_sigqueueinfo", + 139: "rt_sigreturn", + 140: "setpriority", + 141: "getpriority", + 142: "reboot", + 143: "setregid", + 144: "setgid", + 145: "setreuid", + 146: "setuid", + 147: "setresuid", + 148: "getresuid", + 149: "setresgid", + 150: "getresgid", + 151: "setfsuid", + 152: "setfsgid", + 153: "times", + 154: "setpgid", + 155: "getpgid", + 156: "getsid", + 157: "setsid", + 158: "getgroups", + 159: "setgroups", + 160: "uname", + 161: "sethostname", + 162: "setdomainname", + 163: "getrlimit", + 164: "setrlimit", + 165: "getrusage", + 166: "umask", + 167: "prctl", + 168: "getcpu", + 169: "gettimeofday", + 170: "settimeofday", + 171: "adjtimex", + 172: "getpid", + 173: "getppid", + 174: "getuid", + 175: "geteuid", + 176: "getgid", + 177: "getegid", + 178: "gettid", + 179: "sysinfo", + 180: "mq_open", + 181: "mq_unlink", + 182: "mq_timedsend", + 183: "mq_timedreceive", + 184: "mq_notify", + 185: "mq_getsetattr", + 186: "msgget", + 187: "msgctl", + 188: "msgrcv", + 189: "msgsnd", + 190: "semget", + 191: "semctl", + 192: "semtimedop", + 193: "semop", + 194: "shmget", + 195: "shmctl", + 196: "shmat", + 197: "shmdt", + 198: "socket", + 199: "socketpair", + 200: "bind", + 201: "listen", + 202: "accept", + 203: "connect", + 204: "getsockname", + 205: "getpeername", + 206: "sendto", + 207: "recvfrom", + 208: "setsockopt", + 209: "getsockopt", + 210: "shutdown", + 211: "sendmsg", + 212: "recvmsg", + 213: "readahead", + 214: "brk", + 215: "munmap", + 216: "mremap", + 217: "add_key", + 218: "request_key", + 219: "keyctl", + 220: "clone", + 221: "execve", + 222: "mmap", + 223: "fadvise64", + 224: "swapon", + 225: "swapoff", + 226: "mprotect", + 227: "msync", + 228: "mlock", + 229: "munlock", + 230: "mlockall", + 231: "munlockall", + 232: "mincore", + 233: "madvise", + 234: "remap_file_pages", + 235: "mbind", + 236: "get_mempolicy", + 237: "set_mempolicy", + 238: "migrate_pages", + 239: "move_pages", + 240: "rt_tgsigqueueinfo", + 241: "perf_event_open", + 242: "accept4", + 243: "recvmmsg", + 260: "wait4", + 261: "prlimit64", + 262: "fanotify_init", + 263: "fanotify_mark", + 264: "name_to_handle_at", + 265: "open_by_handle_at", + 266: "clock_adjtime", + 267: "syncfs", + 268: "setns", + 269: "sendmmsg", + 270: "process_vm_readv", + 271: "process_vm_writev", + 272: "kcmp", + 273: "finit_module", + 274: "sched_setattr", + 275: "sched_getattr", + 276: "renameat2", + 277: "seccomp", + 278: "getrandom", + 279: "memfd_create", + 280: "bpf", + 281: "execveat", + 282: "userfaultfd", + 283: "membarrier", + 284: "mlock2", + 285: "copy_file_range", + 286: "preadv2", + 287: "pwritev2", + 288: "pkey_mprotect", + 289: "pkey_alloc", + 290: "pkey_free", + 291: "statx", + 292: "io_pgetevents", + 293: "rseq", + 294: "kexec_file_load", + 424: "pidfd_send_signal", + 425: "io_uring_setup", + 426: "io_uring_enter", + 427: "io_uring_register", + 428: "open_tree", + 429: "move_mount", + 430: "fsopen", + 431: "fsconfig", + 432: "fsmount", + 433: "fspick", + 434: "pidfd_open", + 435: "clone3", + 436: "close_range", + 437: "openat2", + 438: "pidfd_getfd", + 439: "faccessat2", +} + +SOCKET_SYSCALL_NAMES = set(( + "socket", + "socketpair", + "connect", + "sendto", + "recvfrom", + "sendmsg", + "recvmsg", + "bind", + "listen", + "accept", + "getsockname", + "getpeername", + "getsockopt", + "setsockopt", + "shutdown", +)) diff --git a/ptrace/syscall/names.py b/ptrace/syscall/names.py index e60d7e0..fb4e6c6 100644 --- a/ptrace/syscall/names.py +++ b/ptrace/syscall/names.py @@ -1,4 +1,4 @@ -from ptrace.cpu_info import CPU_X86_64, CPU_I386, CPU_PPC64, CPU_PPC32 +from ptrace.cpu_info import CPU_X86_64, CPU_I386, CPU_PPC64, CPU_PPC32, CPU_AARCH64 from ptrace.os_tools import RUNNING_LINUX, RUNNING_FREEBSD if RUNNING_LINUX: if CPU_X86_64: @@ -9,6 +9,8 @@ if RUNNING_LINUX: from ptrace.syscall.linux.powerpc64 import SYSCALL_NAMES, SOCKET_SYSCALL_NAMES elif CPU_PPC32: from ptrace.syscall.linux.powerpc32 import SYSCALL_NAMES, SOCKET_SYSCALL_NAMES + elif CPU_AARCH64: + from ptrace.syscall.linux.aarch64 import SYSCALL_NAMES, SOCKET_SYSCALL_NAMES else: raise NotImplementedError("Unsupported CPU architecture") diff --git a/ptrace/syscall/ptrace_syscall.py b/ptrace/syscall/ptrace_syscall.py index dd7db5e..14d9408 100644 --- a/ptrace/syscall/ptrace_syscall.py +++ b/ptrace/syscall/ptrace_syscall.py @@ -1,7 +1,7 @@ from os import strerror from errno import errorcode -from ptrace.cpu_info import CPU_X86_64, CPU_POWERPC, CPU_I386, CPU_ARM +from ptrace.cpu_info import CPU_X86_64, CPU_POWERPC, CPU_I386, CPU_ARM32, CPU_AARCH64 from ptrace.ctypes_tools import ulong2long, formatAddress, formatWordHex from ptrace.func_call import FunctionCall from ptrace.syscall import SYSCALL_NAMES, SYSCALL_PROTOTYPES, SyscallArgument @@ -12,8 +12,10 @@ from ptrace.binding.cpu import CPU_INSTR_POINTER if CPU_POWERPC: SYSCALL_REGISTER = "gpr0" -elif CPU_ARM: +elif CPU_ARM32: SYSCALL_REGISTER = "r7" +elif CPU_AARCH64: + SYSCALL_REGISTER = "r8" elif RUNNING_LINUX: if CPU_X86_64: SYSCALL_REGISTER = "orig_rax" @@ -25,7 +27,9 @@ else: else: SYSCALL_REGISTER = "eax" -if CPU_ARM: +if CPU_ARM32: + RETURN_VALUE_REGISTER = "r0" +elif CPU_AARCH64: RETURN_VALUE_REGISTER = "r0" elif CPU_I386: RETURN_VALUE_REGISTER = "eax" @@ -84,8 +88,10 @@ class PtraceSyscall(FunctionCall): def readArgumentValues(self, regs): if CPU_X86_64: return (regs.rdi, regs.rsi, regs.rdx, regs.r10, regs.r8, regs.r9) - if CPU_ARM: + if CPU_ARM32: return (regs.r0, regs.r1, regs.r2, regs.r3, regs.r4, regs.r5, regs.r6) + if CPU_AARCH64: + return (regs.r0, regs.r1, regs.r2, regs.r3, regs.r4, regs.r5, regs.r6, regs.r7) if RUNNING_BSD: sp = self.process.getStackPointer() return [self.process.readWord(sp + index * CPU_WORD_SIZE) diff --git a/ptrace/version.py b/ptrace/version.py index e273531..531d737 100644 --- a/ptrace/version.py +++ b/ptrace/version.py @@ -1,5 +1,5 @@ PACKAGE = "python-ptrace" -VERSION = (0, 9, 7) +VERSION = (0, 9, 8) __version__ = '.'.join(map(str, VERSION)) WEBSITE = "http://python-ptrace.readthedocs.io/" LICENSE = "GNU GPL v2" diff --git a/tests/test_strace.py b/tests/test_strace.py index f529637..19537f6 100755 --- a/tests/test_strace.py +++ b/tests/test_strace.py @@ -6,13 +6,13 @@ import sys import tempfile import unittest +STRACE = os.path.normpath( + os.path.join(os.path.dirname(__file__), '..', 'strace.py')) -STRACE = os.path.normpath(os.path.join( - os.path.dirname(__file__), '..', 'strace.py')) +AARCH64 = (getattr(os.uname(), 'machine', None) == 'aarch64') class TestStrace(unittest.TestCase): - def strace(self, *args): """ Strace the given command and return the strace output. """ with tempfile.NamedTemporaryFile(mode='wb+') as temp: @@ -56,29 +56,34 @@ class TestStrace(unittest.TestCase): def test_open(self): code = 'open(%a).close()' % __file__ - self.assert_syscall(code, - br"^open(at)?\(.*test_strace\.pyc?', O_RDONLY(\|O_CLOEXEC)?") + self.assert_syscall( + code, br"^open(at)?\(.*test_strace\.pyc?', O_RDONLY(\|O_CLOEXEC)?") def test_chdir(self): - self.assert_syscall( - "import os; os.chdir('directory')", - br"^chdir\('directory'\)\s+= -2 ENOENT") + self.assert_syscall("import os; os.chdir('directory')", + br"^chdir\('directory'\)\s+= -2 ENOENT") def test_rename(self): - self.assert_syscall( - "import os; os.rename('oldpath', 'newpath')", - br"^rename\('oldpath', 'newpath'\)") + pattern = br"^rename\('oldpath', 'newpath'\)" + if AARCH64: + pattern = br"^renameat\(.*'oldpath'.*'newpath'\)" + self.assert_syscall("import os; os.rename('oldpath', 'newpath')", + pattern) def test_link(self): - self.assert_syscall( - "import os; os.link('oldpath', 'newpath')", - br"^link\('oldpath', 'newpath'\)") + pattern = br"^link\('oldpath', 'newpath'\)" + if AARCH64: + pattern = br"^linkat\(.*'oldpath'.*'newpath'.*\)" + self.assert_syscall("import os; os.link('oldpath', 'newpath')", + pattern) def test_symlink(self): + pattern = br"^symlink\('target', 'linkpath'\)" + if AARCH64: + pattern = br"^symlinkat\(.*'target'.*'linkpath'\)" try: - self.assert_syscall( - "import os; os.symlink('target', 'linkpath')", - br"^symlink\('target', 'linkpath'\)") + self.assert_syscall("import os; os.symlink('target', 'linkpath')", + pattern) finally: try: os.unlink('linkpath')