mirror of
https://github.com/intel/llvm.git
synced 2026-01-23 07:58:23 +08:00
85 lines
4.4 KiB
Markdown
85 lines
4.4 KiB
Markdown
|
|
# 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:
|
||
|
|
|
||
|
|
```python3
|
||
|
|
def breakpoint_function_wrapper(frame, bp_loc, internal_dict):
|
||
|
|
# Your code goes here
|
||
|
|
```
|
||
|
|
|
||
|
|
or:
|
||
|
|
|
||
|
|
```python3
|
||
|
|
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:
|
||
|
|
|
||
|
|
```python3
|
||
|
|
(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:
|
||
|
|
|
||
|
|
```python3
|
||
|
|
(lldb) breakpoint command delete 1
|
||
|
|
```
|