43 <li>os.execl(path, arg0, arg1, ...)</li> |
53 <li>os.execl(path, arg0, arg1, ...)</li> |
44 <li>os.execle(path, arg0, arg1, ..., env)</li> |
54 <li>os.execle(path, arg0, arg1, ..., env)</li> |
45 <li>os.execlp(file, arg0, arg1, ...)</li> |
55 <li>os.execlp(file, arg0, arg1, ...)</li> |
46 <li>os.execlpe(file, arg0, arg1, ..., env)</li> |
56 <li>os.execlpe(file, arg0, arg1, ..., env)</li> |
47 </ul> |
57 </ul> |
|
58 |
|
59 @param originalName original name of the function to be patched |
|
60 @type str |
|
61 @return function replacing the original one |
|
62 @type function |
48 """ |
63 """ |
49 def newExecl(path, *args): |
64 def newExecl(path, *args): |
50 """ |
65 """ |
51 Function replacing the 'execl' functions of the os module. |
66 Function replacing the 'execl' functions of the os module. |
52 """ |
67 """ |
53 import os |
68 import os |
54 if ( |
69 if _shallPatch(): |
55 _debugClient.debugging and |
|
56 _debugClient.multiprocessSupport |
|
57 ): |
|
58 args = patchArguments(_debugClient, args) |
70 args = patchArguments(_debugClient, args) |
59 if isPythonProgram(args[0]): |
71 if isPythonProgram(args[0]): |
60 path = args[0] |
72 path = args[0] |
61 return getattr(os, originalName)(path, *args) |
73 return getattr(os, originalName)(path, *args) |
62 return newExecl |
74 return newExecl |
93 |
107 |
94 <ul> |
108 <ul> |
95 <li>os.execve(path, args, env)</li> |
109 <li>os.execve(path, args, env)</li> |
96 <li>os.execvpe(file, args, env)</li> |
110 <li>os.execvpe(file, args, env)</li> |
97 </ul> |
111 </ul> |
|
112 |
|
113 @param originalName original name of the function to be patched |
|
114 @type str |
|
115 @return function replacing the original one |
|
116 @type function |
98 """ |
117 """ |
99 def newExecve(path, args, env): |
118 def newExecve(path, args, env): |
100 """ |
119 """ |
101 Function replacing the 'execve' functions of the os module. |
120 Function replacing the 'execve' functions of the os module. |
102 """ |
121 """ |
103 import os |
122 import os |
104 if ( |
123 if _shallPatch(): |
105 _debugClient.debugging and |
|
106 _debugClient.multiprocessSupport |
|
107 ): |
|
108 args = patchArguments(_debugClient, args) |
124 args = patchArguments(_debugClient, args) |
109 if isPythonProgram(args[0]): |
125 if isPythonProgram(args[0]): |
110 path = args[0] |
126 path = args[0] |
111 return getattr(os, originalName)(path, args, env) |
127 return getattr(os, originalName)(path, args, env) |
112 return newExecve |
128 return newExecve |
113 |
129 |
114 |
130 |
115 # TODO: add createSpawn... |
131 def createSpawnl(originalName): |
|
132 """ |
|
133 Function to patch the 'spawnl' process creation functions. |
|
134 |
|
135 <ul> |
|
136 <li>os.spawnl(mode, path, arg0, arg1, ...)</li> |
|
137 <li>os.spawnlp(mode, file, arg0, arg1, ...)</li> |
|
138 </ul> |
|
139 |
|
140 @param originalName original name of the function to be patched |
|
141 @type str |
|
142 @return function replacing the original one |
|
143 @type function |
|
144 """ |
|
145 def newSpawnl(mode, path, *args): |
|
146 """ |
|
147 Function replacing the 'spawnl' functions of the os module. |
|
148 """ |
|
149 import os |
|
150 args = patchArguments(_debugClient, args) |
|
151 return getattr(os, originalName)(mode, path, *args) |
|
152 return newSpawnl |
|
153 |
|
154 |
|
155 def createSpawnv(originalName): |
|
156 """ |
|
157 Function to patch the 'spawnv' process creation functions. |
|
158 |
|
159 <ul> |
|
160 <li>os.spawnv(mode, path, args)</li> |
|
161 <li>os.spawnvp(mode, file, args)</li> |
|
162 </ul> |
|
163 |
|
164 @param originalName original name of the function to be patched |
|
165 @type str |
|
166 @return function replacing the original one |
|
167 @type function |
|
168 """ |
|
169 def newSpawnv(mode, path, args): |
|
170 """ |
|
171 Function replacing the 'spawnv' functions of the os module. |
|
172 """ |
|
173 import os |
|
174 args = patchArguments(_debugClient, args) |
|
175 return getattr(os, originalName)(mode, path, args) |
|
176 return newSpawnv |
|
177 |
|
178 |
|
179 def createSpawnve(originalName): |
|
180 """ |
|
181 Function to patch the 'spawnve' process creation functions. |
|
182 |
|
183 <ul> |
|
184 <li>os.spawnve(mode, path, args, env)</li> |
|
185 <li>os.spawnvpe(mode, file, args, env)</li> |
|
186 </ul> |
|
187 |
|
188 @param originalName original name of the function to be patched |
|
189 @type str |
|
190 @return function replacing the original one |
|
191 @type function |
|
192 """ |
|
193 def newSpawnve(mode, path, args, env): |
|
194 """ |
|
195 Function replacing the 'spawnve' functions of the os module. |
|
196 """ |
|
197 import os |
|
198 args = patchArguments(_debugClient, args) |
|
199 return getattr(os, originalName)(mode, path, args, env) |
|
200 return newSpawnve |
|
201 |
|
202 |
|
203 def createPosixSpawn(originalName): |
|
204 """ |
|
205 Function to patch the 'posix_spawn' process creation functions. |
|
206 |
|
207 <ul> |
|
208 <li>os.posix_spawn(path, argv, env, *, file_actions=None, ... |
|
209 (6 more))</li> |
|
210 <li>os.posix_spawnp(path, argv, env, *, file_actions=None, ... |
|
211 (6 more))</li> |
|
212 </ul> |
|
213 |
|
214 @param originalName original name of the function to be patched |
|
215 @type str |
|
216 @return function replacing the original one |
|
217 @type function |
|
218 """ |
|
219 def newPosixSpawn(path, argv, env, **kwargs): |
|
220 """ |
|
221 Function replacing the 'posix_spawn' functions of the os module. |
|
222 """ |
|
223 import os |
|
224 argv = patchArguments(_debugClient, argv) |
|
225 return getattr(os, originalName)(path, argv, env, **kwargs) |
|
226 return newPosixSpawn |
116 |
227 |
117 |
228 |
118 def createForkExec(originalName): |
229 def createForkExec(originalName): |
119 """ |
230 """ |
120 Function to patch the 'fork_exec' process creation functions. |
231 Function to patch the 'fork_exec' process creation functions. |
121 |
232 |
122 <ul> |
233 <ul> |
123 <li>_posixsubprocess.fork_exec(args, executable_list, close_fds, |
234 <li>_posixsubprocess.fork_exec(args, executable_list, close_fds, |
124 ... (13 more))</li> |
235 ... (13 more))</li> |
125 </ul> |
236 </ul> |
|
237 |
|
238 @param originalName original name of the function to be patched |
|
239 @type str |
|
240 @return function replacing the original one |
|
241 @type function |
126 """ |
242 """ |
127 def newForkExec(args, *other_args): |
243 def newForkExec(args, *other_args): |
128 """ |
244 """ |
129 Function replacing the 'fork_exec' functions of the _posixsubprocess |
245 Function replacing the 'fork_exec' functions of the _posixsubprocess |
130 module. |
246 module. |
131 """ |
247 """ |
132 import _posixsubprocess |
248 import _posixsubprocess |
133 if ( |
249 if _shallPatch(): |
134 _debugClient.debugging and |
|
135 _debugClient.multiprocessSupport |
|
136 ): |
|
137 args = patchArguments(_debugClient, args) |
250 args = patchArguments(_debugClient, args) |
138 return getattr(_posixsubprocess, originalName)(args, *other_args) |
251 return getattr(_posixsubprocess, originalName)(args, *other_args) |
139 return newForkExec |
252 return newForkExec |
140 |
253 |
141 |
254 |
142 def createFork(original_name): |
255 def createFork(originalName): |
143 """ |
256 """ |
144 Function to patch the 'fork' process creation functions. |
257 Function to patch the 'fork' process creation functions. |
145 |
258 |
146 <ul> |
259 <ul> |
147 <li>os.fork()</li> |
260 <li>os.fork()</li> |
148 </ul> |
261 </ul> |
|
262 |
|
263 @param originalName original name of the function to be patched |
|
264 @type str |
|
265 @return function replacing the original one |
|
266 @type function |
149 """ |
267 """ |
150 def new_fork(): |
268 def new_fork(): |
151 """ |
269 """ |
152 Function replacing the 'fork' function of the os module. |
270 Function replacing the 'fork' function of the os module. |
153 """ |
271 """ |
156 |
274 |
157 # A simple fork will result in a new python process |
275 # A simple fork will result in a new python process |
158 isNewPythonProcess = True |
276 isNewPythonProcess = True |
159 frame = sys._getframe() |
277 frame = sys._getframe() |
160 |
278 |
161 multiprocess = ( |
279 multiprocess = _shallPatch() |
162 _debugClient.debugging and _debugClient.multiprocessSupport |
|
163 ) |
|
164 |
280 |
165 isSubprocessFork = False |
281 isSubprocessFork = False |
|
282 isMultiprocessingPopen = False |
166 while frame is not None: |
283 while frame is not None: |
167 if ( |
284 if frame.f_code.co_name == "_Popen": |
|
285 # fork() was called from multiprocessing; ignore this here |
|
286 # because it is handled in 'MultiprocessingExtension.py'. |
|
287 isMultiprocessingPopen = True |
|
288 break |
|
289 |
|
290 elif ( |
168 frame.f_code.co_name == '_execute_child' and |
291 frame.f_code.co_name == '_execute_child' and |
169 'subprocess' in frame.f_code.co_filename |
292 'subprocess' in frame.f_code.co_filename |
170 ): |
293 ): |
171 isSubprocessFork = True |
294 isSubprocessFork = True |
172 # If we're actually in subprocess.Popen creating a child, it |
295 # If we're actually in subprocess.Popen creating a child, it |
180 break |
303 break |
181 |
304 |
182 frame = frame.f_back |
305 frame = frame.f_back |
183 frame = None # Just make sure we don't hold on to it. |
306 frame = None # Just make sure we don't hold on to it. |
184 |
307 |
185 childProcess = getattr(os, original_name)() # fork |
308 childProcess = getattr(os, originalName)() # fork |
186 if not childProcess: |
309 if not childProcess and not isMultiprocessingPopen: |
187 if isNewPythonProcess: |
310 if isNewPythonProcess: |
188 sys.settrace(None) |
|
189 sys.setprofile(None) |
|
190 _debugClient.sessionClose(False) |
|
191 (wd, host, port, exceptions, tracePython, redirect, |
311 (wd, host, port, exceptions, tracePython, redirect, |
192 noencoding, fork_auto, fork_child) = _debugClient.startOptions |
312 noencoding) = _debugClient.startOptions |
193 _debugClient.startDebugger( |
313 _debugClient.startDebugger( |
194 filename=sys.argv[0], |
314 filename=sys.argv[0], |
195 host=host, |
315 host=host, |
196 port=port, |
316 port=port, |
197 enableTrace=multiprocess and not isSubprocessFork, |
317 enableTrace=multiprocess and not isSubprocessFork, |
253 patchModule(os, "execv", createExecv) |
376 patchModule(os, "execv", createExecv) |
254 patchModule(os, "execve", createExecve) |
377 patchModule(os, "execve", createExecve) |
255 patchModule(os, "execvp", createExecv) |
378 patchModule(os, "execvp", createExecv) |
256 patchModule(os, "execvpe", createExecve) |
379 patchModule(os, "execvpe", createExecve) |
257 |
380 |
258 # TODO: implement patching of the various functions of the os module |
381 # patch 'os.spawn...()' functions |
|
382 patchModule(os, "spawnl", createSpawnl) |
|
383 patchModule(os, "spawnle", createSpawnl) |
|
384 patchModule(os, "spawnlp", createSpawnl) |
|
385 patchModule(os, "spawnlpe", createSpawnl) |
|
386 patchModule(os, "spawnv", createSpawnv) |
|
387 patchModule(os, "spawnve", createSpawnve) |
|
388 patchModule(os, "spawnvp", createSpawnv) |
|
389 patchModule(os, "spawnvpe", createSpawnve) |
|
390 |
|
391 # patch 'os.posix_spawn...()' functions |
|
392 if sys.version_info >= (3, 8) and not isWindowsPlatform(): |
|
393 patchModule(os, "posix_spawn", createPosixSpawn) |
|
394 patchModule(os, "posix_spawnp", createPosixSpawn) |
259 |
395 |
260 if isWindowsPlatform(): |
396 if isWindowsPlatform(): |
261 try: |
397 try: |
262 import _subprocess |
398 import _subprocess |
263 except ImportError: |
399 except ImportError: |