diff --git a/_multibuild b/_multibuild
new file mode 100644
index 0000000..553b69b
--- /dev/null
+++ b/_multibuild
@@ -0,0 +1,4 @@
+
+ cptrace
+ test
+
diff --git a/add-aarch64-support.patch b/add-aarch64-support.patch
deleted file mode 100644
index 3d24ebf..0000000
--- a/add-aarch64-support.patch
+++ /dev/null
@@ -1,769 +0,0 @@
-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')
diff --git a/python-ptrace-0.9.7.tar.gz b/python-ptrace-0.9.7.tar.gz
deleted file mode 100644
index fd55b75..0000000
--- a/python-ptrace-0.9.7.tar.gz
+++ /dev/null
@@ -1,3 +0,0 @@
-version https://git-lfs.github.com/spec/v1
-oid sha256:9bef768ccb508004be49ae24ea5639ade45c116bd02925faa2054765a6c0e3a3
-size 100597
diff --git a/python-ptrace-0.9.8.tar.gz b/python-ptrace-0.9.8.tar.gz
new file mode 100644
index 0000000..45895d7
--- /dev/null
+++ b/python-ptrace-0.9.8.tar.gz
@@ -0,0 +1,3 @@
+version https://git-lfs.github.com/spec/v1
+oid sha256:b54c43e87caf02d1452d6400649822c99e8f7ca31fa3f655ea88caf85369e3d4
+size 104079
diff --git a/python-ptrace-pr81-importlib.patch b/python-ptrace-pr81-importlib.patch
new file mode 100644
index 0000000..c3a9186
--- /dev/null
+++ b/python-ptrace-pr81-importlib.patch
@@ -0,0 +1,34 @@
+From 80e0c97a84eccb8b82737cf40b9c5581c20c245f Mon Sep 17 00:00:00 2001
+From: Mario Haustein
+Date: Sat, 16 Sep 2023 13:49:43 +0200
+Subject: [PATCH] Remove deprecated `imp` module
+
+---
+ setup.py | 7 +++++--
+ 1 file changed, 5 insertions(+), 2 deletions(-)
+
+diff --git a/setup.py b/setup.py
+index 4d6ba36..ad54f9a 100755
+--- a/setup.py
++++ b/setup.py
+@@ -28,7 +28,7 @@
+ # - git commit -a -m "post-release"
+ # - git push
+
+-from imp import load_source
++import importlib.util
+ from os import path
+ try:
+ # setuptools supports bdist_wheel
+@@ -55,7 +55,10 @@
+ with open('README.rst') as fp:
+ LONG_DESCRIPTION = fp.read()
+
+-ptrace = load_source("version", path.join("ptrace", "version.py"))
++ptrace_spec = importlib.util.spec_from_file_location("version", path.join("ptrace", "version.py"))
++ptrace = importlib.util.module_from_spec(ptrace_spec)
++ptrace_spec.loader.exec_module(ptrace)
++
+ PACKAGES = {}
+ for name in MODULES:
+ PACKAGES[name] = name.replace(".", "/")
diff --git a/python-ptrace-pr83-importlib.patch b/python-ptrace-pr83-importlib.patch
new file mode 100644
index 0000000..bc0a351
--- /dev/null
+++ b/python-ptrace-pr83-importlib.patch
@@ -0,0 +1,42 @@
+From 41f5378bbf4bfa75970d5cc3f6615411cff61a6c Mon Sep 17 00:00:00 2001
+From: Stephen Kitt
+Date: Sun, 10 Dec 2023 19:07:27 +0100
+Subject: [PATCH] Use importlib instead of imp in setup_cptrace.py
+
+Signed-off-by: Stephen Kitt
+---
+ setup_cptrace.py | 8 ++++++--
+ 1 file changed, 6 insertions(+), 2 deletions(-)
+
+diff --git a/setup_cptrace.py b/setup_cptrace.py
+index 8de9d01..f06b792 100755
+--- a/setup_cptrace.py
++++ b/setup_cptrace.py
+@@ -1,5 +1,7 @@
+ #!/usr/bin/env python
+
++import importlib.util
++
+ SOURCES = ['cptrace/cptrace.c']
+
+ CLASSIFIERS = [
+@@ -17,7 +19,6 @@
+
+
+ def main():
+- from imp import load_source
+ from os import path
+ from sys import argv
+
+@@ -29,7 +30,10 @@ def main():
+
+ cptrace_ext = Extension('cptrace', sources=SOURCES)
+
+- cptrace = load_source("version", path.join("cptrace", "version.py"))
++ cptrace_spec = importlib.util.spec_from_file_location("version",
++ path.join("cptrace", "version.py"))
++ cptrace = importlib.util.module_from_spec(cptrace_spec)
++ cptrace_spec.loader.exec_module(cptrace)
+
+ install_options = {
+ "name": cptrace.PACKAGE,
diff --git a/python-python-ptrace.changes b/python-python-ptrace.changes
index 0e6bdb9..a97d71f 100644
--- a/python-python-ptrace.changes
+++ b/python-python-ptrace.changes
@@ -1,3 +1,19 @@
+-------------------------------------------------------------------
+Sun Mar 3 19:17:50 UTC 2024 - Ben Greiner
+
+- Update to 0.9.8
+ * Added Arm 64bit (AArch64) support.
+ * Implemented ``PTRACE_GETREGSET`` and ``PTRACE_SETREGSET``
+ required on AArch64 and available on Linux.
+ * Issue #66: Fix ``SIGTRAP|0x80`` or ``SIGTRAP`` wait in
+ syscall_state.exit (``PTRACE_O_TRACESYSGOOD``).
+- Build PEP517 wheels separately in multibuild
+- Add patchtes for Python 3.12:
+ * python-ptrace-pr81-importlib.patch gh#vstinner/python-ptrace#81
+ * python-ptrace-pr83-importlib.patch gh#vstinner/python-ptrace#83
+- Remove upstreamed patch:
+ * add-aarch64-support.patch
+
-------------------------------------------------------------------
Wed Jan 13 07:33:18 UTC 2021 - Guillaume GARDET
diff --git a/python-python-ptrace.spec b/python-python-ptrace.spec
index a391f8c..b783042 100644
--- a/python-python-ptrace.spec
+++ b/python-python-ptrace.spec
@@ -1,7 +1,7 @@
#
# spec file for package python-python-ptrace
#
-# Copyright (c) 2021 SUSE LLC
+# Copyright (c) 2024 SUSE LLC
#
# All modifications and additions to the file contributed by third parties
# remain the property of their copyright owners, unless otherwise agreed
@@ -16,50 +16,93 @@
#
-%{?!python_module:%define python_module() python-%{**} python3-%{**}}
-%define pkg_name python-ptrace
-%define skip_python2 1
-Name: python-%{pkg_name}
-Version: 0.9.7
+%global flavor @BUILD_FLAVOR@%{nil}
+%define pyversion 0.9.8
+%define cversion 0.6.1
+%if "%{flavor}" == ""
+%define pkgname python-ptrace
+%define pkgversion %{pyversion}
+%bcond_with test
+%endif
+%if "%{flavor}" == "cptrace"
+%define pkgname cptrace
+%define pkgversion %{cversion}
+%bcond_with test
+%endif
+%if "%{flavor}" == "test"
+%define pkgname python-ptrace-test
+%define pkgversion %{pyversion}+%{cversion}
+%bcond_without test
+ExcludeArch: %arm
+%endif
+
+Name: python-%{pkgname}
+Version: %{pkgversion}
Release: 0
Summary: Python binding for ptrace
License: GPL-2.0-only
Group: Development/Languages/Python
URL: https://github.com/vstinner/python-ptrace
-Source: https://github.com/haypo/%{pkg_name}/archive/%{version}.tar.gz#!./%{pkg_name}-%{version}.tar.gz
-# PATCH-FIX-UPSTREAM - https://github.com/vstinner/python-ptrace/pull/59
-Patch1: add-aarch64-support.patch
+Source: https://github.com/haypo/python-ptrace/archive/%{pyversion}.tar.gz#/python-ptrace-%{pyversion}.tar.gz
+# PATCH-FIX-UPSTREAM - Add python-ptrace-pr81-importlib.patch gh#vstinner/python-ptrace#81
+Patch0: https://github.com/vstinner/python-ptrace/pull/81.patch#/python-ptrace-pr81-importlib.patch
+# PATCH-FIX-UPSTREAM - Add python-ptrace-pr83-importlib.patch gh#vstinner/python-ptrace#83
+Patch1: https://github.com/vstinner/python-ptrace/pull/83.patch#/python-ptrace-pr83-importlib.patch
+%if "%{flavor}" == "cptrace"
BuildRequires: %{python_module devel}
+%else
+BuildArch: noarch
+Recommends: python-cptrace = %{cversion}
+%endif
+BuildRequires: %{python_module pip}
BuildRequires: %{python_module setuptools}
+BuildRequires: %{python_module wheel}
BuildRequires: fdupes
BuildRequires: python-rpm-macros
Requires(post): update-alternatives
Requires(postun): update-alternatives
+%if %{with test}
+BuildRequires: %{python_module cptrace = %{cversion}}
+BuildRequires: %{python_module python-ptrace = %{pyversion}}
+%endif
%python_subpackages
%description
python-ptrace is a debugger using ptrace written in Python.
%prep
-%setup -q -n %{pkg_name}-%{version}
-%patch1 -p1
+%autosetup -p1 -n python-ptrace-%{pyversion}
sed -i 's/\x0D$//' doc/*.rst
chmod 0644 examples/*.py
%build
-%python_build
-%python_exec setup_cptrace.py build
+%if !%{with test}
+%if "%{flavor}" == "cptrace"
+mv setup.py setup_python-ptrace.py
+mv setup_cptrace.py setup.py
+%endif
+%pyproject_wheel
+%endif
%install
-%python_install
-%python_exec setup_cptrace.py install -O1 --skip-build --root %{buildroot}
+%if !%{with test}
+%pyproject_install
+%if "%{flavor}" == "cptrace"
+%python_expand %fdupes %{buildroot}%{$python_sitearch}
+%else
%python_clone -a %{buildroot}%{_bindir}/gdb.py
%python_clone -a %{buildroot}%{_bindir}/strace.py
%python_expand %fdupes %{buildroot}%{$python_sitelib}
+%endif
+%endif
+%if %{with test}
%check
-%python_exec runtests.py
+%python_exec runtests.py -v
+%endif
+%if !%{with test}
+%if "%{flavor}" == ""
%post
%python_install_alternative strace.py
%python_install_alternative gdb.py
@@ -75,8 +118,16 @@ chmod 0644 examples/*.py
%python_alternative %{_bindir}/gdb.py
%python_alternative %{_bindir}/strace.py
%{python_sitelib}/ptrace/
-%{python_sitelib}/python_ptrace-*-py*.egg-info
+%{python_sitelib}/python_ptrace-%{pkgversion}.dist-info
+%endif
+
+%if "%{flavor}" == "cptrace"
+%files %{python_files}
+%license COPYING
+%doc README.rst
%{python_sitearch}/cptrace*.so
-%{python_sitearch}/cptrace-*-py*.egg-info
+%{python_sitearch}/cptrace-%{pkgversion}.dist-info
+%endif
+%endif
%changelog