A RPC server interface for the LLDB Python bridge.
Principally the lldb debugger is usable as a python module but on many systems it is compiled against the system's default Python, if you want to use another Python version there will be incompatability problems.
Usually you don't want to have a debugger running in-process because if that crashes, all your Python code will crash with it. So we wrapped the lldb interface into an XMLRPC server (as that's in the standard lib of Python). So when the debugger crashes the worst thing that could happen would be an exception on the receiver side.
Run the lldb_server.py
with the Python installation that the lldb
debugger was build against (usually it suffices to make lldb_server.py
executable and start it directly).
lldb_server.py
has two unnamed command line parameters:
- The first one is a path to the lldb python module. If you're using the open Source Version of Swift on OSX you'll need the following path: /Library/Developer/Toolchains/swift-latest.xctoolchain/System/Library/PrivateFrameworks/LLDB.framework/Resources/Python On Linux you will need something like: /home/user/swift/usr/lib/python2.7/site-packages
- The second one is the port to start the server on. It will always listen on the localhost loopback interface only.
import threading
import xmlrpc
from subprocess import Popen
lldb_server_executable = "lldb_server.py"
lldb_path = "/home/user/swift/usr/lib/python2.7/site-packages"
port = 12345
args = ['/usr/bin/python', lldb_server_executable, lldb_path, str(port)]
p = Popen(args, cwd=path)
threading.Thread(
target=debugger_thread,
name='debugger_thread',
args=(p, port)
).start()
def debugger_thread(p, port):
lldb = xmlrpc.ServerProxy('http://localhost:' + str(port), allow_none=True)
lldb.prepare(
executable_path # executable to run
[], # cmdline args
None, # environment
None, # executable search path
"." # working dir
)
# Do whatever you want here
lldb.shutdown_server()
if p:
p.wait()
import xmlrpc.client
import threading
from subprocess import Popen
lldb_server_executable = "lldb_server.py"
lldb_path = "/home/user/swift/usr/lib/python2.7/site-packages"
port = 12345
args = ['/usr/bin/python', lldb_server_executable, lldb_path, str(port)]
p = Popen(args, cwd=path)
threading.Thread(
target=debugger_thread,
name='debugger_thread',
args=(p, port)
).start()
def debugger_thread(p, port):
lldb = xmlrpc.client.ServerProxy('http://localhost:' + str(port), allow_none=True)
lldb.prepare(
executable_path # executable to run
[], # cmdline args
None, # environment
None, # executable search path
"." # working dir
)
# Do whatever you want here
lldb.shutdown_server()
if p:
p.wait()
This command loads an executable and sets its startup parameters. The executable is started and immediately halted on the first instruction.
Parameters:
- 1:
executable
, string, the executable to load (make sure it has been compiled with debug symbols) - 2:
params
, array of strings, command line parameters - 3:
environment
, array of strings, environment variables to set (format like in C envp:Name=Value
) - 4:
path
, array of strings, directories to add to search path - 5:
work_dir
, string, working directory
This starts or continues execution, it takes no parameters.
This interrupts execution, it takes no parameters.
This makes a single source-code line step, stepping into function calls as it encounters one, it takes no parameters.
This makes a single source-code line step keeping the current execution context (e.g. stepping over function calls), it takes no parameters.
This continues running until the current stack frame is popped (e.g. a return call in a function, etc.), it takes no parameters.
This stopps execution and exits the lldb server (target process is killed with SIGKILL
), it takes no parameters.
This command has no parameters and will exit the server process, do not try to call any other RPC after this.
Fetch current debugger status, returns a string. Common return values:
launching
: Executable is launching, libraries are loadedrunning
: Executable is runningstopped
+ reason: Executable has stopped, see below for reasonsstepping
: Currently executing a step commandcrashed
: Executable has crashedexited
: Executable has exited (shown only very briefly as the server exits on this state)
Uncommon return values (may happen when the user uses the console)
invalid
: Invalid status, internal errorunloaded
: Executable unloadedconnected
: Connected to external debug server (remote debugger)attaching
: Attaching to external debug server or already running processdetached
: Detached from process or debug serversuspended
: Process that the debugger has been attached to has been suspendedunknown
+ optional error code
Stop reasons, will be appended to stopped
state with a comma:
breakpoint
: Stopped because of breakpointwatchpoint
: Briefly interrupted because of watchpointsignal
: Stopped because of UNIX signal, look for this state when waiting for theprepare
command to finishexception
: Exception was thrown (mostly used in ObjC and C++)invalid
: Internal errornone
: No reason, probably the user called an interrupt commandtrace
: Trace point hitexec
: Target calledexec
plan_complete
: User initiated action completed (status is used after step commands)thread_exit
: Selected thread exitedinstrumentation
: Instrumentation called a stop action (dtrace, etc.)
Fetches all data that has been buffered for stdout
, takes no parameter, returns a string. If there has nothing been buffered, returns empty string.
Fetches all data that has been buffered for stderr
, takes no parameter, returns a string. If there has nothing been buffered, returns empty string.
Send a string to stdin
of target. Takes a string as parameter.
Fetch a list of all defined breakpoints. Takes no parameter.
Return value is an array of dictionary objects with the following keys:
file
: string, full path to the file the breakpoint is defined forline
: integer, line number in the fileenabled
: boolean, enabled state of the breakpointcondition
: string, condition when the breakpoint actually breaksignore_count
: integer, ignore the breakpoint n times before triggeringid
: integer, breakpoint id
Set a breakpoint for a specific file and line. Parameters:
- 1:
filename
: string, full file path - 2:
line_number
: integer, line number - 3:
condition
: string, condition when the breakpoint triggers orNone
- 4:
ignore_count
: integer, how often to ignore the breakpoint until triggering orNone
Delete a breakpoint. Parameters:
- 1:
id
: integer, breakpoint id to delete
Enable a breakpoint. Parameters:
- 1:
id
: integer, breakpoint id to enable
Disable a breakpoint. Parameters:
- 1:
id
: integer, breakpoint id to disable
Disable all breakpoints, takes no parameters.
Enable all breakpoints, takes no parameters.
Delete all breakpoints, takes no parameters.
Temporarily disable all breakpoints, saves enabled state internally, takes no parameters.
Re-Enable temporarily disabled breakpoints, pops the internal state, takes not parameters.
Get backtraces for all active threads, takes no parameters.
Return value is a dictionary which keys are the stringified thread IDs, values are dictionaries, union of thread info (see get_threads
) and a bt
component.
bt
contains an array of stack frames, dictionaries on their own, with the following keys:
Resolvable frames (e.g. debug symbols available):
address
: string, stringified load address (to avoid integer overflows of Python's XMLRPC implementation)module
: string, module namefunction
: string, function namefile
: string, full path to fileline
: integer, line numbercolumn
: integer, column in line if available, else 0inlined
: boolean, has this function been inlinedarguments
: dictionary, key = argument name, value = argument value
Unresolvable stack frames (no debug symbols):
address
: string, stringified load address (to avoid integer overflows of Python's XMLRPC implementation)module
: string, module namesymbol
: string, symbol nameoffset
: string, stringified instruction offset into the symbol
Get backtrace of currently selected thread, takes no parameters.
Return value is a dictionary. The dict is a union of thread info and a bt
component. For format see get_threads
and get_backtrace
Get thread info for all active threads, takes no parameters.
Return value is an array of dictionaries with the following keys:
id
, string, stringified thread id (to avoid integer overflows of Python's XMLRPC implementation)index
, integer, thread indexname
, string, thread name orNone
if none was suppliedqueue
, string, GCD queue if thread belongs to queue orNone
stop_reason
: string, stop reason (seeget_status
for possible values) orrunning
num_frames
: integer, number of stack framesselected
: boolean, True if this is the selected thread
Select a thread ID as the current thread. Takes one parameter:
- 1:
id
: string, thread id as you got them fromget_threads
Returns thread info for currently selected thread. For format of return value see get_threads
.
Get function arguments for a specific thread and stack frame. Parameters:
- 1:
thread_id
: string, the thread id you got fromget_threads
- 2:
frame_index
: integer, index of the stack frame to query
Return value is a dictionary. Keys are the argument names (always strings), values the argument values (lldb description strings).
Get local variables for a specific thread and stack frame. Parameters and return values are the same as in get_arguments
.
Get all variables (local, static, global) for a specific thread and stack frame. Parameters and return values are the same as in get_arguments
.
Execute a lldb command as if the user typed it into the console. Takes one parameter, a string with the command. Return value is a dictionary with the following keys:
succeeded
: boolean, was the command successful?output
: string, command output orNone
if command failederror
: string, error output orNone
if command succeeded