[docs] Update HowToReleaseLLVM documentation.
[llvm-project.git] / lldb / examples / python / process_events.py
blob16706d81b33d56f93e54ec9ad4792c24546cf2bc
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 +
34 '/../SharedFrameworks/LLDB.framework/Resources/Python'))
35 lldb_python_dirs.append(
36 xcode_dir + '/Library/PrivateFrameworks/LLDB.framework/Resources/Python')
37 lldb_python_dirs.append(
38 '/System/Library/PrivateFrameworks/LLDB.framework/Resources/Python')
39 success = False
40 for lldb_python_dir in lldb_python_dirs:
41 if os.path.exists(lldb_python_dir):
42 if not (sys.path.__contains__(lldb_python_dir)):
43 sys.path.append(lldb_python_dir)
44 try:
45 import lldb
46 except ImportError:
47 pass
48 else:
49 print('imported lldb from: "%s"' % (lldb_python_dir))
50 success = True
51 break
52 if not success:
53 print("error: couldn't locate the 'lldb' module, please set PYTHONPATH correctly")
54 sys.exit(1)
57 def print_threads(process, options):
58 if options.show_threads:
59 for thread in process:
60 print('%s %s' % (thread, thread.GetFrameAtIndex(0)))
63 def run_commands(command_interpreter, commands):
64 return_obj = lldb.SBCommandReturnObject()
65 for command in commands:
66 command_interpreter.HandleCommand(command, return_obj)
67 if return_obj.Succeeded():
68 print(return_obj.GetOutput())
69 else:
70 print(return_obj)
71 if options.stop_on_error:
72 break
75 def main(argv):
76 description = '''Debugs a program using the LLDB python API and uses asynchronous broadcast events to watch for process state changes.'''
77 epilog = '''Examples:
79 #----------------------------------------------------------------------
80 # Run "/bin/ls" with the arguments "-lAF /tmp/", and set a breakpoint
81 # at "malloc" and backtrace and read all registers each time we stop
82 #----------------------------------------------------------------------
83 % ./process_events.py --breakpoint malloc --stop-command bt --stop-command 'register read' -- /bin/ls -lAF /tmp/
85 '''
86 optparse.OptionParser.format_epilog = lambda self, formatter: self.epilog
87 parser = optparse.OptionParser(
88 description=description,
89 prog='process_events',
90 usage='usage: process_events [options] program [arg1 arg2]',
91 epilog=epilog)
92 parser.add_option(
93 '-v',
94 '--verbose',
95 action='store_true',
96 dest='verbose',
97 help="Enable verbose logging.",
98 default=False)
99 parser.add_option(
100 '-b',
101 '--breakpoint',
102 action='append',
103 type='string',
104 metavar='BPEXPR',
105 dest='breakpoints',
106 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.')
107 parser.add_option(
108 '-a',
109 '--arch',
110 type='string',
111 dest='arch',
112 help='The architecture to use when creating the debug target.',
113 default=None)
114 parser.add_option(
115 '--platform',
116 type='string',
117 metavar='platform',
118 dest='platform',
119 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".',
120 default=None)
121 parser.add_option(
122 '-l',
123 '--launch-command',
124 action='append',
125 type='string',
126 metavar='CMD',
127 dest='launch_commands',
128 help='LLDB command interpreter commands to run once after the process has launched. This option can be specified more than once.',
129 default=[])
130 parser.add_option(
131 '-s',
132 '--stop-command',
133 action='append',
134 type='string',
135 metavar='CMD',
136 dest='stop_commands',
137 help='LLDB command interpreter commands to run each time the process stops. This option can be specified more than once.',
138 default=[])
139 parser.add_option(
140 '-c',
141 '--crash-command',
142 action='append',
143 type='string',
144 metavar='CMD',
145 dest='crash_commands',
146 help='LLDB command interpreter commands to run in case the process crashes. This option can be specified more than once.',
147 default=[])
148 parser.add_option(
149 '-x',
150 '--exit-command',
151 action='append',
152 type='string',
153 metavar='CMD',
154 dest='exit_commands',
155 help='LLDB command interpreter commands to run once after the process has exited. This option can be specified more than once.',
156 default=[])
157 parser.add_option(
158 '-T',
159 '--no-threads',
160 action='store_false',
161 dest='show_threads',
162 help="Don't show threads when process stops.",
163 default=True)
164 parser.add_option(
165 '--ignore-errors',
166 action='store_false',
167 dest='stop_on_error',
168 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.",
169 default=True)
170 parser.add_option(
171 '-n',
172 '--run-count',
173 type='int',
174 dest='run_count',
175 metavar='N',
176 help='How many times to run the process in case the process exits.',
177 default=1)
178 parser.add_option(
179 '-t',
180 '--event-timeout',
181 type='int',
182 dest='event_timeout',
183 metavar='SEC',
184 help='Specify the timeout in seconds to wait for process state change events.',
185 default=lldb.UINT32_MAX)
186 parser.add_option(
187 '-e',
188 '--environment',
189 action='append',
190 type='string',
191 metavar='ENV',
192 dest='env_vars',
193 help='Environment variables to set in the inferior process when launching a process.')
194 parser.add_option(
195 '-d',
196 '--working-dir',
197 type='string',
198 metavar='DIR',
199 dest='working_dir',
200 help='The current working directory when launching a process.',
201 default=None)
202 parser.add_option(
203 '-p',
204 '--attach-pid',
205 type='int',
206 dest='attach_pid',
207 metavar='PID',
208 help='Specify a process to attach to by process ID.',
209 default=-1)
210 parser.add_option(
211 '-P',
212 '--attach-name',
213 type='string',
214 dest='attach_name',
215 metavar='PROCESSNAME',
216 help='Specify a process to attach to by name.',
217 default=None)
218 parser.add_option(
219 '-w',
220 '--attach-wait',
221 action='store_true',
222 dest='attach_wait',
223 help='Wait for the next process to launch when attaching to a process by name.',
224 default=False)
225 try:
226 (options, args) = parser.parse_args(argv)
227 except:
228 return
230 attach_info = None
231 launch_info = None
232 exe = None
233 if args:
234 exe = args.pop(0)
235 launch_info = lldb.SBLaunchInfo(args)
236 if options.env_vars:
237 launch_info.SetEnvironmentEntries(options.env_vars, True)
238 if options.working_dir:
239 launch_info.SetWorkingDirectory(options.working_dir)
240 elif options.attach_pid != -1:
241 if options.run_count == 1:
242 attach_info = lldb.SBAttachInfo(options.attach_pid)
243 else:
244 print("error: --run-count can't be used with the --attach-pid option")
245 sys.exit(1)
246 elif not options.attach_name is None:
247 if options.run_count == 1:
248 attach_info = lldb.SBAttachInfo(
249 options.attach_name, options.attach_wait)
250 else:
251 print("error: --run-count can't be used with the --attach-name option")
252 sys.exit(1)
253 else:
254 print('error: a program path for a program to debug and its arguments are required')
255 sys.exit(1)
257 # Create a new debugger instance
258 debugger = lldb.SBDebugger.Create()
259 debugger.SetAsync(True)
260 command_interpreter = debugger.GetCommandInterpreter()
261 # Create a target from a file and arch
263 if exe:
264 print("Creating a target for '%s'" % exe)
265 error = lldb.SBError()
266 target = debugger.CreateTarget(
267 exe, options.arch, options.platform, True, error)
269 if target:
271 # Set any breakpoints that were specified in the args if we are launching. We use the
272 # command line command to take advantage of the shorthand breakpoint
273 # creation
274 if launch_info and options.breakpoints:
275 for bp in options.breakpoints:
276 debugger.HandleCommand("_regexp-break %s" % (bp))
277 run_commands(command_interpreter, ['breakpoint list'])
279 for run_idx in range(options.run_count):
280 # Launch the process. Since we specified synchronous mode, we won't return
281 # from this function until we hit the breakpoint at main
282 error = lldb.SBError()
284 if launch_info:
285 if options.run_count == 1:
286 print('Launching "%s"...' % (exe))
287 else:
288 print('Launching "%s"... (launch %u of %u)' % (exe, run_idx + 1, options.run_count))
290 process = target.Launch(launch_info, error)
291 else:
292 if options.attach_pid != -1:
293 print('Attaching to process %i...' % (options.attach_pid))
294 else:
295 if options.attach_wait:
296 print('Waiting for next to process named "%s" to launch...' % (options.attach_name))
297 else:
298 print('Attaching to existing process named "%s"...' % (options.attach_name))
299 process = target.Attach(attach_info, error)
301 # Make sure the launch went ok
302 if process and process.GetProcessID() != lldb.LLDB_INVALID_PROCESS_ID:
304 pid = process.GetProcessID()
305 print('Process is %i' % (pid))
306 if attach_info:
307 # continue process if we attached as we won't get an
308 # initial event
309 process.Continue()
311 listener = debugger.GetListener()
312 # sign up for process state change events
313 stop_idx = 0
314 done = False
315 while not done:
316 event = lldb.SBEvent()
317 if listener.WaitForEvent(options.event_timeout, event):
318 if lldb.SBProcess.EventIsProcessEvent(event):
319 state = lldb.SBProcess.GetStateFromEvent(event)
320 if state == lldb.eStateInvalid:
321 # Not a state event
322 print('process event = %s' % (event))
323 else:
324 print("process state changed event: %s" % (lldb.SBDebugger.StateAsCString(state)))
325 if state == lldb.eStateStopped:
326 if stop_idx == 0:
327 if launch_info:
328 print("process %u launched" % (pid))
329 run_commands(
330 command_interpreter, ['breakpoint list'])
331 else:
332 print("attached to process %u" % (pid))
333 for m in target.modules:
334 print(m)
335 if options.breakpoints:
336 for bp in options.breakpoints:
337 debugger.HandleCommand(
338 "_regexp-break %s" % (bp))
339 run_commands(
340 command_interpreter, ['breakpoint list'])
341 run_commands(
342 command_interpreter, options.launch_commands)
343 else:
344 if options.verbose:
345 print("process %u stopped" % (pid))
346 run_commands(
347 command_interpreter, options.stop_commands)
348 stop_idx += 1
349 print_threads(process, options)
350 print("continuing process %u" % (pid))
351 process.Continue()
352 elif state == lldb.eStateExited:
353 exit_desc = process.GetExitDescription()
354 if exit_desc:
355 print("process %u exited with status %u: %s" % (pid, process.GetExitStatus(), exit_desc))
356 else:
357 print("process %u exited with status %u" % (pid, process.GetExitStatus()))
358 run_commands(
359 command_interpreter, options.exit_commands)
360 done = True
361 elif state == lldb.eStateCrashed:
362 print("process %u crashed" % (pid))
363 print_threads(process, options)
364 run_commands(
365 command_interpreter, options.crash_commands)
366 done = True
367 elif state == lldb.eStateDetached:
368 print("process %u detached" % (pid))
369 done = True
370 elif state == lldb.eStateRunning:
371 # process is running, don't say anything,
372 # we will always get one of these after
373 # resuming
374 if options.verbose:
375 print("process %u resumed" % (pid))
376 elif state == lldb.eStateUnloaded:
377 print("process %u unloaded, this shouldn't happen" % (pid))
378 done = True
379 elif state == lldb.eStateConnected:
380 print("process connected")
381 elif state == lldb.eStateAttaching:
382 print("process attaching")
383 elif state == lldb.eStateLaunching:
384 print("process launching")
385 else:
386 print('event = %s' % (event))
387 else:
388 # timeout waiting for an event
389 print("no process event for %u seconds, killing the process..." % (options.event_timeout))
390 done = True
391 # Now that we are done dump the stdout and stderr
392 process_stdout = process.GetSTDOUT(1024)
393 if process_stdout:
394 print("Process STDOUT:\n%s" % (process_stdout))
395 while process_stdout:
396 process_stdout = process.GetSTDOUT(1024)
397 print(process_stdout)
398 process_stderr = process.GetSTDERR(1024)
399 if process_stderr:
400 print("Process STDERR:\n%s" % (process_stderr))
401 while process_stderr:
402 process_stderr = process.GetSTDERR(1024)
403 print(process_stderr)
404 process.Kill() # kill the process
405 else:
406 if error:
407 print(error)
408 else:
409 if launch_info:
410 print('error: launch failed')
411 else:
412 print('error: attach failed')
414 lldb.SBDebugger.Terminate()
416 if __name__ == '__main__':
417 main(sys.argv[1:])