Thanks to visit codestin.com
Credit goes to github.com

Skip to content

Commit 7a4bee6

Browse files
committed
[lldb/docs] Breakdown python reference into multiple files
This pages improve the LLDB website documentation readability and discoverability by breaking down the very long python-reference page into multiple subpages each explaining a specific topic. The long term goal is to have tutorials for every scripting extension. This also converts the pages to markdown, since it's easier to write. Signed-off-by: Med Ismail Bennani <[email protected]>
1 parent a5f6db4 commit 7a4bee6

9 files changed

+1333
-1922
lines changed

lldb/docs/use/python-reference.rst

Lines changed: 18 additions & 1123 deletions
Large diffs are not rendered by default.

lldb/docs/use/python.rst

Lines changed: 0 additions & 799 deletions
This file was deleted.
Lines changed: 62 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,62 @@
1+
# Accessing Script Documentation
2+
3+
The LLDB API is contained in a python module named lldb. A useful resource when
4+
writing Python extensions is the lldb Python classes reference guide.
5+
6+
The documentation is also accessible in an interactive debugger session with
7+
the following command:
8+
9+
```python3
10+
(lldb) script help(lldb)
11+
Help on package lldb:
12+
13+
NAME
14+
lldb - The lldb module contains the public APIs for Python binding.
15+
16+
FILE
17+
/System/Library/PrivateFrameworks/LLDB.framework/Versions/A/Resources/Python/lldb/__init__.py
18+
19+
DESCRIPTION
20+
...
21+
```
22+
23+
You can also get help using a module class name. The full API that is exposed
24+
for that class will be displayed in a man page style window. Below we want to
25+
get help on the lldb.SBFrame class:
26+
27+
```python3
28+
(lldb) script help(lldb.SBFrame)
29+
Help on class SBFrame in module lldb:
30+
31+
class SBFrame(builtins.object)
32+
| SBFrame(*args)
33+
|
34+
| Represents one of the stack frames associated with a thread.
35+
|
36+
| SBThread contains SBFrame(s). For example (from test/lldbutil.py), ::
37+
|
38+
| def print_stacktrace(thread, string_buffer = False):
39+
| '''Prints a simple stack trace of this thread.'''
40+
...
41+
```
42+
43+
Or you can get help using any python object, here we use the lldb.process
44+
object which is a global variable in the lldb module which represents the
45+
currently selected process:
46+
47+
```python3
48+
(lldb) script help(lldb.process)
49+
Help on SBProcess in module lldb object:
50+
51+
class SBProcess(builtins.object)
52+
| SBProcess(*args)
53+
|
54+
| Represents the process associated with the target program.
55+
|
56+
| SBProcess supports thread iteration. For example (from test/lldbutil.py), ::
57+
|
58+
| # ==================================================
59+
| # Utility functions related to Threads and Processes
60+
| # ==================================================
61+
...
62+
```
Lines changed: 85 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,85 @@
1+
# Breakpoint-Triggered Scripts
2+
3+
One very powerful use of the lldb Python API is to have a python script run
4+
when a breakpoint gets hit. Adding python scripts to breakpoints provides a way
5+
to create complex breakpoint conditions and also allows for smart logging and
6+
data gathering.
7+
8+
When your process hits a breakpoint to which you have attached some python
9+
code, the code is executed as the body of a function which takes three
10+
arguments:
11+
12+
```python3
13+
def breakpoint_function_wrapper(frame, bp_loc, internal_dict):
14+
# Your code goes here
15+
```
16+
17+
or:
18+
19+
```python3
20+
def breakpoint_function_wrapper(frame, bp_loc, extra_args, internal_dict):
21+
# Your code goes here
22+
```
23+
24+
| Argument | Type | Description |
25+
|----------|------|-------------|
26+
| `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`. |
27+
| `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. |
28+
| `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. |
29+
| `internal_dict` | `dict` | The python session dictionary as a standard python dictionary object. |
30+
31+
Optionally, a Python breakpoint command can return a value. Returning `False`
32+
tells LLDB that you do not want to stop at the breakpoint. Any other return
33+
value (including None or leaving out the return statement altogether) is akin
34+
to telling LLDB to actually stop at the breakpoint. This can be useful in
35+
situations where a breakpoint only needs to stop the process when certain
36+
conditions are met, and you do not want to inspect the program state manually
37+
at every stop and then continue.
38+
39+
An example will show how simple it is to write some python code and attach it
40+
to a breakpoint. The following example will allow you to track the order in
41+
which the functions in a given shared library are first executed during one run
42+
of your program. This is a simple method to gather an order file which can be
43+
used to optimize function placement within a binary for execution locality.
44+
45+
We do this by setting a regular expression breakpoint that will match every
46+
function in the shared library. The regular expression '.' will match any
47+
string that has at least one character in it, so we will use that. This will
48+
result in one lldb.SBBreakpoint object that contains an
49+
lldb.SBBreakpointLocation object for each function. As the breakpoint gets hit,
50+
we use a counter to track the order in which the function at this particular
51+
breakpoint location got hit. Since our code is passed the location that was
52+
hit, we can get the name of the function from the location, disable the
53+
location so we won't count this function again; then log some info and continue
54+
the process.
55+
56+
Note we also have to initialize our counter, which we do with the simple
57+
one-line version of the script command.
58+
59+
Here is the code:
60+
61+
```python3
62+
(lldb) breakpoint set --func-regex=. --shlib=libfoo.dylib
63+
Breakpoint created: 1: regex = '.', module = libfoo.dylib, locations = 223
64+
(lldb) script counter = 0
65+
(lldb) breakpoint command add --script-type python 1
66+
Enter your Python command(s). Type 'DONE' to end.
67+
> # Increment our counter. Since we are in a function, this must be a global python variable
68+
> global counter
69+
> counter += 1
70+
> # Get the name of the function
71+
> name = frame.GetFunctionName()
72+
> # Print the order and the function name
73+
> print('[%i] %s' % (counter, name))
74+
> # Disable the current breakpoint location so it doesn't get hit again
75+
> bp_loc.SetEnabled(False)
76+
> # No need to stop here
77+
> return False
78+
> DONE
79+
```
80+
81+
The breakpoint command add command above attaches a python script to breakpoint 1. To remove the breakpoint command:
82+
83+
```python3
84+
(lldb) breakpoint command delete 1
85+
```
Lines changed: 128 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,128 @@
1+
# Custom Breakpoint Resolvers
2+
3+
Another use of the Python API's in lldb is to create a custom breakpoint
4+
resolver.
5+
6+
It allows you to provide the algorithm which will be used in the breakpoint's
7+
search of the space of the code in a given Target to determine where to set the
8+
breakpoint locations - the actual places where the breakpoint will trigger. To
9+
understand how this works you need to know a little about how lldb handles
10+
breakpoints.
11+
12+
In lldb, a breakpoint is composed of three parts:
13+
1. the Searcher
14+
2. the Resolver,
15+
3. the Stop Options.
16+
17+
The Searcher and Resolver cooperate to determine how breakpoint locations are
18+
set and differ between each breakpoint type. Stop options determine what
19+
happens when a location triggers and includes the commands, conditions, ignore
20+
counts, etc. Stop options are common between all breakpoint types, so for our
21+
purposes only the Searcher and Resolver are relevant.
22+
23+
### Breakpoint Searcher
24+
25+
The Searcher's job is to traverse in a structured way the code in the current
26+
target. It proceeds from the Target, to search all the Modules in the Target,
27+
in each Module it can recurse into the Compile Units in that module, and within
28+
each Compile Unit it can recurse over the Functions it contains.
29+
30+
The Searcher can be provided with a SearchFilter that it will use to restrict
31+
this search. For instance, if the SearchFilter specifies a list of Modules, the
32+
Searcher will not recurse into Modules that aren't on the list. When you pass
33+
the -s modulename flag to break set you are creating a Module-based search
34+
filter. When you pass -f filename.c to break set -n you are creating a file
35+
based search filter. If neither of these is specified, the breakpoint will have
36+
a no-op search filter, so all parts of the program are searched and all
37+
locations accepted.
38+
39+
### Breakpoint Resolver
40+
41+
The Resolver has two functions:
42+
43+
The most important one is the callback it provides. This will get called at the
44+
appropriate time in the course of the search. The callback is where the job of
45+
adding locations to the breakpoint gets done.
46+
47+
The other function is specifying to the Searcher at what depth in the above
48+
described recursion it wants to be called. Setting a search depth also provides
49+
a stop for the recursion. For instance, if you request a Module depth search,
50+
then the callback will be called for each Module as it gets added to the
51+
Target, but the searcher will not recurse into the Compile Units in the module.
52+
53+
One other slight subtlety is that the depth at which you get called back is not
54+
necessarily the depth at which the SearchFilter is specified. For instance,
55+
if you are doing symbol searches, it is convenient to use the Module depth for
56+
the search, since symbols are stored in the module. But the SearchFilter might
57+
specify some subset of CompileUnits, so not all the symbols you might find in
58+
each module will pass the search. You don't need to handle this situation
59+
yourself, since SBBreakpoint::AddLocation will only add locations that pass the
60+
Search Filter. This API returns an SBError to inform you whether your location
61+
was added.
62+
63+
When the breakpoint is originally created, its Searcher will process all the
64+
currently loaded modules. The Searcher will also visit any new modules as they
65+
are added to the target. This happens, for instance, when a new shared library
66+
gets added to the target in the course of running, or on rerunning if any of
67+
the currently loaded modules have been changed. Note, in the latter case, all
68+
the locations set in the old module will get deleted and you will be asked to
69+
recreate them in the new version of the module when your callback gets called
70+
with that module. For this reason, you shouldn't try to manage the locations
71+
you add to the breakpoint yourself. Note that the Breakpoint takes care of
72+
deduplicating equal addresses in AddLocation, so you shouldn't need to worry
73+
about that anyway.
74+
75+
### Scripted Breakpoint Resolver
76+
77+
At present, when adding a ScriptedBreakpoint type, you can only provide a
78+
custom Resolver, not a custom SearchFilter.
79+
80+
The custom Resolver is provided as a Python class with the following methods:
81+
82+
| Name | Arguments | Description |
83+
|------|-----------|-------------|
84+
| `__init__` | `bkpt`: `lldb.SBBreakpoint` `extra_args`: `lldb.SBStructuredData` | This is the constructor for the new Resolver. `bkpt` is the breakpoint owning this Resolver. `extra_args` is an `SBStructuredData` object that the user can pass in when creating instances of this breakpoint. It is not required, but is quite handy. For instance if you were implementing a breakpoint on some symbol name, you could write a generic symbol name based Resolver, and then allow the user to pass in the particular symbol in the extra_args |
85+
| `__callback__` | `sym_ctx`: `lldb.SBSymbolContext` | This is the Resolver callback. The `sym_ctx` argument will be filled with the current stage of the search. For instance, if you asked for a search depth of lldb.eSearchDepthCompUnit, then the target, module and compile_unit fields of the sym_ctx will be filled. The callback should look just in the context passed in `sym_ctx` for new locations. If the callback finds an address of interest, it can add it to the breakpoint with the `SBBreakpoint.AddLocation` method, using the breakpoint passed in to the `__init__` method. |
86+
| `__get_depth__` | `None` | Specify the depth at which you wish your callback to get called. The currently supported options are: `lldb.eSearchDepthModule` `lldb.eSearchDepthCompUnit` `lldb.eSearchDepthFunction` For instance, if you are looking up symbols, which are stored at the Module level, you will want to get called back module by module. So you would want to return `lldb.eSearchDepthModule`. This method is optional. If not provided the search will be done at Module depth. |
87+
| `get_short_help` | `None` | This is an optional method. If provided, the returned string will be printed at the beginning of the description for this breakpoint. |
88+
89+
To define a new breakpoint command defined by this class from the lldb command
90+
line, use the command:
91+
92+
```
93+
(lldb) breakpoint set -P MyModule.MyResolverClass
94+
```
95+
96+
You can also populate the extra_args SBStructuredData with a dictionary of
97+
key/value pairs with:
98+
99+
```
100+
(lldb) breakpoint set -P MyModule.MyResolverClass -k key_1 -v value_1 -k key_2 -v value_2
101+
```
102+
103+
Although you can't write a scripted SearchFilter, both the command line and the
104+
SB API's for adding a scripted resolver allow you to specify a SearchFilter
105+
restricted to certain modules or certain compile units. When using the command
106+
line to create the resolver, you can specify a Module specific SearchFilter by
107+
passing the -s ModuleName option - which can be specified multiple times. You
108+
can also specify a SearchFilter restricted to certain compile units by passing
109+
in the -f CompUnitName option. This can also be specified more than once. And
110+
you can mix the two to specify "this comp unit in this module". So, for
111+
instance,
112+
113+
```
114+
(lldb) breakpoint set -P MyModule.MyResolverClass -s a.out
115+
```
116+
117+
will use your resolver, but will only recurse into or accept new locations in
118+
the module a.out.
119+
120+
Another option for creating scripted breakpoints is to use the
121+
SBTarget.BreakpointCreateFromScript API. This one has the advantage that you
122+
can pass in an arbitrary SBStructuredData object, so you can create more
123+
complex parametrizations. SBStructuredData has a handy SetFromJSON method which
124+
you can use for this purpose. Your __init__ function gets passed this
125+
SBStructuredData object. This API also allows you to directly provide the list
126+
of Modules and the list of CompileUnits that will make up the SearchFilter. If
127+
you pass in empty lists, the breakpoint will use the default "search
128+
everywhere,accept everything" filter.
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
# Detecting Patterns With Recognizers
2+
3+
Frame recognizers allow for retrieving information about special frames based
4+
on ABI, arguments or other special properties of that frame, even without
5+
source code or debug info. Currently, one use case is to extract function
6+
arguments that would otherwise be inaccessible, or augment existing arguments.
7+
8+
Adding a custom frame recognizer is done by implementing a Python class and
9+
using the `frame recognizer add` command. The Python class should implement the
10+
`get_recognized_arguments` method and it will receive an argument of type
11+
`lldb.SBFrame` representing the current frame that we are trying to recognize.
12+
The method should return a (possibly empty) list of `lldb.SBValue` objects that
13+
represent the recognized arguments.
14+
15+
An example of a recognizer that retrieves the file descriptor values from libc
16+
functions 'read', 'write' and 'close' follows:
17+
18+
```python3
19+
class LibcFdRecognizer:
20+
def get_recognized_arguments(self, frame: lldb.SBFrame):
21+
if frame.name in ["read", "write", "close"]:
22+
fd = frame.EvaluateExpression("$arg1").unsigned
23+
target = frame.thread.process.target
24+
value = target.CreateValueFromExpression("fd", "(int)%d" % fd)
25+
return [value]
26+
return []
27+
```
28+
29+
The file containing this implementation can be imported via `command script import`
30+
and then we can register this recognizer with `frame recognizer add`.
31+
32+
It's important to restrict the recognizer to the libc library (which is
33+
`libsystem_kernel.dylib` on macOS) to avoid matching functions with the same name
34+
in other modules:
35+
36+
```c++
37+
(lldb) command script import .../fd_recognizer.py
38+
(lldb) frame recognizer add -l fd_recognizer.LibcFdRecognizer -n read -s libsystem_kernel.dylib
39+
```
40+
41+
When the program is stopped at the beginning of the 'read' function in libc, we can view the recognizer arguments in 'frame variable':
42+
43+
```c++
44+
(lldb) b read
45+
(lldb) r
46+
Process 1234 stopped
47+
* thread #1, queue = 'com.apple.main-thread', stop reason = breakpoint 1.3
48+
frame #0: 0x00007fff06013ca0 libsystem_kernel.dylib`read
49+
(lldb) frame variable
50+
(int) fd = 3
51+
```

0 commit comments

Comments
 (0)