Run DCE after a LoopFlatten test to reduce spurious output [nfc]
[llvm-project.git] / lldb / examples / python / process_events.py
blob6225ae06b78e944a4c36a349c3f65600926a1ff3
1 #!/usr/bin/env python
3 # ----------------------------------------------------------------------
4 # Be sure to add the python path that points to the LLDB shared library.
5 # On MacOSX csh, tcsh:
6 # setenv PYTHONPATH /Applications/Xcode.app/Contents/SharedFrameworks/LLDB.framework/Resources/Python
7 # On MacOSX sh, bash:
8 # export PYTHONPATH=/Applications/Xcode.app/Contents/SharedFrameworks/LLDB.framework/Resources/Python
9 # ----------------------------------------------------------------------
11 import optparse
12 import os
13 import platform
14 import sys
15 import subprocess
17 # ----------------------------------------------------------------------
18 # Code that auto imports LLDB
19 # ----------------------------------------------------------------------
20 try:
21 # Just try for LLDB in case PYTHONPATH is already correctly setup
22 import lldb
23 except ImportError:
24 lldb_python_dirs = list()
25 # lldb is not in the PYTHONPATH, try some defaults for the current platform
26 platform_system = platform.system()
27 if platform_system == "Darwin":
28 # On Darwin, try the currently selected Xcode directory
29 xcode_dir = subprocess.check_output("xcode-select --print-path", shell=True)
30 if xcode_dir:
31 lldb_python_dirs.append(
32 os.path.realpath(
33 xcode_dir + "/../SharedFrameworks/LLDB.framework/Resources/Python"
36 lldb_python_dirs.append(
37 xcode_dir + "/Library/PrivateFrameworks/LLDB.framework/Resources/Python"
39 lldb_python_dirs.append(
40 "/System/Library/PrivateFrameworks/LLDB.framework/Resources/Python"
42 success = False
43 for lldb_python_dir in lldb_python_dirs:
44 if os.path.exists(lldb_python_dir):
45 if not (sys.path.__contains__(lldb_python_dir)):
46 sys.path.append(lldb_python_dir)
47 try:
48 import lldb
49 except ImportError:
50 pass
51 else:
52 print('imported lldb from: "%s"' % (lldb_python_dir))
53 success = True
54 break
55 if not success:
56 print(
57 "error: couldn't locate the 'lldb' module, please set PYTHONPATH correctly"
59 sys.exit(1)
62 def print_threads(process, options):
63 if options.show_threads:
64 for thread in process:
65 print("%s %s" % (thread, thread.GetFrameAtIndex(0)))
68 def run_commands(command_interpreter, commands):
69 return_obj = lldb.SBCommandReturnObject()
70 for command in commands:
71 command_interpreter.HandleCommand(command, return_obj)
72 if return_obj.Succeeded():
73 print(return_obj.GetOutput())
74 else:
75 print(return_obj)
76 if options.stop_on_error:
77 break
80 def main(argv):
81 description = """Debugs a program using the LLDB python API and uses asynchronous broadcast events to watch for process state changes."""
82 epilog = """Examples:
84 #----------------------------------------------------------------------
85 # Run "/bin/ls" with the arguments "-lAF /tmp/", and set a breakpoint
86 # at "malloc" and backtrace and read all registers each time we stop
87 #----------------------------------------------------------------------
88 % ./process_events.py --breakpoint malloc --stop-command bt --stop-command 'register read' -- /bin/ls -lAF /tmp/
90 """
91 optparse.OptionParser.format_epilog = lambda self, formatter: self.epilog
92 parser = optparse.OptionParser(
93 description=description,
94 prog="process_events",
95 usage="usage: process_events [options] program [arg1 arg2]",
96 epilog=epilog,
98 parser.add_option(
99 "-v",
100 "--verbose",
101 action="store_true",
102 dest="verbose",
103 help="Enable verbose logging.",
104 default=False,
106 parser.add_option(
107 "-b",
108 "--breakpoint",
109 action="append",
110 type="string",
111 metavar="BPEXPR",
112 dest="breakpoints",
113 help='Breakpoint commands to create after the target has been created, the values will be sent to the "_regexp-break" command which supports breakpoints by name, file:line, and address.',
115 parser.add_option(
116 "-a",
117 "--arch",
118 type="string",
119 dest="arch",
120 help="The architecture to use when creating the debug target.",
121 default=None,
123 parser.add_option(
124 "--platform",
125 type="string",
126 metavar="platform",
127 dest="platform",
128 help='Specify the platform to use when creating the debug target. Valid values include "localhost", "darwin-kernel", "ios-simulator", "remote-freebsd", "remote-macosx", "remote-ios", "remote-linux".',
129 default=None,
131 parser.add_option(
132 "-l",
133 "--launch-command",
134 action="append",
135 type="string",
136 metavar="CMD",
137 dest="launch_commands",
138 help="LLDB command interpreter commands to run once after the process has launched. This option can be specified more than once.",
139 default=[],
141 parser.add_option(
142 "-s",
143 "--stop-command",
144 action="append",
145 type="string",
146 metavar="CMD",
147 dest="stop_commands",
148 help="LLDB command interpreter commands to run each time the process stops. This option can be specified more than once.",
149 default=[],
151 parser.add_option(
152 "-c",
153 "--crash-command",
154 action="append",
155 type="string",
156 metavar="CMD",
157 dest="crash_commands",
158 help="LLDB command interpreter commands to run in case the process crashes. This option can be specified more than once.",
159 default=[],
161 parser.add_option(
162 "-x",
163 "--exit-command",
164 action="append",
165 type="string",
166 metavar="CMD",
167 dest="exit_commands",
168 help="LLDB command interpreter commands to run once after the process has exited. This option can be specified more than once.",
169 default=[],
171 parser.add_option(
172 "-T",
173 "--no-threads",
174 action="store_false",
175 dest="show_threads",
176 help="Don't show threads when process stops.",
177 default=True,
179 parser.add_option(
180 "--ignore-errors",
181 action="store_false",
182 dest="stop_on_error",
183 help="Don't stop executing LLDB commands if the command returns an error. This applies to all of the LLDB command interpreter commands that get run for launch, stop, crash and exit.",
184 default=True,
186 parser.add_option(
187 "-n",
188 "--run-count",
189 type="int",
190 dest="run_count",
191 metavar="N",
192 help="How many times to run the process in case the process exits.",
193 default=1,
195 parser.add_option(
196 "-t",
197 "--event-timeout",
198 type="int",
199 dest="event_timeout",
200 metavar="SEC",
201 help="Specify the timeout in seconds to wait for process state change events.",
202 default=lldb.UINT32_MAX,
204 parser.add_option(
205 "-e",
206 "--environment",
207 action="append",
208 type="string",
209 metavar="ENV",
210 dest="env_vars",
211 help="Environment variables to set in the inferior process when launching a process.",
213 parser.add_option(
214 "-d",
215 "--working-dir",
216 type="string",
217 metavar="DIR",
218 dest="working_dir",
219 help="The current working directory when launching a process.",
220 default=None,
222 parser.add_option(
223 "-p",
224 "--attach-pid",
225 type="int",
226 dest="attach_pid",
227 metavar="PID",
228 help="Specify a process to attach to by process ID.",
229 default=-1,
231 parser.add_option(
232 "-P",
233 "--attach-name",
234 type="string",
235 dest="attach_name",
236 metavar="PROCESSNAME",
237 help="Specify a process to attach to by name.",
238 default=None,
240 parser.add_option(
241 "-w",
242 "--attach-wait",
243 action="store_true",
244 dest="attach_wait",
245 help="Wait for the next process to launch when attaching to a process by name.",
246 default=False,
248 try:
249 (options, args) = parser.parse_args(argv)
250 except:
251 return
253 attach_info = None
254 launch_info = None
255 exe = None
256 if args:
257 exe = args.pop(0)
258 launch_info = lldb.SBLaunchInfo(args)
259 if options.env_vars:
260 launch_info.SetEnvironmentEntries(options.env_vars, True)
261 if options.working_dir:
262 launch_info.SetWorkingDirectory(options.working_dir)
263 elif options.attach_pid != -1:
264 if options.run_count == 1:
265 attach_info = lldb.SBAttachInfo(options.attach_pid)
266 else:
267 print("error: --run-count can't be used with the --attach-pid option")
268 sys.exit(1)
269 elif not options.attach_name is None:
270 if options.run_count == 1:
271 attach_info = lldb.SBAttachInfo(options.attach_name, options.attach_wait)
272 else:
273 print("error: --run-count can't be used with the --attach-name option")
274 sys.exit(1)
275 else:
276 print(
277 "error: a program path for a program to debug and its arguments are required"
279 sys.exit(1)
281 # Create a new debugger instance
282 debugger = lldb.SBDebugger.Create()
283 debugger.SetAsync(True)
284 command_interpreter = debugger.GetCommandInterpreter()
285 # Create a target from a file and arch
287 if exe:
288 print("Creating a target for '%s'" % exe)
289 error = lldb.SBError()
290 target = debugger.CreateTarget(exe, options.arch, options.platform, True, error)
292 if target:
293 # Set any breakpoints that were specified in the args if we are launching. We use the
294 # command line command to take advantage of the shorthand breakpoint
295 # creation
296 if launch_info and options.breakpoints:
297 for bp in options.breakpoints:
298 debugger.HandleCommand("_regexp-break %s" % (bp))
299 run_commands(command_interpreter, ["breakpoint list"])
301 for run_idx in range(options.run_count):
302 # Launch the process. Since we specified synchronous mode, we won't return
303 # from this function until we hit the breakpoint at main
304 error = lldb.SBError()
306 if launch_info:
307 if options.run_count == 1:
308 print('Launching "%s"...' % (exe))
309 else:
310 print(
311 'Launching "%s"... (launch %u of %u)'
312 % (exe, run_idx + 1, options.run_count)
315 process = target.Launch(launch_info, error)
316 else:
317 if options.attach_pid != -1:
318 print("Attaching to process %i..." % (options.attach_pid))
319 else:
320 if options.attach_wait:
321 print(
322 'Waiting for next to process named "%s" to launch...'
323 % (options.attach_name)
325 else:
326 print(
327 'Attaching to existing process named "%s"...'
328 % (options.attach_name)
330 process = target.Attach(attach_info, error)
332 # Make sure the launch went ok
333 if process and process.GetProcessID() != lldb.LLDB_INVALID_PROCESS_ID:
334 pid = process.GetProcessID()
335 print("Process is %i" % (pid))
336 if attach_info:
337 # continue process if we attached as we won't get an
338 # initial event
339 process.Continue()
341 listener = debugger.GetListener()
342 # sign up for process state change events
343 stop_idx = 0
344 done = False
345 while not done:
346 event = lldb.SBEvent()
347 if listener.WaitForEvent(options.event_timeout, event):
348 if lldb.SBProcess.EventIsProcessEvent(event):
349 state = lldb.SBProcess.GetStateFromEvent(event)
350 if state == lldb.eStateInvalid:
351 # Not a state event
352 print("process event = %s" % (event))
353 else:
354 print(
355 "process state changed event: %s"
356 % (lldb.SBDebugger.StateAsCString(state))
358 if state == lldb.eStateStopped:
359 if stop_idx == 0:
360 if launch_info:
361 print("process %u launched" % (pid))
362 run_commands(
363 command_interpreter, ["breakpoint list"]
365 else:
366 print("attached to process %u" % (pid))
367 for m in target.modules:
368 print(m)
369 if options.breakpoints:
370 for bp in options.breakpoints:
371 debugger.HandleCommand(
372 "_regexp-break %s" % (bp)
374 run_commands(
375 command_interpreter,
376 ["breakpoint list"],
378 run_commands(
379 command_interpreter, options.launch_commands
381 else:
382 if options.verbose:
383 print("process %u stopped" % (pid))
384 run_commands(
385 command_interpreter, options.stop_commands
387 stop_idx += 1
388 print_threads(process, options)
389 print("continuing process %u" % (pid))
390 process.Continue()
391 elif state == lldb.eStateExited:
392 exit_desc = process.GetExitDescription()
393 if exit_desc:
394 print(
395 "process %u exited with status %u: %s"
396 % (pid, process.GetExitStatus(), exit_desc)
398 else:
399 print(
400 "process %u exited with status %u"
401 % (pid, process.GetExitStatus())
403 run_commands(
404 command_interpreter, options.exit_commands
406 done = True
407 elif state == lldb.eStateCrashed:
408 print("process %u crashed" % (pid))
409 print_threads(process, options)
410 run_commands(
411 command_interpreter, options.crash_commands
413 done = True
414 elif state == lldb.eStateDetached:
415 print("process %u detached" % (pid))
416 done = True
417 elif state == lldb.eStateRunning:
418 # process is running, don't say anything,
419 # we will always get one of these after
420 # resuming
421 if options.verbose:
422 print("process %u resumed" % (pid))
423 elif state == lldb.eStateUnloaded:
424 print(
425 "process %u unloaded, this shouldn't happen"
426 % (pid)
428 done = True
429 elif state == lldb.eStateConnected:
430 print("process connected")
431 elif state == lldb.eStateAttaching:
432 print("process attaching")
433 elif state == lldb.eStateLaunching:
434 print("process launching")
435 else:
436 print("event = %s" % (event))
437 else:
438 # timeout waiting for an event
439 print(
440 "no process event for %u seconds, killing the process..."
441 % (options.event_timeout)
443 done = True
444 # Now that we are done dump the stdout and stderr
445 process_stdout = process.GetSTDOUT(1024)
446 if process_stdout:
447 print("Process STDOUT:\n%s" % (process_stdout))
448 while process_stdout:
449 process_stdout = process.GetSTDOUT(1024)
450 print(process_stdout)
451 process_stderr = process.GetSTDERR(1024)
452 if process_stderr:
453 print("Process STDERR:\n%s" % (process_stderr))
454 while process_stderr:
455 process_stderr = process.GetSTDERR(1024)
456 print(process_stderr)
457 process.Kill() # kill the process
458 else:
459 if error:
460 print(error)
461 else:
462 if launch_info:
463 print("error: launch failed")
464 else:
465 print("error: attach failed")
467 lldb.SBDebugger.Terminate()
470 if __name__ == "__main__":
471 main(sys.argv[1:])