Breakpoint-Triggered Scripts#

One very powerful use of the lldb Python API is to have a python script 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.

When your process hits a breakpoint to which you have attached some python code, the code is executed as the body of a function which takes three arguments:

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

or:

def breakpoint_function_wrapper(frame, bp_loc, extra_args, internal_dict):
   # Your code goes here

Argument

Type

Description

frame

lldb.SBFrame

The current stack frame where the breakpoint got hit. 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.

extra_args

lldb.SBStructuredData

Optional If your breakpoint callback function takes this extra parameter, then when the callback gets added to a breakpoint, its contents can parametrize this use of the callback. For instance, instead of writing a callback that stops when the caller is โ€œFooโ€, you could take the function name from a field in the extra_args, making the callback more general. The -k and -v options to breakpoint command add will be passed as a Dictionary in the extra_args parameter, or you can provide it with the SB APIโ€™s.

internal_dict

dict

The python session dictionary as a standard python dictionary object.

Optionally, a Python breakpoint command can return a value. Returning False tells LLDB that you do not want to stop at the breakpoint. Any other return value (including None or leaving out the return statement altogether) is akin to telling LLDB to actually stop at the breakpoint. This can be useful in situations where a breakpoint only needs to stop the process when certain conditions are met, and you do not want to inspect the program state manually at every stop and then continue.

An example will show how simple it is to write some python code and attach it to a breakpoint. The following example will allow you to track the order in which the functions in a given shared library are first executed during one run of your program. This is a simple method to gather an order file which can be used to optimize function placement within a binary for execution locality.

We do this by setting a regular expression breakpoint that will match every function in the shared library. The regular expression โ€˜.โ€™ will match any string that has at least one character in it, so we will use that. This will result in one lldb.SBBreakpoint object that contains an lldb.SBBreakpointLocation object for each function. As the breakpoint gets hit, we use a counter to track the order in which the function at this particular breakpoint location got hit. Since our code is passed the location that was hit, we can get the name of the function from the location, disable the location so we wonโ€™t count this function again; then log some info and continue the process.

Note we also have to initialize our counter, which we do with the simple one-line version of the script command.

Here is the code:

(lldb) breakpoint set --func-regex=. --shlib=libfoo.dylib
Breakpoint created: 1: regex = '.', module = libfoo.dylib, locations = 223
(lldb) script counter = 0
(lldb) breakpoint command add --script-type python 1
Enter your Python command(s). Type 'DONE' to end.
> # Increment our counter.  Since we are in a function, this must be a global python variable
> global counter
> counter += 1
> # Get the name of the function
> name = frame.GetFunctionName()
> # Print the order and the function name
> print('[%i] %s' % (counter, name))
> # Disable the current breakpoint location so it doesn't get hit again
> bp_loc.SetEnabled(False)
> # No need to stop here
> return False
> DONE

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

(lldb) breakpoint command delete 1