LLDB Python FAQ

Introduction

The entire LLDB API is available through a script bridging interface in Python. Python can be used as an embedded script interpreter, or it can be used directly from python at the command line.

Embedded Python Interpreter

The embedded python interpreter can be accessed in a variety of way from within LLDB. The easiest way is to type script command prompt:

(lldb) script
Python Interactive Interpreter. To exit, type 'quit()', 'exit()' or Ctrl-D.
>>> 2+3
5
>>> hex(12345)
'0x3039'
>>> 

This drops you into the embedded python interpreter. There are a some convenience variables that are set for you in the lldb python module that refer to the current program and debugger state:

Variable Type Description
lldb.debugger lldb.SBDebugger A module global variable containing the current debugger object. The type is a lldb.SBDebugger object and it contains a reference to the debegger object that owns the command interpreter and all targets in your debug session.
lldb.target lldb.SBTarget A module global variable containing the currently selected target. The type is a lldb.SBTarget object and the object will only be valid if there is a current target. The target select <target-index> commmand can be used to change the currently selected target.
lldb.process lldb.SBProcess A module global variable containing the current process. The type is a lldb.SBProcess object and the object will only be valid if there is a current target and that target has a process.
lldb.thread lldb.SBThread A module global variable containing the current thread. The type is a lldb.SBThread object and the object will only be valid if the process has threads, and if the process has a thread selected. A thread is always selected in the command interpreter when a target stops. The thread select <thread-index> commmand can be used to change the currently selected thread.
lldb.frame lldb.SBFrame A module global variable containing the current stack frame. The type is a lldb.SBFrame object and the object will only be valid if the thread is stopped and has a frame selected. A stack frame is always selected in the command interpreter when a target stops. The frame select <frame-index> commmand can be used to change the currently selected thread.

One in the embedded interpreter, these objects can be used. Almost all of the lldb.SB objects are able to briefly describe themselves by printing them:

(lldb) script
Python Interactive Interpreter. To exit, type 'quit()', 'exit()' or Ctrl-D.
>>> print lldb.debugger
Debugger (instance: "debugger_1", id: 1)
>>> print lldb.target
a.out
>>> print lldb.process
SBProcess: pid = 59289, state = stopped, threads = 1, executable = a.out
>>> print lldb.thread
SBThread: tid = 0x1f03
>>> print lldb.frame
frame #0: 0x0000000100000bb6 a.out main + 54 at main.c:16

Running a Python script when a breakpoint gets hit

A python script can be run when a breakpoint gets hit. Adding python scripts to breakpoints provides a way to create complex breakpoint conditions and also allows for smart logging and data gathering.

A python function gets run when a breakpoint, and this function has two arguments:

def breakpoint_function(frame, bp_loc):
  # Your code goes here

Argument Type Description
frame lldb.SBFrame The current stack frame where the breakpoint got hit. The type is a lldb.SBFrame object and the object will always be valid. This frame argument might not match the currently selected stack frame found in the lldb module global variable lldb.frame.
bp_loc lldb.SBBreakpointLocation The breakpoint location that just got hit. Breakpoints are represented by lldb.SBBreakpoint objects. These breakpoint objects can have one or more locations. These locations are represented by lldb.SBBreakpointLocation objects.

Now we are ready to create a python function and attach it to a breakpoint. The following example will wllow you to create an order file for a shared library. We do this by setting a regular exprsssion breakpoint at every function in a shared library. The regular expression we will use is '.' which will match any function that has at least any character in the function name. This will result in one lldb.SBBreakpoint object that contains many lldb.SBBreakpointLocation objects. As the breakpoint continually gets hit, we use the hit count on the main lldb.SBBreakpoint to tell us the breakpoint hit number, and we disable the location (not the main breakpoint) on the lldb.SBBreakpointLocation object. Then we log some info and continue the process.

(lldb) breakpoint set --func-regex=. --shlib=libfoo.dylib
Breakpoint created: 1: regex = '.', module = libfoo.dylib, locations = 223
(lldb) breakpoint command add --script-type python 1
Enter your Python command(s). Type 'DONE' to end.
> # Get the hit count of the main breakpoint
> hit_count = bp_loc.GetBreakpoint().GetHitCount()
> # Get the name of the function
> name = frame.GetFunctionName()
> # Print the order and the function name
> print '[%i] %s' % (hit_count, name)
> # Disable the current breakpoint location so it doesn't get hit again
> bp_loc.SetEnabled(False)
> # How continue the process
> frame.GetThread().GetProcess().Continue()
> DONE

The breakpoint command add command above attaches a python script to breakpoint 1. To remove the breakpoint command:

(lldb) breakpoint command delete 1

Create a new LLDB command using a python function

Python functions can be used to create new commands that the LLDB command interpreter doesn't have. This provides a very flexible and easy way to extend LLDB to meet your debugging requirements.

A python function that implements a new LDB command has four arguments:

def Symbolicate(debugger, command, result, dict): SymbolicateCrashLog (command.split())

def command_function(debugger, command, result, dict):
          # Your code goes here
        

Argument Type Description
debugger lldb.SBDebugger The current debugger object.
command python string A python string containing all arguments for your command. If you need to chop up the arguments try using the shlex module's shlex.split(command) to properly extract the arguments.
result lldb.SBCommandReturnObject A return object where you can indicate the success or failure of your command. You can also provide information for the command result by printing data into it. You can also just print data as you normally would in a python script and the outout will show up.
dict python dict object The dictionary for the current embedded script session which contains all variables and functions.

Now we can create a module called ls.py that will implement a function that can be used by LLDB's python command code:

#!/usr/bin/python

import lldb
import commands
import optparse
import shlex

def ls(debugger, command, result, dict):
    print commands.getoutput('/bin/ls %s' % command)

# Any code that isn't in a function in python gets run when the module is loaded
if lldb.debugger:
    # This script is being run from LLDB in the emabedded command interpreter
    # lets register the 'ls' command with the command interpreter automatically!
    lldb.debugger.HandleCommand('command script add -f ls.ls ls')
    print 'The "ls" python command has been installed and is ready for use.'

Now we can load the module into LLDB and use it

% lldb
(lldb) script import ls
The "ls" python command has been installed and is ready for use.
(lldb) ls -l /tmp/
total 365848
-rw-r--r--@  1 someuser  wheel         6148 Jan 19 17:27 .DS_Store
-rw-------   1 someuser  wheel         7331 Jan 19 15:37 crash.log

A template has been created in the source repository that can help you to create lldb command quickly:

cmdtemplate.py

Using the lldb.py module in python

LLDB has all of its core code build into a shared library which gets used by the lldb command line application. On Mac OS X this shared library is a framework: LLDB.framework and on other unix variants the program is a shared library lldb.so. The LLDB.framework contains the lldb.py module and you will need to tell python where to look in order to find this module. This is done by setting the PYTHONPATH environment variable contain a path to the directory that contains the lldb.py python module:

For csh and tcsh:

% setenv PYTHONPATH /Developer/Library/PrivateFrameworks/LLDB.framework/Resources/Python

For sh and bash:

% export PYTHONPATH=/Developer/Library/PrivateFrameworks/LLDB.framework/Resources/Python

Now your python scripts are ready to import the lldb module. Below is a python script that will launch a program from the current working directory called "a.out", set a breakpoint at "main", and then run and hit the breakpoint, and print the process, thread and frame objects if the process stopped:

#!/usr/bin/python

import lldb

# Set the path to the executable to debug
exe = "./a.out"

# Create a new debugger instance
debugger = lldb.SBDebugger.Create()

# When we step or continue, don't return from the function until the process 
# stops. We do this by setting the async mode to false.
debugger.SetAsync (False)

# Create a target from a file and arch
print "Creating a target for '%s'" % exe

target = debugger.CreateTargetWithFileAndArch (exe, lldb.LLDB_ARCH_DEFAULT)

if target:
    # If the target is valid set a breakpoint at main
    main_bp = target.BreakpointCreateByName ("main", target.GetExecutable().GetFilename());

    print main_bp

    # Launch the process. Since we specified synchronous mode, we won't return
    # from this function until we hit the breakpoint at main
    process = target.LaunchSimple (None, None, os.getcwd())
    
    # Make sure the launch went ok
    if process:
        # Print some simple process info
        state = process.GetState ()
        print process
        if state == lldb.eStateStopped:
        # Get the first thread
        thread = process.GetThreadAtIndex (0)
        if thread:
            # Print some simple thread info
            print thread
            # Get the first frame
            frame = thread.GetFrameAtIndex (0)
            if frame:
                # Print some simple frame info
                print frame
                function = frame.GetFunction()
                # See if we have debug info (a function)
                if function:
                    # We do have a function, print some info for the function
                    print function
                    # Now get all instructions for this function and print them
                    insts = function.GetInstructions(target)
                    disassemble_instructions (insts)
                else:
                    # See if we have a symbol in the symbol table for where we stopped
                    symbol = frame.GetSymbol();
                    if symbol:
                        # We do have a symbol, print some info for the symbol
                        print symbol