The LLDB Debugger - Part 2: Breakpoints
lldb debug breakpoint Estimated reading time: 12 minutesTo correctly prepare the application logic we should define some instructions and execute them at a certain moment, in other words - execute instructions. But, sometimes it’s hard to tell if it works in a way, we expect or not.
A great helper here - a breakpoint
- an ability of our debugger to stop the code execution at some point (with or without some conditions).
Knowing the main commands and how we can use them, can improve u’r understanding of the code and u’r performance as a developer.
Articles in this series:
- The LLDB Debugger - Part 1: Basics
- The LLDB Debugger - Part 2: Breakpoints
- The LLDB Debugger - Part 3: Watchpoint
The breakpoint
A breakpoint is a great ability for us, developers. Last time, I described some basic usage of breakpoints
within lldb
, so check it out for basic usage.
Check this official doc for all available options
man
If u don’t know how some commands work, the best option is to try it out and check the man page for it.
So, if u type:
(lldb) help breakpoint
The output will provide for u all necessary information:
U can go on and try to ask for help for each subcommand:
(lldb) help br set
and so on.
image
Looking into man
pages is a good approach, but sometimes u just want to get the required information and that’s it.
To do so, we can use additional details about our code within breakpoints. How do get them? Well, our code is organized in different targets and targets contain different modules. So the idea here is quite simple - we should find interesting details about modules where our code is declared and then, using them, add breakpoints specific to some concrete situation or event.
Luckily for us, there is a bunch of great commands for this (commands for accessing information for one or more target modules) - target modules
. The abbreviation for this - is image
.
image
has subcommands that can do exactly what we want - lookup
:
lookup -- Look up information within executable and
dependent shared library images.
To get information about some method use the next command:
(lldb) image lookup -n "<SymbolName>"
As result, u can get something like this:
different options can improve lookup, for example
-r
- regex
in output for the command above u can see 3 components:
1) place where this method declared (path) 2) address 3) summary with symbol info and module name
In Obj-C, the symbol is just a method declaration with a sign -
for instance method or +
for type methods. One more example: [UILabel setText:]
or -[UIImage setImage:]
.
It’s good to mention, that there are few special symbols for UIKit
(similar exists for AppKit
. Check this article, where I cover few of the most useful as for me.
By the way, we can check where these symbols declared within image lookup
:
Such symbol’s syntax is valid for Obj-C language.
For Swift, syntax a bit different - we should use next: Module.Type.Method
.
To be more precise, let’s create a new class:
Now, we can use image lookup -n MyApp.SomeClass.myFunc
- everything that contains myFunc will be displayed:
Here u can see, that we have 3 symbols for method in swift:
These are exactly symbols that we should use when we have to deal with within Swift.
By the way, when we stop an app, by default context is set to Obj-C language. To switch it into another language u may use
-l
parameter, where value - one of the supported languages.to get a list of supported languages -
help language
Now, we can use this knowledge to be able to create any symbolic breakpoint, even to code, to which we haven’t access:
The
b
command and thebreakpoint set
command are quite different.b
is a DWIM type command that tries as much as possible to emulate the gdb breakpoint parser’s syntax. It eventually dispatches to `break set with the appropriate breakpoint type. source
We can also use rb
command - rb
is an abbreviation for breakpoint set -r %1
. This command has a lot of options. Most used are:
- -n - Set the breakpoint by function name
- -l - Specifies the line number on which to set this breakpoint
- -i - Set the number of times this breakpoint is skipped before stopping
- -s - Specify scope
- -f - Specifies the source file in which to set this breakpoint
- -F - Set the breakpoint by fully qualified function names
- -A - All files are searched for source pattern matches
- -C - Add command that can be run when br is hit
to get more run
help rb
Run rb .
- this will create a breakpoint on everything :).
command on hit
A very interesting option that can be used within breakpoint set
is -C
. According to doc - A command to run when the breakpoint is hit can be provided more than once, the commands will get run in order left to right.
This is how in xCode u can specify few actions when a breakpoint hit has occurred. Within lldb
console this can be done as follow:
Another option - is to use breakpoint command add <ID of breakpoint>
:
conditions
It’s also good to know how to set some conditions for breakpoint
- -c
or --condition
.
-c <expr> ( --condition <expr> )
The breakpoint stops only if this condition
expression evaluates to true.
Let’s modify our function in SomeClass
:
And now, we can add a condition for the previously added breakpoint:
here I also used
modify
command to edit and change the existing breakpoint. But u can use-c
argument even when u create a breakpoint.
To remove condition - set if blank - -c ""
.
modification
As was shown in the previous example, we can modify the breakpoint. Other options are (from Apple doc):
--condition
(-c
) Specifies an expression that must evaluate to true in order for the breakpoint to stop--ignore-count
(-i
) Specifies the number of times the breakpoint is skipped before stopping--one-shot
(-o
) Removes the breakpoint the first time it stops--queue-name
(-q
) Specifies the name of the queue on which the breakpoint stops--thread-name
(-T
) Specifies the name of the thread on which the breakpoint stops--thread-id
(-t
) Specifies the ID (TID) of the thread on which the breakpoint stops--thread-index
(-x
) Specifies the index of the thread on which the breakpoint stops
errors
Another useful feature is the ability to set a breakpoint to any error in Swift or Objective-C:
(lldb) breakpoint set -E Swift
(lldb) breakpoint set -E objc
In addition, we can add the concrete type (exception-typename) for such breakpoint using -O
option:
(lldb) breakpoint set -E Swift -O MyErrorType
managing
This is a simple one and easy-to-remember :)
- To list breakpoints use
list
command. - To disable breakpoints use
disable
command. - To delete breakpoints use
delete
command.
support
stepping
Often it’s useful to make the next step from a stopped point. For this purpose, we can use thread step-in
command. Keep in mind, that using -c
option we can tell how many steps to do at once.
Another supportive command - thread step-over
performs stepping-over calls.
There are a few more options related to the stepping process:
step-out
, step-in
, step-scripted
, step-inst-over
- run help
within them to inspect and play a bit with them!
backtrace
Sometimes, we also would like to see a full stack of information - in this case, thread backtrace
or simply bt
is very helpful.
type look
type look
another helpful command that can quickly review type definition without switching context:
variable
And of cause inspecting the variable can be done using frame variable
.
sharing
To share breakpoint using a file, we can use command write
and read
:
Result - file with current breakpoints:
Export can be done using next command
or load from the file
Conclusion
Breakpoints - are great when u need to stop and inspect the code and variables around. Thankfully to lldb
they have rich support of most required and commonly used commands.
Knowing the name of the operation (breakpoint
) and a help
command can provide for u additional benefits during application development.
Articles in this series:
- The LLDB Debugger - Part 1: Basics
- The LLDB Debugger - Part 2: Breakpoints
- The LLDB Debugger - Part 3: Watchpoint
Resources
Share on: