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(
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"
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
)
52 print('imported lldb from: "%s"' % (lldb_python_dir
))
57 "error: couldn't locate the 'lldb' module, please set PYTHONPATH correctly"
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())
76 if options
.stop_on_error
:
81 description
= """Debugs a program using the LLDB python API and uses asynchronous broadcast events to watch for process state changes."""
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/
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]",
103 help="Enable verbose logging.",
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.',
120 help="The architecture to use when creating the debug target.",
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".',
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.",
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.",
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.",
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.",
174 action
="store_false",
176 help="Don't show threads when process stops.",
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.",
192 help="How many times to run the process in case the process exits.",
199 dest
="event_timeout",
201 help="Specify the timeout in seconds to wait for process state change events.",
202 default
=lldb
.UINT32_MAX
,
211 help="Environment variables to set in the inferior process when launching a process.",
219 help="The current working directory when launching a process.",
228 help="Specify a process to attach to by process ID.",
236 metavar
="PROCESSNAME",
237 help="Specify a process to attach to by name.",
245 help="Wait for the next process to launch when attaching to a process by name.",
249 (options
, args
) = parser
.parse_args(argv
)
258 launch_info
= lldb
.SBLaunchInfo(args
)
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
)
267 print("error: --run-count can't be used with the --attach-pid option")
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
)
273 print("error: --run-count can't be used with the --attach-name option")
277 "error: a program path for a program to debug and its arguments are required"
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
288 print("Creating a target for '%s'" % exe
)
289 error
= lldb
.SBError()
290 target
= debugger
.CreateTarget(exe
, options
.arch
, options
.platform
, True, error
)
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
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()
307 if options
.run_count
== 1:
308 print('Launching "%s"...' % (exe
))
311 'Launching "%s"... (launch %u of %u)'
312 % (exe
, run_idx
+ 1, options
.run_count
)
315 process
= target
.Launch(launch_info
, error
)
317 if options
.attach_pid
!= -1:
318 print("Attaching to process %i..." % (options
.attach_pid
))
320 if options
.attach_wait
:
322 'Waiting for next to process named "%s" to launch...'
323 % (options
.attach_name
)
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
))
337 # continue process if we attached as we won't get an
341 listener
= debugger
.GetListener()
342 # sign up for process state change events
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
:
352 print("process event = %s" % (event
))
355 "process state changed event: %s"
356 % (lldb
.SBDebugger
.StateAsCString(state
))
358 if state
== lldb
.eStateStopped
:
361 print("process %u launched" % (pid
))
363 command_interpreter
, ["breakpoint list"]
366 print("attached to process %u" % (pid
))
367 for m
in target
.modules
:
369 if options
.breakpoints
:
370 for bp
in options
.breakpoints
:
371 debugger
.HandleCommand(
372 "_regexp-break %s" % (bp
)
379 command_interpreter
, options
.launch_commands
383 print("process %u stopped" % (pid
))
385 command_interpreter
, options
.stop_commands
388 print_threads(process
, options
)
389 print("continuing process %u" % (pid
))
391 elif state
== lldb
.eStateExited
:
392 exit_desc
= process
.GetExitDescription()
395 "process %u exited with status %u: %s"
396 % (pid
, process
.GetExitStatus(), exit_desc
)
400 "process %u exited with status %u"
401 % (pid
, process
.GetExitStatus())
404 command_interpreter
, options
.exit_commands
407 elif state
== lldb
.eStateCrashed
:
408 print("process %u crashed" % (pid
))
409 print_threads(process
, options
)
411 command_interpreter
, options
.crash_commands
414 elif state
== lldb
.eStateDetached
:
415 print("process %u detached" % (pid
))
417 elif state
== lldb
.eStateRunning
:
418 # process is running, don't say anything,
419 # we will always get one of these after
422 print("process %u resumed" % (pid
))
423 elif state
== lldb
.eStateUnloaded
:
425 "process %u unloaded, this shouldn't happen"
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")
436 print("event = %s" % (event
))
438 # timeout waiting for an event
440 "no process event for %u seconds, killing the process..."
441 % (options
.event_timeout
)
444 # Now that we are done dump the stdout and stderr
445 process_stdout
= process
.GetSTDOUT(1024)
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)
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
463 print("error: launch failed")
465 print("error: attach failed")
467 lldb
.SBDebugger
.Terminate()
470 if __name__
== "__main__":