3 #----------------------------------------------------------------------
4 # Be sure to add the python path that points to the LLDB shared library.
6 # setenv PYTHONPATH /Applications/Xcode.app/Contents/SharedFrameworks/LLDB.framework/Resources/Python
8 # export PYTHONPATH=/Applications/Xcode.app/Contents/SharedFrameworks/LLDB.framework/Resources/Python
9 #----------------------------------------------------------------------
17 #----------------------------------------------------------------------
18 # Code that auto imports LLDB
19 #----------------------------------------------------------------------
21 # Just try for LLDB in case PYTHONPATH is already correctly setup
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)
31 lldb_python_dirs
.append(
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')
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
)
49 print('imported lldb from: "%s"' % (lldb_python_dir
))
53 print("error: couldn't locate the 'lldb' module, please set PYTHONPATH correctly")
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())
71 if options
.stop_on_error
:
76 description
= '''Debugs a program using the LLDB python API and uses asynchronous broadcast events to watch for process state changes.'''
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/
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]',
97 help="Enable verbose logging.",
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.')
112 help='The architecture to use when creating the debug target.',
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".',
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.',
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.',
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.',
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.',
160 action
='store_false',
162 help="Don't show threads when process stops.",
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.",
176 help='How many times to run the process in case the process exits.',
182 dest
='event_timeout',
184 help='Specify the timeout in seconds to wait for process state change events.',
185 default
=lldb
.UINT32_MAX
)
193 help='Environment variables to set in the inferior process when launching a process.')
200 help='The current working directory when launching a process.',
208 help='Specify a process to attach to by process ID.',
215 metavar
='PROCESSNAME',
216 help='Specify a process to attach to by name.',
223 help='Wait for the next process to launch when attaching to a process by name.',
226 (options
, args
) = parser
.parse_args(argv
)
235 launch_info
= lldb
.SBLaunchInfo(args
)
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
)
244 print("error: --run-count can't be used with the --attach-pid option")
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
)
251 print("error: --run-count can't be used with the --attach-name option")
254 print('error: a program path for a program to debug and its arguments are required')
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
264 print("Creating a target for '%s'" % exe
)
265 error
= lldb
.SBError()
266 target
= debugger
.CreateTarget(
267 exe
, options
.arch
, options
.platform
, True, error
)
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
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()
285 if options
.run_count
== 1:
286 print('Launching "%s"...' % (exe
))
288 print('Launching "%s"... (launch %u of %u)' % (exe
, run_idx
+ 1, options
.run_count
))
290 process
= target
.Launch(launch_info
, error
)
292 if options
.attach_pid
!= -1:
293 print('Attaching to process %i...' % (options
.attach_pid
))
295 if options
.attach_wait
:
296 print('Waiting for next to process named "%s" to launch...' % (options
.attach_name
))
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
))
307 # continue process if we attached as we won't get an
311 listener
= debugger
.GetListener()
312 # sign up for process state change events
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
:
322 print('process event = %s' % (event
))
324 print("process state changed event: %s" % (lldb
.SBDebugger
.StateAsCString(state
)))
325 if state
== lldb
.eStateStopped
:
328 print("process %u launched" % (pid
))
330 command_interpreter
, ['breakpoint list'])
332 print("attached to process %u" % (pid
))
333 for m
in target
.modules
:
335 if options
.breakpoints
:
336 for bp
in options
.breakpoints
:
337 debugger
.HandleCommand(
338 "_regexp-break %s" % (bp
))
340 command_interpreter
, ['breakpoint list'])
342 command_interpreter
, options
.launch_commands
)
345 print("process %u stopped" % (pid
))
347 command_interpreter
, options
.stop_commands
)
349 print_threads(process
, options
)
350 print("continuing process %u" % (pid
))
352 elif state
== lldb
.eStateExited
:
353 exit_desc
= process
.GetExitDescription()
355 print("process %u exited with status %u: %s" % (pid
, process
.GetExitStatus(), exit_desc
))
357 print("process %u exited with status %u" % (pid
, process
.GetExitStatus()))
359 command_interpreter
, options
.exit_commands
)
361 elif state
== lldb
.eStateCrashed
:
362 print("process %u crashed" % (pid
))
363 print_threads(process
, options
)
365 command_interpreter
, options
.crash_commands
)
367 elif state
== lldb
.eStateDetached
:
368 print("process %u detached" % (pid
))
370 elif state
== lldb
.eStateRunning
:
371 # process is running, don't say anything,
372 # we will always get one of these after
375 print("process %u resumed" % (pid
))
376 elif state
== lldb
.eStateUnloaded
:
377 print("process %u unloaded, this shouldn't happen" % (pid
))
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")
386 print('event = %s' % (event
))
388 # timeout waiting for an event
389 print("no process event for %u seconds, killing the process..." % (options
.event_timeout
))
391 # Now that we are done dump the stdout and stderr
392 process_stdout
= process
.GetSTDOUT(1024)
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)
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
410 print('error: launch failed')
412 print('error: attach failed')
414 lldb
.SBDebugger
.Terminate()
416 if __name__
== '__main__':