2019-01-30 18:51:40 +00:00
|
|
|
Tutorial
|
|
|
|
========
|
|
|
|
|
2024-05-02 08:45:48 +01:00
|
|
|
This document describes how to use LLDB if you are already familiar with
|
|
|
|
GDB's command set. We will start with some details on LLDB command structure and
|
2024-05-01 10:00:12 +01:00
|
|
|
syntax.
|
2019-01-30 18:51:40 +00:00
|
|
|
|
|
|
|
Command Structure
|
|
|
|
-----------------
|
|
|
|
|
2024-05-02 08:45:48 +01:00
|
|
|
Unlike GDB's quite free-form commands, LLDB's are more structured. All commands
|
2024-05-01 10:00:12 +01:00
|
|
|
are of the form:
|
2019-01-30 18:51:40 +00:00
|
|
|
|
|
|
|
::
|
|
|
|
|
|
|
|
<noun> <verb> [-options [option-value]] [argument [argument...]]
|
|
|
|
|
2024-05-01 10:00:12 +01:00
|
|
|
The command line parsing is done before command execution, so it is the same for
|
|
|
|
all commands. The command syntax for basic commands is very simple.
|
2023-02-02 13:46:42 -08:00
|
|
|
|
2024-05-01 10:00:12 +01:00
|
|
|
* Arguments, options and option values are all white-space separated.
|
|
|
|
* Either single ``'`` or double-quotes ``"`` (in pairs) are used to protect white-spaces
|
|
|
|
in an argument.
|
|
|
|
* Escape backslashes and double quotes within arguments should be escaped
|
|
|
|
with a backslash ``\``.
|
|
|
|
|
2024-05-02 08:45:48 +01:00
|
|
|
This makes LLDB's commands more regular, but it also means you may have to quote
|
|
|
|
some arguments in LLDB that you would not in GDB.
|
2024-05-01 10:00:12 +01:00
|
|
|
|
2024-05-02 08:45:48 +01:00
|
|
|
There is one other special quote character in LLDB - the backtick `````.
|
|
|
|
If you put backticks around an argument or option value, LLDB will run the text
|
2023-02-02 13:46:42 -08:00
|
|
|
of the value through the expression parser, and the result of the expression
|
2024-05-01 10:00:12 +01:00
|
|
|
will be passed to the command. So for instance, if ``len`` is a local
|
|
|
|
``int`` variable with the value ``5``, then the command:
|
2023-02-02 13:46:42 -08:00
|
|
|
|
|
|
|
::
|
|
|
|
|
|
|
|
(lldb) memory read -c `len` 0x12345
|
|
|
|
|
2024-05-01 10:00:12 +01:00
|
|
|
Will receive the value ``5`` for the count option, rather than the string ``len``.
|
2019-01-30 18:51:40 +00:00
|
|
|
|
|
|
|
Options can be placed anywhere on the command line, but if the arguments begin
|
2024-05-02 08:45:48 +01:00
|
|
|
with a ``-`` then you have to tell LLDB that you are done with options for the
|
2024-05-01 10:00:12 +01:00
|
|
|
current command by adding an option termination: ``--``.
|
|
|
|
|
|
|
|
So for instance, if you want to launch a process and give the ``process launch``
|
|
|
|
command the ``--stop-at-entry`` option, yet you want the process you are about
|
|
|
|
to launch to be launched with the arguments ``-program_arg value``, you would type:
|
2019-01-30 18:51:40 +00:00
|
|
|
|
|
|
|
::
|
|
|
|
|
|
|
|
(lldb) process launch --stop-at-entry -- -program_arg value
|
|
|
|
|
|
|
|
We also tried to reduce the number of special purpose argument parsers, which
|
2024-05-01 10:00:12 +01:00
|
|
|
sometimes forces the user to be explicit about their intentions. The first
|
2024-05-02 08:45:48 +01:00
|
|
|
instance you willl see of this is the breakpoint command. In GDB, to set a
|
2024-05-01 10:00:12 +01:00
|
|
|
breakpoint, you might enter:
|
2019-01-30 18:51:40 +00:00
|
|
|
|
|
|
|
::
|
|
|
|
|
|
|
|
(gdb) break foo.c:12
|
|
|
|
|
2024-05-01 10:00:12 +01:00
|
|
|
To break at line ``12`` of ``foo.c``, and:
|
2019-01-30 18:51:40 +00:00
|
|
|
|
|
|
|
::
|
|
|
|
|
|
|
|
(gdb) break foo
|
|
|
|
|
2024-05-01 10:00:12 +01:00
|
|
|
To break at the function ``foo``. As time went on, the parser that tells ``foo.c:12``
|
|
|
|
from ``foo`` from ``foo.c::foo`` (which means the function ``foo`` in the file ``foo.c``)
|
|
|
|
got more and more complex. Especially in C++ there are times where there is
|
|
|
|
really no way to specify the function you want to break on.
|
|
|
|
|
2024-05-02 08:45:48 +01:00
|
|
|
The LLDB commands are more verbose but also more precise and allow for
|
2024-05-01 10:00:12 +01:00
|
|
|
intelligent auto completion.
|
2019-01-30 18:51:40 +00:00
|
|
|
|
2024-05-02 08:45:48 +01:00
|
|
|
To set the same file and line breakpoint in LLDB you can enter either of:
|
2019-01-30 18:51:40 +00:00
|
|
|
|
|
|
|
::
|
|
|
|
|
|
|
|
(lldb) breakpoint set --file foo.c --line 12
|
|
|
|
(lldb) breakpoint set -f foo.c -l 12
|
|
|
|
|
2024-05-02 08:45:48 +01:00
|
|
|
To set a breakpoint on a function named ``foo`` in LLDB you can enter either of:
|
2019-01-30 18:51:40 +00:00
|
|
|
|
|
|
|
::
|
|
|
|
|
|
|
|
(lldb) breakpoint set --name foo
|
|
|
|
(lldb) breakpoint set -n foo
|
|
|
|
|
2024-05-01 10:00:12 +01:00
|
|
|
You can use the ``--name`` option multiple times to make a breakpoint on a set of
|
2019-01-30 18:51:40 +00:00
|
|
|
functions as well. This is convenient since it allows you to set common
|
|
|
|
conditions or commands without having to specify them multiple times:
|
|
|
|
|
|
|
|
::
|
|
|
|
|
|
|
|
(lldb) breakpoint set --name foo --name bar
|
|
|
|
|
2024-05-02 08:45:48 +01:00
|
|
|
Setting breakpoints by name is even more specialized in LLDB as you can specify
|
2019-01-30 18:51:40 +00:00
|
|
|
that you want to set a breakpoint at a function by method name. To set a
|
2024-05-01 10:00:12 +01:00
|
|
|
breakpoint on all C++ methods named ``foo`` you can enter either of:
|
2019-01-30 18:51:40 +00:00
|
|
|
|
|
|
|
::
|
|
|
|
|
|
|
|
(lldb) breakpoint set --method foo
|
|
|
|
(lldb) breakpoint set -M foo
|
|
|
|
|
|
|
|
|
2024-05-01 10:00:12 +01:00
|
|
|
To set a breakpoint Objective-C selectors named ``alignLeftEdges:`` you can enter either of:
|
2019-01-30 18:51:40 +00:00
|
|
|
|
|
|
|
::
|
|
|
|
|
|
|
|
(lldb) breakpoint set --selector alignLeftEdges:
|
|
|
|
(lldb) breakpoint set -S alignLeftEdges:
|
|
|
|
|
|
|
|
You can limit any breakpoints to a specific executable image by using the
|
2024-05-01 10:00:12 +01:00
|
|
|
``--shlib <path>`` (``-s <path>`` for short):
|
2019-01-30 18:51:40 +00:00
|
|
|
|
|
|
|
::
|
|
|
|
|
|
|
|
(lldb) breakpoint set --shlib foo.dylib --name foo
|
|
|
|
(lldb) breakpoint set -s foo.dylib -n foo
|
|
|
|
|
2024-05-01 10:00:12 +01:00
|
|
|
The ``--shlib`` option can also be repeated to specify several shared libraries.
|
2019-01-30 18:51:40 +00:00
|
|
|
|
|
|
|
Suggestions on more interesting primitives of this sort are also very welcome.
|
|
|
|
|
2024-05-02 08:45:48 +01:00
|
|
|
Just like GDB, the LLDB command interpreter does a shortest unique string match
|
2019-01-30 18:51:40 +00:00
|
|
|
on command names, so the following two commands will both execute the same
|
|
|
|
command:
|
|
|
|
|
|
|
|
::
|
|
|
|
|
|
|
|
(lldb) breakpoint set -n "-[SKTGraphicView alignLeftEdges:]"
|
|
|
|
(lldb) br s -n "-[SKTGraphicView alignLeftEdges:]"
|
|
|
|
|
2024-05-02 08:45:48 +01:00
|
|
|
LLDB also supports command completion for source file names, symbol names, file
|
2024-05-01 10:00:12 +01:00
|
|
|
names, etc. Completion is initiated by hitting TAB. Individual options in a
|
|
|
|
command can have different completers, so for instance, the ``--file <path>``
|
|
|
|
option in ``breakpoint`` completes to source files, the ``--shlib <path>`` option
|
|
|
|
to currently loaded shared libraries, etc. You can even do things like if you
|
2024-05-02 08:45:48 +01:00
|
|
|
specify ``--shlib <path>``, and are completing on ``--file <path>``, LLDB will only
|
2024-05-01 10:00:12 +01:00
|
|
|
list source files in the shared library specified by ``--shlib <path>``.
|
|
|
|
|
|
|
|
The individual commands are pretty extensively documented. You can use the ``help``
|
2019-01-30 18:51:40 +00:00
|
|
|
command to get an overview of which commands are available or to obtain details
|
2024-05-01 10:00:12 +01:00
|
|
|
about specific commands. There is also an ``apropos`` command that will search the
|
2019-01-30 18:51:40 +00:00
|
|
|
help text for all commands for a particular word and dump a summary help string
|
|
|
|
for each matching command.
|
|
|
|
|
|
|
|
Finally, there is a mechanism to construct aliases for commonly used commands.
|
2021-04-08 10:55:55 -07:00
|
|
|
For instance, if you get annoyed typing:
|
2019-01-30 18:51:40 +00:00
|
|
|
|
|
|
|
::
|
|
|
|
|
|
|
|
(lldb) breakpoint set --file foo.c --line 12
|
|
|
|
|
2024-05-01 10:00:12 +01:00
|
|
|
You can do:
|
2019-01-30 18:51:40 +00:00
|
|
|
|
|
|
|
::
|
|
|
|
|
|
|
|
(lldb) command alias bfl breakpoint set -f %1 -l %2
|
|
|
|
(lldb) bfl foo.c 12
|
|
|
|
|
2024-05-02 08:45:48 +01:00
|
|
|
LLDB has a few aliases for commonly used commands (e.g. ``step``, ``next`` and
|
2024-05-01 10:00:12 +01:00
|
|
|
``continue``) but it does not try to be exhaustive because in our experience it
|
2019-01-30 18:51:40 +00:00
|
|
|
is more convenient to make the basic commands unique down to a letter or two,
|
|
|
|
and then learn these sequences than to fill the namespace with lots of aliases,
|
|
|
|
and then have to type them all the way out.
|
|
|
|
|
2024-08-08 12:55:10 -07:00
|
|
|
If the alias abbreviation or the full alias command collides with another
|
|
|
|
existing command, the command resolver will prefer to use the alias over any
|
|
|
|
other command as far as there is only one alias command match.
|
|
|
|
|
2024-05-02 08:45:48 +01:00
|
|
|
However, users are free to customize LLDB's command set however they like, and
|
|
|
|
since LLDB reads the file ``~/.lldbinit`` at startup, you can store all your
|
2019-01-30 18:51:40 +00:00
|
|
|
aliases there and they will be generally available to you. Your aliases are
|
2024-05-01 10:00:12 +01:00
|
|
|
also documented in the ``help`` command so you can remind yourself of what you have
|
2019-01-30 18:51:40 +00:00
|
|
|
set up.
|
|
|
|
|
2024-05-02 08:45:48 +01:00
|
|
|
One alias of note that LLDB does include by popular demand is a weak emulator of
|
|
|
|
GDB's ``break`` command. It does not try to do everything that GDB's break command
|
2024-05-01 10:00:12 +01:00
|
|
|
does (for instance, it does not handle ``foo.c::bar``). But it mostly works, and
|
|
|
|
makes the transition easier. Also, by popular demand, it is aliased to ``b``. If you
|
2024-05-02 08:45:48 +01:00
|
|
|
actually want to learn the LLDB command set natively, that means it will get in
|
2024-05-01 10:00:12 +01:00
|
|
|
the way of the rest of the breakpoint commands. Fortunately, if you do not like
|
|
|
|
one of our aliases, you can easily get rid of it by running, for example:
|
2019-01-30 18:51:40 +00:00
|
|
|
|
|
|
|
::
|
|
|
|
|
|
|
|
(lldb) command unalias b
|
|
|
|
|
2024-05-01 10:00:12 +01:00
|
|
|
You can also do:
|
2019-01-30 18:51:40 +00:00
|
|
|
|
|
|
|
::
|
|
|
|
|
|
|
|
(lldb) command alias b breakpoint
|
|
|
|
|
2024-05-02 08:45:48 +01:00
|
|
|
So you can run the native LLDB breakpoint command with just ``b``.
|
2019-01-30 18:51:40 +00:00
|
|
|
|
2024-05-02 08:45:48 +01:00
|
|
|
The LLDB command parser also supports "raw" commands, where, after command
|
2019-01-30 18:51:40 +00:00
|
|
|
options are stripped off, the rest of the command string is passed
|
|
|
|
uninterpreted to the command. This is convenient for commands whose arguments
|
|
|
|
might be some complex expression that would be painful to backslash protect.
|
2024-05-01 10:00:12 +01:00
|
|
|
For instance, the ``expression`` command is a "raw" command for obvious reasons.
|
|
|
|
The ``help`` output for a command will tell you if it is "raw" or not, so you
|
2019-01-30 18:51:40 +00:00
|
|
|
know what to expect. The one thing you have to watch out for is that since raw
|
|
|
|
commands still can have options, if your command string has dashes in it,
|
2024-05-01 10:00:12 +01:00
|
|
|
you will have to indicate these are not option markers by putting ``--`` after the
|
2019-01-30 18:51:40 +00:00
|
|
|
command name, but before your command string.
|
|
|
|
|
2024-05-02 08:45:48 +01:00
|
|
|
LLDB also has a built-in Python interpreter, which is accessible by the
|
2024-10-08 12:29:39 +08:00
|
|
|
``script`` command. All the functionality of the debugger is available as classes
|
2024-05-02 08:45:48 +01:00
|
|
|
in the Python interpreter, so the more complex commands that in GDB you would
|
2024-05-01 10:00:12 +01:00
|
|
|
introduce with the ``define`` command can be done by writing Python functions
|
2024-05-02 08:45:48 +01:00
|
|
|
using the LLDB Python library, then loading the scripts into your running
|
2024-05-01 10:00:12 +01:00
|
|
|
session and accessing them with the ``script`` command.
|
2019-01-30 18:51:40 +00:00
|
|
|
|
2024-05-02 08:45:48 +01:00
|
|
|
Loading a Program Into LLDB
|
2019-01-30 18:51:40 +00:00
|
|
|
---------------------------
|
|
|
|
|
2024-05-02 08:45:48 +01:00
|
|
|
First you need to set the program to debug. As with GDB, you can start LLDB and
|
2024-05-01 10:00:12 +01:00
|
|
|
specify the file you wish to debug on the command line:
|
2019-01-30 18:51:40 +00:00
|
|
|
|
|
|
|
::
|
|
|
|
|
|
|
|
$ lldb /Projects/Sketch/build/Debug/Sketch.app
|
|
|
|
Current executable set to '/Projects/Sketch/build/Debug/Sketch.app' (x86_64).
|
|
|
|
|
2024-05-01 10:00:12 +01:00
|
|
|
Or you can specify it after the fact with the ``file`` command:
|
2019-01-30 18:51:40 +00:00
|
|
|
|
|
|
|
::
|
|
|
|
|
|
|
|
$ lldb
|
|
|
|
(lldb) file /Projects/Sketch/build/Debug/Sketch.app
|
|
|
|
Current executable set to '/Projects/Sketch/build/Debug/Sketch.app' (x86_64).
|
|
|
|
|
|
|
|
Setting Breakpoints
|
|
|
|
-------------------
|
|
|
|
|
2024-05-01 10:00:12 +01:00
|
|
|
We have discussed how to set breakpoints above. You can use ``help breakpoint set``
|
|
|
|
to see all the options for breakpoint setting. For instance, you could do:
|
2019-01-30 18:51:40 +00:00
|
|
|
|
|
|
|
::
|
|
|
|
|
|
|
|
(lldb) breakpoint set --selector alignLeftEdges:
|
|
|
|
Breakpoint created: 1: name = 'alignLeftEdges:', locations = 1, resolved = 1
|
|
|
|
|
2024-05-01 10:00:12 +01:00
|
|
|
You can find out about the breakpoints you have set with:
|
2019-01-30 18:51:40 +00:00
|
|
|
|
|
|
|
::
|
|
|
|
|
|
|
|
(lldb) breakpoint list
|
|
|
|
Current breakpoints:
|
|
|
|
1: name = 'alignLeftEdges:', locations = 1, resolved = 1
|
|
|
|
1.1: where = Sketch`-[SKTGraphicView alignLeftEdges:] + 33 at /Projects/Sketch/SKTGraphicView.m:1405, address = 0x0000000100010d5b, resolved, hit count = 0
|
|
|
|
|
|
|
|
|
|
|
|
Note that setting a breakpoint creates a logical breakpoint, which could
|
|
|
|
resolve to one or more locations. For instance, break by selector would set a
|
|
|
|
breakpoint on all the methods that implement that selector in the classes in
|
|
|
|
your program. Similarly, a file and line breakpoint might result in multiple
|
|
|
|
locations if that file and line were inlined in different places in your code.
|
|
|
|
|
2021-03-01 23:40:29 -08:00
|
|
|
The logical breakpoint has an integer id, and its locations have an id within
|
2024-05-01 10:00:12 +01:00
|
|
|
their parent breakpoint (the two are joined by a ``.``, e.g. ``1.1`` in the example
|
2021-04-08 10:55:55 -07:00
|
|
|
above).
|
2019-01-30 18:51:40 +00:00
|
|
|
|
2024-05-01 10:00:12 +01:00
|
|
|
Also logical breakpoints remain live so that if another shared library were
|
|
|
|
to be loaded that had another implementation of the ``alignLeftEdges:`` selector,
|
|
|
|
the new location would be added to breakpoint ``1`` (e.g. a ``1.2`` breakpoint would
|
2019-01-30 18:51:40 +00:00
|
|
|
be set on the newly loaded selector).
|
|
|
|
|
|
|
|
The other piece of information in the breakpoint listing is whether the
|
|
|
|
breakpoint location was resolved or not. A location gets resolved when the file
|
|
|
|
address it corresponds to gets loaded into the program you are debugging. For
|
|
|
|
instance if you set a breakpoint in a shared library that then gets unloaded,
|
|
|
|
that breakpoint location will remain, but it will no longer be resolved.
|
|
|
|
|
2024-05-02 08:45:48 +01:00
|
|
|
One other thing to note for GDB users is that LLDB acts like GDB with:
|
2019-01-30 18:51:40 +00:00
|
|
|
|
|
|
|
::
|
|
|
|
|
|
|
|
(gdb) set breakpoint pending on
|
|
|
|
|
2024-05-02 08:45:48 +01:00
|
|
|
Which means that LLDB will always make a breakpoint from your specification, even if it
|
2024-05-01 10:00:12 +01:00
|
|
|
could not find any locations that match the specification. You can tell whether
|
2019-01-30 18:51:40 +00:00
|
|
|
the expression was resolved or not by checking the locations field in
|
2024-05-02 08:45:48 +01:00
|
|
|
``breakpoint list``, and LLDB reports the breakpoint as ``pending`` when you set it so
|
2024-05-01 10:00:12 +01:00
|
|
|
you can tell you have made a typo more easily, if that was indeed the reason no
|
2019-01-30 18:51:40 +00:00
|
|
|
locations were found:
|
|
|
|
|
|
|
|
::
|
|
|
|
|
|
|
|
(lldb) breakpoint set --file foo.c --line 12
|
|
|
|
Breakpoint created: 2: file ='foo.c', line = 12, locations = 0 (pending)
|
|
|
|
WARNING: Unable to resolve breakpoint to any actual locations.
|
|
|
|
|
|
|
|
You can delete, disable, set conditions and ignore counts either on all the
|
|
|
|
locations generated by your logical breakpoint, or on any one of the particular
|
2024-05-01 10:00:12 +01:00
|
|
|
locations your specification resolved to. For instance, if you wanted to add a
|
|
|
|
command to print a backtrace when you hit this breakpoint you could do:
|
2019-01-30 18:51:40 +00:00
|
|
|
|
|
|
|
::
|
|
|
|
|
|
|
|
(lldb) breakpoint command add 1.1
|
|
|
|
Enter your debugger command(s). Type 'DONE' to end.
|
|
|
|
> bt
|
|
|
|
> DONE
|
|
|
|
|
2024-05-02 08:45:48 +01:00
|
|
|
By default, the breakpoint command add command takes LLDB command line
|
2024-05-01 10:00:12 +01:00
|
|
|
commands. You can also specify this explicitly by passing the ``--command``
|
|
|
|
option. Use ``--script`` if you want to implement your breakpoint command using
|
2019-01-30 18:51:40 +00:00
|
|
|
the Python script instead.
|
|
|
|
|
2024-05-02 08:45:48 +01:00
|
|
|
This is a convenient point to bring up another feature of the LLDB command
|
2024-05-01 10:00:12 +01:00
|
|
|
``help``. Do:
|
2019-01-30 18:51:40 +00:00
|
|
|
|
|
|
|
::
|
|
|
|
|
|
|
|
(lldb) help break command add
|
|
|
|
Add a set of commands to a breakpoint, to be executed whenever the breakpoint is hit.
|
|
|
|
|
|
|
|
Syntax: breakpoint command add <cmd-options> <breakpt-id>
|
|
|
|
etc...
|
|
|
|
|
2024-05-01 10:00:12 +01:00
|
|
|
When you see arguments to commands specified in the ``Syntax`` section in angle brackets
|
|
|
|
like ``<breakpt-id>``, that indicates that that is some common argument type that
|
2019-01-30 18:51:40 +00:00
|
|
|
you can get further help on from the command system. So in this case you could
|
|
|
|
do:
|
|
|
|
|
|
|
|
::
|
|
|
|
|
2024-10-08 12:29:39 +08:00
|
|
|
(lldb) help <breakpt-id>
|
|
|
|
<breakpt-id> -- Breakpoint ID's consist major and minor numbers; the major etc...
|
2019-01-30 18:51:40 +00:00
|
|
|
|
|
|
|
Breakpoint Names
|
|
|
|
----------------
|
|
|
|
|
2024-05-01 10:00:12 +01:00
|
|
|
Breakpoints carry two orthogonal sets of information: one specifies where to set
|
|
|
|
the breakpoint, and the other how to react when the breakpoint is hit. The latter
|
|
|
|
set of information (e.g. commands, conditions, hit-count, auto-continue...) we
|
|
|
|
call breakpoint options.
|
2019-01-30 18:51:40 +00:00
|
|
|
|
2024-05-01 10:00:12 +01:00
|
|
|
It is fairly common to want to apply one set of options to a number of breakpoints.
|
|
|
|
For instance, you might want to check that ``self == nil`` and if it is, print a
|
|
|
|
backtrace and continue, on a number of methods. One convenient way to do that would
|
|
|
|
be to make all the breakpoints, then configure the options with:
|
2019-01-30 18:51:40 +00:00
|
|
|
|
|
|
|
::
|
|
|
|
|
|
|
|
(lldb) breakpoint modify -c "self == nil" -C bt --auto-continue 1 2 3
|
|
|
|
|
2024-05-01 10:00:12 +01:00
|
|
|
That is not too bad, but you have to repeat this for every new breakpoint you make,
|
|
|
|
and if you wanted to change the options, you have to remember all the ones you are
|
|
|
|
using this way.
|
2019-01-30 18:51:40 +00:00
|
|
|
|
2024-05-01 10:00:12 +01:00
|
|
|
Breakpoint names provide a convenient solution to this problem. The simple solution
|
|
|
|
would be to use the name to gather the breakpoints you want to affect this way into
|
|
|
|
a group. So when you make the breakpoint you would do:
|
2019-01-30 18:51:40 +00:00
|
|
|
|
|
|
|
::
|
|
|
|
|
|
|
|
(lldb) breakpoint set -N SelfNil
|
|
|
|
|
2024-05-01 10:00:12 +01:00
|
|
|
Then when you have made all your breakpoints, you can set up or modify the options
|
|
|
|
using the name to collect all the relevant breakpoints.
|
2019-01-30 18:51:40 +00:00
|
|
|
|
|
|
|
::
|
|
|
|
|
|
|
|
(lldb) breakpoint modify -c "self == nil" -C bt --auto-continue SelfNil
|
|
|
|
|
|
|
|
That is better, but suffers from the problem that when new breakpoints get
|
2024-05-01 10:00:12 +01:00
|
|
|
added, they do not pick up these modifications, and the options only exist in
|
|
|
|
the context of actual breakpoints, so they are hard to store and reuse.
|
2019-01-30 18:51:40 +00:00
|
|
|
|
2023-09-02 09:32:48 -07:00
|
|
|
An even better solution is to make a fully configured breakpoint name:
|
2019-01-30 18:51:40 +00:00
|
|
|
|
|
|
|
::
|
|
|
|
|
|
|
|
(lldb) breakpoint name configure -c "self == nil" -C bt --auto-continue SelfNil
|
|
|
|
|
|
|
|
Then you can apply the name to your breakpoints, and they will all pick up
|
|
|
|
these options. The connection from name to breakpoints remains live, so when
|
|
|
|
you change the options configured on the name, all the breakpoints pick up
|
|
|
|
those changes. This makes it easy to use configured names to experiment with
|
|
|
|
your options.
|
|
|
|
|
2024-05-01 10:00:12 +01:00
|
|
|
You can make breakpoint names in your ``.lldbinit`` file, so you can use them to
|
2019-01-30 18:51:40 +00:00
|
|
|
can behaviors that you have found useful and reapply them in future sessions.
|
|
|
|
|
|
|
|
You can also make a breakpoint name from the options set on a breakpoint:
|
|
|
|
|
|
|
|
::
|
|
|
|
|
|
|
|
(lldb) breakpoint name configure -B 1 SelfNil
|
|
|
|
|
|
|
|
which makes it easy to copy behavior from one breakpoint to a set of others.
|
|
|
|
|
|
|
|
Setting Watchpoints
|
|
|
|
-------------------
|
|
|
|
|
|
|
|
In addition to breakpoints, you can use help watchpoint to see all the commands
|
2024-05-01 10:00:12 +01:00
|
|
|
for watchpoint manipulations. For instance, you might do the following to watch
|
|
|
|
a variable called ``global`` for write operation, but only stop if the condition
|
|
|
|
``(global==5)`` is true:
|
2019-01-30 18:51:40 +00:00
|
|
|
|
|
|
|
::
|
|
|
|
|
|
|
|
(lldb) watch set var global
|
|
|
|
Watchpoint created: Watchpoint 1: addr = 0x100001018 size = 4 state = enabled type = w
|
|
|
|
declare @ '/Volumes/data/lldb/svn/ToT/test/functionalities/watchpoint/watchpoint_commands/condition/main.cpp:12'
|
|
|
|
(lldb) watch modify -c '(global==5)'
|
|
|
|
(lldb) watch list
|
|
|
|
Current watchpoints:
|
|
|
|
Watchpoint 1: addr = 0x100001018 size = 4 state = enabled type = w
|
|
|
|
declare @ '/Volumes/data/lldb/svn/ToT/test/functionalities/watchpoint/watchpoint_commands/condition/main.cpp:12'
|
|
|
|
condition = '(global==5)'
|
|
|
|
(lldb) c
|
|
|
|
Process 15562 resuming
|
|
|
|
(lldb) about to write to 'global'...
|
|
|
|
Process 15562 stopped and was programmatically restarted.
|
|
|
|
Process 15562 stopped and was programmatically restarted.
|
|
|
|
Process 15562 stopped and was programmatically restarted.
|
|
|
|
Process 15562 stopped and was programmatically restarted.
|
|
|
|
Process 15562 stopped
|
|
|
|
* thread #1: tid = 0x1c03, 0x0000000100000ef5 a.out`modify + 21 at main.cpp:16, stop reason = watchpoint 1
|
|
|
|
frame #0: 0x0000000100000ef5 a.out`modify + 21 at main.cpp:16
|
|
|
|
13
|
|
|
|
14 static void modify(int32_t &var) {
|
|
|
|
15 ++var;
|
|
|
|
-> 16 }
|
|
|
|
17
|
|
|
|
18 int main(int argc, char** argv) {
|
|
|
|
19 int local = 0;
|
|
|
|
(lldb) bt
|
|
|
|
* thread #1: tid = 0x1c03, 0x0000000100000ef5 a.out`modify + 21 at main.cpp:16, stop reason = watchpoint 1
|
|
|
|
frame #0: 0x0000000100000ef5 a.out`modify + 21 at main.cpp:16
|
|
|
|
frame #1: 0x0000000100000eac a.out`main + 108 at main.cpp:25
|
|
|
|
frame #2: 0x00007fff8ac9c7e1 libdyld.dylib`start + 1
|
|
|
|
(lldb) frame var global
|
|
|
|
(int32_t) global = 5
|
|
|
|
(lldb) watch list -v
|
|
|
|
Current watchpoints:
|
|
|
|
Watchpoint 1: addr = 0x100001018 size = 4 state = enabled type = w
|
|
|
|
declare @ '/Volumes/data/lldb/svn/ToT/test/functionalities/watchpoint/watchpoint_commands/condition/main.cpp:12'
|
|
|
|
condition = '(global==5)'
|
Remove hardware index from watchpoints and breakpoints (#72012)
The Watchpoint and Breakpoint objects try to track the hardware index
that was used for them, if they are hardware wp/bp's. The majority of
our debugging goes over the gdb remote serial protocol, and when we set
the watchpoint/breakpoint, there is no (standard) way for the remote
stub to communicate to lldb which hardware index was used. We have an
lldb-extension packet to query the total number of watchpoint registers.
When a watchpoint is hit, there is an lldb extension to the stop reply
packet (documented in lldb-gdb-remote.txt) to describe the watchpoint
including its actual hardware index,
<addr within wp range> <wp hw index> <actual accessed address>
(the third field is specifically needed for MIPS). At this point, if the
stub reported these three fields (the stub is only required to provide
the first), we can know the actual hardware index for this watchpoint.
Breakpoints are worse; there's never any way for us to be notified about
which hardware index was used. Breakpoints got this as a side effect of
inherting from StoppointSite with Watchpoints.
We expose the watchpoint hardware index through "watchpoint list -v" and
through SBWatchpoint::GetHardwareIndex.
With my large watchpoint support, there is no *single* hardware index
that may be used for a watchpoint, it may need multiple resources. Also
I don't see what a user is supposed to do with this information, or an
IDE. Knowing the total number of watchpoint registers on the target, and
knowing how many Watchpoint Resources are currently in use, is helpful.
Knowing how many Watchpoint Resources
a single user-specified watchpoint needed to be implemented is useful.
But knowing which registers were used is an implementation detail and
not available until we hit the watchpoint when using gdb remote serial
protocol.
So given all that, I'm removing watchpoint hardware index numbers. I'm
changing the SB API to always return -1.
2023-11-15 13:32:42 -08:00
|
|
|
hit_count = 5 ignore_count = 0
|
2019-01-30 18:51:40 +00:00
|
|
|
(lldb)
|
|
|
|
|
|
|
|
Starting or Attaching to Your Program
|
|
|
|
-------------------------------------
|
|
|
|
|
2024-05-02 08:45:48 +01:00
|
|
|
To launch a program in LLDB you will use the ``process launch`` command or one of
|
2024-05-01 10:00:12 +01:00
|
|
|
its built in aliases:
|
2019-01-30 18:51:40 +00:00
|
|
|
|
|
|
|
::
|
|
|
|
|
|
|
|
(lldb) process launch
|
|
|
|
(lldb) run
|
|
|
|
(lldb) r
|
|
|
|
|
|
|
|
You can also attach to a process by process ID or process name. When attaching
|
2024-05-02 08:45:48 +01:00
|
|
|
to a process by name, LLDB also supports the ``--waitfor`` option which waits for
|
2019-01-30 18:51:40 +00:00
|
|
|
the next process that has that name to show up, and attaches to it
|
|
|
|
|
|
|
|
::
|
|
|
|
|
|
|
|
(lldb) process attach --pid 123
|
|
|
|
(lldb) process attach --name Sketch
|
|
|
|
(lldb) process attach --name Sketch --waitfor
|
|
|
|
|
|
|
|
After you launch or attach to a process, your process might stop somewhere:
|
|
|
|
|
|
|
|
::
|
|
|
|
|
|
|
|
(lldb) process attach -p 12345
|
|
|
|
Process 46915 Attaching
|
|
|
|
Process 46915 Stopped
|
|
|
|
1 of 3 threads stopped with reasons:
|
|
|
|
* thread #1: tid = 0x2c03, 0x00007fff85cac76a, where = libSystem.B.dylib`__getdirentries64 + 10, stop reason = signal = SIGSTOP, queue = com.apple.main-thread
|
|
|
|
|
2024-05-01 10:00:12 +01:00
|
|
|
Note the line that says ``1 of 3 threads stopped with reasons:`` and the lines
|
2019-01-30 18:51:40 +00:00
|
|
|
that follow it. In a multi-threaded environment it is very common for more than
|
|
|
|
one thread to hit your breakpoint(s) before the kernel actually returns control
|
|
|
|
to the debugger. In that case, you will see all the threads that stopped for
|
|
|
|
some interesting reason listed in the stop message.
|
|
|
|
|
|
|
|
Controlling Your Program
|
|
|
|
------------------------
|
|
|
|
|
2024-05-01 10:00:12 +01:00
|
|
|
After launching, you can continue until you hit your breakpoint. The primitive commands
|
|
|
|
for process control all exist under the "thread" command:
|
2019-01-30 18:51:40 +00:00
|
|
|
|
|
|
|
::
|
|
|
|
|
|
|
|
(lldb) thread continue
|
|
|
|
Resuming thread 0x2c03 in process 46915
|
|
|
|
Resuming process 46915
|
|
|
|
(lldb)
|
|
|
|
|
2024-05-01 10:00:12 +01:00
|
|
|
At present you can only operate on one thread at a time, but the design will
|
|
|
|
ultimately support saying "step over the function in Thread 1, and step into the
|
2024-05-02 08:45:48 +01:00
|
|
|
function in Thread 2, and continue Thread 3" etc. When LLDB eventually supports
|
2024-05-01 10:00:12 +01:00
|
|
|
keeping some threads running while others are stopped this will be particularly
|
|
|
|
important. For convenience, however, all the stepping commands have easy aliases.
|
|
|
|
So ``thread continue`` is just ``c``, etc.
|
2019-01-30 18:51:40 +00:00
|
|
|
|
2024-05-02 08:45:48 +01:00
|
|
|
The other program stepping commands are pretty much the same as in GDB. You have got:
|
2019-01-30 18:51:40 +00:00
|
|
|
|
|
|
|
::
|
|
|
|
|
2024-05-02 08:45:48 +01:00
|
|
|
(lldb) thread step-in // The same as GDB's "step" or "s"
|
|
|
|
(lldb) thread step-over // The same as GDB's "next" or "n"
|
|
|
|
(lldb) thread step-out // The same as GDB's "finish" or "f"
|
2019-01-30 18:51:40 +00:00
|
|
|
|
2024-05-02 08:45:48 +01:00
|
|
|
By default, LLDB does defined aliases to all common GDB process control commands
|
|
|
|
(``s``, ``step``, ``n``, ``next``, ``finish``). If LLDB is missing any, please add
|
2024-05-01 10:00:12 +01:00
|
|
|
them to your ``~/.lldbinit`` file using the ``command alias`` command.
|
2019-01-30 18:51:40 +00:00
|
|
|
|
2024-05-02 08:45:48 +01:00
|
|
|
LLDB also supports the step by instruction versions:
|
2019-01-30 18:51:40 +00:00
|
|
|
|
|
|
|
::
|
|
|
|
|
|
|
|
|
2024-05-02 08:45:48 +01:00
|
|
|
(lldb) thread step-inst // The same as GDB's "stepi" / "si"
|
|
|
|
(lldb) thread step-over-inst // The same as GDB's "nexti" / "ni"
|
2019-01-30 18:51:40 +00:00
|
|
|
|
2024-05-02 08:45:48 +01:00
|
|
|
Finally, LLDB has a run until line or frame exit stepping mode:
|
2019-01-30 18:51:40 +00:00
|
|
|
|
|
|
|
::
|
|
|
|
|
|
|
|
(lldb) thread until 100
|
|
|
|
|
2024-05-01 10:00:12 +01:00
|
|
|
This command will run the thread in the current frame until it reaches line 100
|
2019-01-30 18:51:40 +00:00
|
|
|
in this frame or stops if it leaves the current frame. This is a pretty close
|
2024-05-02 08:45:48 +01:00
|
|
|
equivalent to GDB's ``until`` command.
|
2019-01-30 18:51:40 +00:00
|
|
|
|
2024-09-27 09:36:52 -07:00
|
|
|
One other useful thing to note about the lldb stepping commands is that they
|
|
|
|
are implemented as a stack of interruptible operations. Until the operation -
|
|
|
|
e.g. step to the next line - is completed, it will remain on the
|
|
|
|
stack. If the step over is interrupted and control returned to you,
|
|
|
|
any new stepping commands you issue won't replace the step-over, but instead
|
|
|
|
their operations will be pushed onto the stack after the original step over.
|
|
|
|
Then each of them will be retired as they are completed, finally returning to the
|
|
|
|
original step over operation.
|
|
|
|
|
|
|
|
Suppose, for instance, you ``step-over`` a source line with a function call.
|
|
|
|
If there is a breakpoint in that function, hitting the breakpoint will interrupt
|
|
|
|
the step over. At that point, you will likely want to examine the state at
|
|
|
|
the breakpoint, maybe stepping around in that frame, or stepping into other
|
|
|
|
functions, running some expressions, etc.
|
|
|
|
|
|
|
|
Because the original step-over has remained on the stack, when you've finished
|
|
|
|
your examinations, a simple ``continue`` will resume the original ``step-over``
|
|
|
|
operation, and you will arrive at the end of your starting source line in the
|
|
|
|
original frame.
|
|
|
|
|
|
|
|
This saves you from having to keep track of your original intention, and manually
|
|
|
|
issuing the requisite number of ``step-out`` commands to get back to the frame
|
|
|
|
you were stepping over. The stack maintains that information for you.
|
|
|
|
|
|
|
|
Hand-called functions using the ``expr`` command are also implemented by
|
|
|
|
operations on this same stack. So if you are calling some code with the ``expr`` command,
|
|
|
|
and hit a breakpoint during the evaluation of that code, you can examine
|
|
|
|
the state where you stopped, and when you're satisfied, issue a
|
|
|
|
``continue`` to finish the expression evaluation operation and print the function
|
|
|
|
result.
|
|
|
|
|
|
|
|
You can examine the state of the operations stack using the ``thread plan list``
|
|
|
|
command, and if, for instance, you decide you don't actually want that outermost
|
|
|
|
next to continue running, you can remove it with the ``thread plan discard``
|
|
|
|
command. If you are interested in following this process in more detail, the
|
|
|
|
``lldb step`` logging channel is useful source of information.
|
|
|
|
|
2024-05-02 08:45:48 +01:00
|
|
|
A process, by default, will share the LLDB terminal with the inferior process.
|
|
|
|
When in this mode, much like when debugging with GDB, when the process is
|
2024-05-01 10:00:12 +01:00
|
|
|
running anything you type will go to the ``STDIN`` of the inferior process. To
|
|
|
|
interrupt your inferior program, type ``CTRL+C``.
|
2019-01-30 18:51:40 +00:00
|
|
|
|
2024-05-01 10:00:12 +01:00
|
|
|
If you attach to a process, or launch a process with the ``--no-stdin`` option,
|
2022-01-14 16:21:10 -08:00
|
|
|
the command interpreter is always available to enter commands. It might be a
|
2024-05-02 08:45:48 +01:00
|
|
|
little disconcerting to GDB users to always have an ``(lldb)`` prompt. This allows
|
2024-05-01 10:00:12 +01:00
|
|
|
you to set a breakpoint, or use any other command without having to explicitly
|
|
|
|
interrupt the program you are debugging:
|
2019-01-30 18:51:40 +00:00
|
|
|
|
|
|
|
::
|
|
|
|
|
|
|
|
(lldb) process continue
|
|
|
|
(lldb) breakpoint set --name stop_here
|
|
|
|
|
|
|
|
There are many commands that won't work while running, and the command
|
2024-05-01 10:00:12 +01:00
|
|
|
interpreter will let you know when this is the case. Please file an issue if
|
|
|
|
it does not. This way of operation will set us up for a future debugging
|
2019-01-30 18:51:40 +00:00
|
|
|
mode called thread centric debugging. This mode will allow us to run all
|
|
|
|
threads and only stop the threads that are at breakpoints or have exceptions or
|
|
|
|
signals.
|
|
|
|
|
|
|
|
The commands that currently work while running include interrupting the process
|
2024-05-01 10:00:12 +01:00
|
|
|
to halt execution (``process interrupt``), getting the process status (``process status``),
|
|
|
|
breakpoint setting and clearing (``breakpoint [set|clear|enable|disable|list] ...``),
|
|
|
|
and memory reading and writing (``memory [read|write] ...``).
|
2019-01-30 18:51:40 +00:00
|
|
|
|
|
|
|
The question of disabling stdio when running brings up a good opportunity to
|
2024-05-01 10:00:12 +01:00
|
|
|
show how to set debugger properties. If you always want to run in
|
|
|
|
the ``--no-stdin`` mode, you can set this as a generic process property using the
|
2024-05-02 08:45:48 +01:00
|
|
|
LLDB ``settings`` command, which is equivalent to GDB's ``set`` command.
|
2024-05-01 10:00:12 +01:00
|
|
|
In this case you would say:
|
2019-01-30 18:51:40 +00:00
|
|
|
|
|
|
|
::
|
|
|
|
|
|
|
|
(lldb) settings set target.process.disable-stdio true
|
|
|
|
|
2024-05-02 08:45:48 +01:00
|
|
|
Over time, GDB's ``set`` command became a wilderness of disordered options, so
|
|
|
|
that there were useful options that even experienced GDB users did not know
|
|
|
|
about because they were too hard to find. LLDB instead organizes the settings
|
2019-01-30 18:51:40 +00:00
|
|
|
hierarchically using the structure of the basic entities in the debugger. For
|
|
|
|
the most part anywhere you can specify a setting on a generic entity (threads,
|
2024-05-01 10:00:12 +01:00
|
|
|
for example) you can also apply the option to a particular instance. You can
|
|
|
|
view the available settings with the command ``settings list`` and there is help
|
|
|
|
on the settings command explaining how it works more generally.
|
2019-01-30 18:51:40 +00:00
|
|
|
|
|
|
|
Examining Thread State
|
|
|
|
----------------------
|
|
|
|
|
2024-05-02 08:45:48 +01:00
|
|
|
Once you have stopped, LLDB will choose a current thread, usually the one that
|
2019-01-30 18:51:40 +00:00
|
|
|
stopped "for a reason", and a current frame in that thread (on stop this is
|
|
|
|
always the bottom-most frame). Many the commands for inspecting state work on
|
|
|
|
this current thread/frame.
|
|
|
|
|
|
|
|
To inspect the current state of your process, you can start with the threads:
|
|
|
|
|
|
|
|
::
|
|
|
|
|
|
|
|
(lldb) thread list
|
|
|
|
Process 46915 state is Stopped
|
|
|
|
* thread #1: tid = 0x2c03, 0x00007fff85cac76a, where = libSystem.B.dylib`__getdirentries64 + 10, stop reason = signal = SIGSTOP, queue = com.apple.main-thread
|
|
|
|
thread #2: tid = 0x2e03, 0x00007fff85cbb08a, where = libSystem.B.dylib`kevent + 10, queue = com.apple.libdispatch-manager
|
|
|
|
thread #3: tid = 0x2f03, 0x00007fff85cbbeaa, where = libSystem.B.dylib`__workq_kernreturn + 10
|
|
|
|
|
|
|
|
The ``*`` indicates that Thread 1 is the current thread. To get a backtrace for
|
|
|
|
that thread, do:
|
|
|
|
|
|
|
|
::
|
|
|
|
|
|
|
|
(lldb) thread backtrace
|
|
|
|
thread #1: tid = 0x2c03, stop reason = breakpoint 1.1, queue = com.apple.main-thread
|
|
|
|
frame #0: 0x0000000100010d5b, where = Sketch`-[SKTGraphicView alignLeftEdges:] + 33 at /Projects/Sketch/SKTGraphicView.m:1405
|
|
|
|
frame #1: 0x00007fff8602d152, where = AppKit`-[NSApplication sendAction:to:from:] + 95
|
|
|
|
frame #2: 0x00007fff860516be, where = AppKit`-[NSMenuItem _corePerformAction] + 365
|
|
|
|
frame #3: 0x00007fff86051428, where = AppKit`-[NSCarbonMenuImpl performActionWithHighlightingForItemAtIndex:] + 121
|
|
|
|
frame #4: 0x00007fff860370c1, where = AppKit`-[NSMenu performKeyEquivalent:] + 272
|
|
|
|
frame #5: 0x00007fff86035e69, where = AppKit`-[NSApplication _handleKeyEquivalent:] + 559
|
|
|
|
frame #6: 0x00007fff85f06aa1, where = AppKit`-[NSApplication sendEvent:] + 3630
|
|
|
|
frame #7: 0x00007fff85e9d922, where = AppKit`-[NSApplication run] + 474
|
|
|
|
frame #8: 0x00007fff85e965f8, where = AppKit`NSApplicationMain + 364
|
|
|
|
frame #9: 0x0000000100015ae3, where = Sketch`main + 33 at /Projects/Sketch/SKTMain.m:11
|
|
|
|
frame #10: 0x0000000100000f20, where = Sketch`start + 52
|
|
|
|
|
2024-05-01 10:00:12 +01:00
|
|
|
You can also provide a list of threads to backtrace, or the keyword ``all`` to see all threads:
|
2019-01-30 18:51:40 +00:00
|
|
|
|
|
|
|
::
|
|
|
|
|
|
|
|
(lldb) thread backtrace all
|
|
|
|
|
|
|
|
You can select the current thread, which will be used by default in all the
|
2024-05-01 10:00:12 +01:00
|
|
|
commands in the next section, with the ``thread select`` command:
|
2019-01-30 18:51:40 +00:00
|
|
|
|
|
|
|
::
|
|
|
|
|
|
|
|
(lldb) thread select 2
|
|
|
|
|
2024-05-01 10:00:12 +01:00
|
|
|
where the thread index is just the one shown in the ``thread list`` listing.
|
2019-01-30 18:51:40 +00:00
|
|
|
|
|
|
|
|
|
|
|
Examining Stack Frame State
|
|
|
|
---------------------------
|
|
|
|
|
|
|
|
The most convenient way to inspect a frame's arguments and local variables is
|
2024-05-01 10:00:12 +01:00
|
|
|
to use the ``frame variable`` command:
|
2019-01-30 18:51:40 +00:00
|
|
|
|
|
|
|
::
|
|
|
|
|
|
|
|
(lldb) frame variable
|
|
|
|
self = (SKTGraphicView *) 0x0000000100208b40
|
|
|
|
_cmd = (struct objc_selector *) 0x000000010001bae1
|
|
|
|
sender = (id) 0x00000001001264e0
|
|
|
|
selection = (NSArray *) 0x00000001001264e0
|
|
|
|
i = (NSUInteger) 0x00000001001264e0
|
|
|
|
c = (NSUInteger) 0x00000001001253b0
|
|
|
|
|
2024-05-01 10:00:12 +01:00
|
|
|
As you see above, if you do not specify any variable names, all arguments and
|
|
|
|
locals will be shown. If you call ``frame variable`` passing in the names of
|
|
|
|
particular local variables, only those variables will be printed. For instance:
|
2019-01-30 18:51:40 +00:00
|
|
|
|
|
|
|
::
|
|
|
|
|
|
|
|
(lldb) frame variable self
|
|
|
|
(SKTGraphicView *) self = 0x0000000100208b40
|
|
|
|
|
2024-05-01 10:00:12 +01:00
|
|
|
You can also pass in a path to some sub-element of one of the available locals,
|
2019-01-30 18:51:40 +00:00
|
|
|
and that sub-element will be printed. For instance:
|
|
|
|
|
|
|
|
::
|
|
|
|
|
|
|
|
(lldb) frame variable self.isa
|
|
|
|
(struct objc_class *) self.isa = 0x0000000100023730
|
|
|
|
|
2024-05-01 10:00:12 +01:00
|
|
|
The ``frame variable`` command is not a full expression parser but it does
|
2019-01-30 18:51:40 +00:00
|
|
|
support a few simple operations like ``&``, ``*``, ``->``, ``[]`` (no
|
|
|
|
overloaded operators). The array brackets can be used on pointers to treat
|
|
|
|
pointers as arrays:
|
|
|
|
|
|
|
|
::
|
|
|
|
|
|
|
|
(lldb) frame variable *self
|
|
|
|
(SKTGraphicView *) self = 0x0000000100208b40
|
|
|
|
(NSView) NSView = {
|
|
|
|
(NSResponder) NSResponder = {
|
|
|
|
...
|
|
|
|
|
|
|
|
(lldb) frame variable &self
|
|
|
|
(SKTGraphicView **) &self = 0x0000000100304ab
|
|
|
|
|
|
|
|
(lldb) frame variable argv[0]
|
|
|
|
(char const *) argv[0] = 0x00007fff5fbffaf8 "/Projects/Sketch/build/Debug/Sketch.app/Contents/MacOS/Sketch"
|
|
|
|
|
|
|
|
The frame variable command will also perform "object printing" operations on
|
2024-05-02 08:45:48 +01:00
|
|
|
variables (currently LLDB only supports ObjC printing, using the object's
|
2024-05-01 10:00:12 +01:00
|
|
|
``description`` method. Turn this on by passing the ``-o`` flag to frame variable:
|
2019-01-30 18:51:40 +00:00
|
|
|
|
|
|
|
::
|
|
|
|
|
|
|
|
(lldb) frame variable -o self (SKTGraphicView *) self = 0x0000000100208b40 <SKTGraphicView: 0x100208b40>
|
|
|
|
You can select another frame to view with the "frame select" command
|
|
|
|
|
|
|
|
(lldb) frame select 9
|
|
|
|
frame #9: 0x0000000100015ae3, where = Sketch`function1 + 33 at /Projects/Sketch/SKTFunctions.m:11
|
|
|
|
|
2024-05-01 10:00:12 +01:00
|
|
|
You can also move up and down the stack by passing the ``--relative`` (``-r``) option.
|
2024-05-02 08:45:48 +01:00
|
|
|
We also have built-in aliases ``u`` and ``d`` which behave like their GDB equivalents.
|