# HG changeset patch # User Victor Stinner # Date 1417423044 -3600 # Mon Dec 01 09:37:24 2014 +0100 # Node ID eba1a6dba205559d724d32c80d955a65e078505e # Parent e6fef4231a8a28ef91c1feaf3bfbcbd29822c939 Issue #17: syscall parser now supports O_CLOEXEC and SOCK_CLOEXEC, fix unit tests on Python 3.4 and newer diff --git a/doc/changelog.rst b/doc/changelog.rst --- a/doc/changelog.rst +++ b/doc/changelog.rst @@ -3,6 +3,12 @@ Changelog ========= +python-ptrace 0.8.2 +------------------- + +* Issue #17: syscall parser now supports O_CLOEXEC and SOCK_CLOEXEC, fix unit + tests on Python 3.4 and newer + python-ptrace 0.8.1 (2014-10-30) -------------------------------- diff --git a/ptrace/syscall/posix_arg.py b/ptrace/syscall/posix_arg.py --- a/ptrace/syscall/posix_arg.py +++ b/ptrace/syscall/posix_arg.py @@ -24,7 +24,7 @@ return formatBits(argument.value, ACCESS_MODE_BITMASK, "F_OK") # From /usr/include/bits/fcntl.h (Ubuntu Feisty, i386) -OPEN_MODE_BITMASK = ( +OPEN_MODE_BITMASK = [ (0o1, "O_WRONLY"), (0o2, "O_RDWR"), (0o100, "O_CREAT"), @@ -40,10 +40,17 @@ (0o200000, "O_DIRECTORY"), (0o400000, "O_NOFOLLOW"), (0o1000000, "O_NOATIME"), -) +] +O_CLOEXEC = 0o02000000 def formatOpenMode(argument): - return formatBits(int(argument.value), OPEN_MODE_BITMASK, "O_RDONLY", oct) + value = argument.value + cloexec = bool(value & O_CLOEXEC) + value = value & ~O_CLOEXEC + text = formatBits(int(value), OPEN_MODE_BITMASK, "O_RDONLY", oct) + if cloexec: + text += '|O_CLOEXEC' + return text CLONE_FLAGS_BITMASK = ( (0x00000100, "CLONE_VM"), diff --git a/ptrace/syscall/posix_constants.py b/ptrace/syscall/posix_constants.py --- a/ptrace/syscall/posix_constants.py +++ b/ptrace/syscall/posix_constants.py @@ -1,5 +1,5 @@ from ptrace.syscall.socketcall_constants import ( - SOCKET_FAMILY, SOCKET_TYPE, SOCKET_PROTOCOL, + SOCKET_FAMILY, SOCKET_PROTOCOL, SETSOCKOPT_LEVEL, SETSOCKOPT_OPTNAME) SYSCALL_ARG_DICT = { @@ -51,7 +51,6 @@ }, "socket": { "domain": SOCKET_FAMILY, - "type": SOCKET_TYPE, "protocol": SOCKET_PROTOCOL, }, "getsockopt": { diff --git a/ptrace/syscall/socketcall_constants.py b/ptrace/syscall/socketcall_constants.py --- a/ptrace/syscall/socketcall_constants.py +++ b/ptrace/syscall/socketcall_constants.py @@ -1,3 +1,5 @@ +import socket + SOCKETCALL = { 1: "socket", 2: "bind", @@ -56,6 +58,19 @@ 10: "SOCK_PACKET", } +def formatSocketType(argument): + value = argument.value + text = [] + if hasattr(socket, 'SOCK_CLOEXEC'): + cloexec = value & socket.SOCK_CLOEXEC + value &= ~socket.SOCK_CLOEXEC + else: + cloexec = False + text = SOCKET_TYPE.get(value, value) + if cloexec: + text += '|SOCK_CLOEXEC' + return text + SOCKET_PROTOCOL = { 1: "IPPROTO_ICMP", 58: "IPPROTO_ICMPV6", diff --git a/ptrace/syscall/syscall_argument.py b/ptrace/syscall/syscall_argument.py --- a/ptrace/syscall/syscall_argument.py +++ b/ptrace/syscall/syscall_argument.py @@ -22,6 +22,7 @@ from ptrace.syscall.freebsd_constants import SYSCALL_ARG_DICT else: SYSCALL_ARG_DICT = {} +from ptrace.syscall.socketcall_constants import formatSocketType KNOWN_STRUCTS = [] if RUNNING_LINUX: @@ -35,6 +36,7 @@ "mmap": {"prot": formatMmapProt}, "mmap2": {"prot": formatMmapProt}, "clone": {"flags": formatCloneFlags}, + "socket": {"type": formatSocketType}, "setsockopt": {"optval": formatOptVal}, } diff --git a/tests/test_strace.py b/tests/test_strace.py --- a/tests/test_strace.py +++ b/tests/test_strace.py @@ -39,10 +39,19 @@ expected = os.fsencode(expected) self.assertEqual(match.group(1), expected) + def test_open(self): + if PY3: + code = 'open(%a).close()' % __file__ + else: + code = 'open(%r).close()' % __file__ + stdout = self.strace(sys.executable, '-c', code) + pattern = re.compile(br"^open\(.*test_strace\.py', O_RDONLY(\|O_CLOEXEC)?\)", re.MULTILINE) + self.assertTrue(pattern.search(stdout), stdout) + def test_socket(self): code = 'import socket; socket.socket(socket.AF_INET, socket.SOCK_STREAM).close()' stdout = self.strace(sys.executable, '-c', code) - pattern = re.compile(b'^socket\\(AF_INET, SOCK_STREAM, ', re.MULTILINE) + pattern = re.compile(br'^socket\(AF_INET, SOCK_STREAM(\|SOCK_CLOEXEC)?, ', re.MULTILINE) self.assertTrue(pattern.search(stdout), stdout) if __name__ == "__main__":