summaryrefslogtreecommitdiff
blob: 2e6e76f8e6df93f528753db6cb0ce2caa8dbcfba (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
# HG changeset patch
# User Victor Stinner <victor.stinner@gmail.com>
# 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__":