forked from OSchip/llvm-project
Adding some docs on how to use lldb. First cut...
llvm-svn: 113046
This commit is contained in:
parent
9f8e704151
commit
56f4ee05e9
|
@ -0,0 +1,405 @@
|
|||
Here's a short precis of how to run lldb if you are familiar with the
|
||||
gdb command set:
|
||||
|
||||
|
||||
1) LLDB Command Structure:
|
||||
|
||||
First some details on lldb command structure to help orient you...
|
||||
|
||||
Unlike gdb's command set, which is rather free-form, we tried to make
|
||||
the lldb command set fairly structured. The commands are all of the
|
||||
form
|
||||
|
||||
<noun> <verb> [-options [option-value]] [argument [argument...]]
|
||||
|
||||
We also tried to reduce the number of special purpose argument
|
||||
parsers, which sometimes forces the user to be a little more explicit
|
||||
about stating their intentions. The first instance you'll note of
|
||||
this is the breakpoint command. In gdb, to set a breakpoint, you
|
||||
would just say:
|
||||
|
||||
(gdb) break set foo.c:12
|
||||
|
||||
or
|
||||
|
||||
(gdb) break set foo
|
||||
|
||||
if foo is a function. 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 and bizarre, and especially in C++
|
||||
there are times where there's really no way to specify the function
|
||||
you want to break on. The lldb commands are more verbose but also precise.
|
||||
So you say:
|
||||
|
||||
(lldb) breakpoint set -f foo.c -l 12
|
||||
|
||||
to set a file & line breakpoint. To set a breakpoint on a function by name, you do:
|
||||
|
||||
(lldb) breakpoint set -n foo
|
||||
|
||||
This can allow us to be more expressive, so you can say:
|
||||
|
||||
(lldb) breakpoint set -M foo
|
||||
|
||||
to break on all methods named foo, or:
|
||||
|
||||
(lldb) breakpoint set -S alignLeftEdges:
|
||||
|
||||
to set a breakpoint on all ObjC selectors called alignLeftEdges:. It
|
||||
also makes it easy to compose specifications, like:
|
||||
|
||||
(lldb) breakpoint set -s foo.dylib -n foo
|
||||
|
||||
for all functions called foo in the shared library foo.dylib. Suggestions
|
||||
on more interesting primitives of this sort are also very welcome.
|
||||
|
||||
The next structural difference between lldb & gdb is that the command
|
||||
line is actually parsed by the command interpreter not the commands.
|
||||
That means the command syntax is more regular, but it also means you
|
||||
may have to quote some arguments in lldb that you wouldn't in gdb.
|
||||
But the command syntax is very simple, basically arguments, options
|
||||
and option values are all white-space separated. If you need to put a
|
||||
backslash or double-quote character in an argument you back-slash it
|
||||
in the argument. So for instance:
|
||||
|
||||
(lldb) breakpoint set -n "-[SKTGraphicView alignLeftEdges:]"
|
||||
|
||||
Just like gdb, the lldb command interpreter does a shortest unique
|
||||
string match on command names, so the previous command can also be
|
||||
typed:
|
||||
|
||||
(lldb) b s -n "-[SKTGraphicView alignLeftEdges:]"
|
||||
|
||||
lldb also supports command completion for source file names, symbol
|
||||
names, file names, etc. Completion is initiated by a hitting a <TAB>.
|
||||
Individual options a command can have different completers, so for
|
||||
instance the -f option in "breakpoint" completes to source files, the
|
||||
-s option to currently loaded dylibs, etc... We can even do things
|
||||
like if you specify -s, and are completing on -f, we will only
|
||||
list source files in the dylib specified by -s...
|
||||
|
||||
The individual commands are pretty extensively documented, using
|
||||
with the "help" command. And there is an "apropos" command that will
|
||||
search the help 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. So for instance if you get annoyed typing
|
||||
|
||||
(lldb) b s -f foo.c -l 12
|
||||
|
||||
you can do:
|
||||
|
||||
(lldb) command alias bfl breakpoint set -f %1 -l %2
|
||||
(lldb) bfl foo.c 12
|
||||
|
||||
We have added a few aliases for commonly used commands (e.g. "step",
|
||||
"next" and "continue") but we haven't tried to be exhaustive because
|
||||
in our experience it is more convenient to make the basic commands
|
||||
unique down to a letter or two, and then learn these sequences than
|
||||
fill the namespace with lots of aliases, and then have to type them
|
||||
all the way out.
|
||||
|
||||
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 aliases there and they will be generally available to
|
||||
you. Your aliases are also documented in the help command so you can
|
||||
remind yourself of what you've set up.
|
||||
|
||||
lldb also has a built-in Python interpreter, which is accessible by
|
||||
the "script" command. All the functionality of the debugger is
|
||||
available as classes in the Python interpreter, so the more complex
|
||||
commands that in gdb you would introduce with the "define" command can
|
||||
be done by writing Python functions using the lldb-Python library,
|
||||
then loading the scripts into your running session and accessing them
|
||||
with the "script" command.
|
||||
|
||||
|
||||
|
||||
2) A typical session:
|
||||
|
||||
|
||||
a) Setting the program to debug:
|
||||
|
||||
|
||||
As with gdb, you can start lldb and specify the file you wish to debug
|
||||
on the command line:
|
||||
|
||||
$ lldb /Projects/Sketch/build/Debug/Sketch.app
|
||||
Current executable set to '/Projects/Sketch/build/Debug/Sketch.app' (x86_64).
|
||||
|
||||
or you can specify it after the fact with the "file" command:
|
||||
|
||||
(lldb) file /Projects/Sketch/build/Debug/Sketch.app
|
||||
Current executable set to '/Projects/Sketch/build/Debug/Sketch.app' (x86_64).
|
||||
|
||||
|
||||
b) Setting breakpoints:
|
||||
|
||||
|
||||
We've discussed how to set breakpoints above. You can use "help break set"
|
||||
to see all the options for breakpoint setting. For instance, we might do:
|
||||
|
||||
(lldb) b s -S alignLeftEdges:
|
||||
Breakpoint created: 1: name = 'alignLeftEdges:', locations = 1, resolved = 1
|
||||
|
||||
You can find out about the breakpoints you've set with:
|
||||
|
||||
(lldb) break list
|
||||
Current breakpoints:
|
||||
1: name = 'alignLeftEdges:', locations = 1, resolved = 1
|
||||
1.1: where = Sketch`-[SKTGraphicView alignLeftEdges:] + 33 at /Volumes/ThePlayground/Users/jingham/Projects/Sketch/SKTGraphicView.m:1405, address = 0x0000000100010d5b, resolved, hit count = 0
|
||||
|
||||
Note that each "logical" breakpoint can have multiple resolved
|
||||
"locations". The logical breakpoint has an integer id, and it's
|
||||
locations have a an id within their parent breakpoint (the two are
|
||||
joined by a ".", e.g. 1.1 in the example above.) Also the breakpoints
|
||||
remain "live" so that if another shared library were to be loaded that
|
||||
had another implementation of the "alignLeftEdges:" selector, and new
|
||||
location would be added to the breakpoint 1 for it.
|
||||
|
||||
You can delete, disable, set conditions and ignore counts either on
|
||||
all the locations generated by your logical breakpoint. So for
|
||||
instance if we wanted to add a command to print a backtrace when we
|
||||
hit this breakpoint we could do:
|
||||
|
||||
(lldb) b command add -c 1.1
|
||||
Enter your debugger command(s). Type 'DONE' to end.
|
||||
> bt
|
||||
> DONE
|
||||
|
||||
The "-c" specifies that the breakpoint command is a set of lldb
|
||||
commmand interpreter commands. Use "-s" if you want to implement your
|
||||
breakpoint command using the lldb Python interface instead.
|
||||
|
||||
|
||||
c) Running the program:
|
||||
|
||||
Then you can either launch the process with the command:
|
||||
|
||||
(lldb) process launch
|
||||
|
||||
or its alias:
|
||||
|
||||
(lldb) r
|
||||
|
||||
Or you can attach to a process by name with:
|
||||
|
||||
(lldb) process attach -n Sketch
|
||||
|
||||
the "attach by name" also supports the "-w" option which waits for the
|
||||
next process of that name to show up, and attaches to that. You can also
|
||||
attach by PID:
|
||||
|
||||
(lldb) process attach -p 12345
|
||||
Process 46915 Attaching
|
||||
(lldb) 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
|
||||
|
||||
Note that we tell you that "1 of 3 threads stopped with reasons" and
|
||||
then list those threads. 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.
|
||||
|
||||
|
||||
d) Controlling execution:
|
||||
|
||||
|
||||
Then we can continue till we hit our breakpoint. The primitive
|
||||
commands for process control all exist under the "thread" command:
|
||||
|
||||
(lldb) thread continue
|
||||
Resuming thread 0x2c03 in process 46915
|
||||
Resuming process 46915
|
||||
(lldb)
|
||||
|
||||
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 function in Thread 2, and continue Thread
|
||||
3" etc. When we eventually support keeping some threads running while
|
||||
others are stopped this will be particularly important. For
|
||||
convenience, however, all the stepping type commands have easy
|
||||
aliases. So "thread continue" is just "c", etc.
|
||||
|
||||
The other program stepping commands are pretty much the same as in gdb. You've got:
|
||||
|
||||
(lldb) thread step-in
|
||||
|
||||
which is the same as gdb's "step" or the alias:
|
||||
|
||||
(lldb) s
|
||||
|
||||
(lldb) thread step-over
|
||||
|
||||
which is the same as gdb's "next" and is aliased to
|
||||
|
||||
(lldb) n
|
||||
|
||||
(lldb) thread step-out
|
||||
|
||||
which is the same as gdb's "finish" and is aliased to
|
||||
|
||||
(lldb) f
|
||||
|
||||
And the "by instruction" versions:
|
||||
|
||||
(lldb) thread step-inst
|
||||
(lldb) thread step-over-inst
|
||||
|
||||
Finally, there's:
|
||||
|
||||
(lldb) thread until 100
|
||||
|
||||
which runs the thread in the current frame till it reaches line 100 in
|
||||
this frame or stops if it leaves the current frame. This is a pretty
|
||||
close equivalent to gdb's until command.
|
||||
|
||||
|
||||
One thing here that might be a little disconcerting to gdb users here
|
||||
is that when you resume you immediately get a prompt back. That's
|
||||
because the lldb interpreter remains live when you are running the
|
||||
target. This allows you to set a breakpoint, etc without having to
|
||||
explicitly interrupt the program you are debugging. We're still
|
||||
working out all the operations that it is safe to do while running.
|
||||
But this way of operation will set us up for "no stop" debugging when
|
||||
we get to implementing that.
|
||||
|
||||
If you want to interrupt a running program do:
|
||||
|
||||
(lldb) process interrupt
|
||||
|
||||
To find out the state of the program, use:
|
||||
|
||||
(lldb) process status
|
||||
Process 47958 is running.
|
||||
|
||||
This is very convenient, but it does have the down-side that debugging
|
||||
programs that use stdin is no longer as straightforward. For now, you
|
||||
have to specify another tty to use as the program stdout & stdin using
|
||||
the appropriate options to "process launch", or start your program in
|
||||
another terminal and catch it with "process attach -w". We will come
|
||||
up with some more convenient way to juggle the terminal back & forth
|
||||
over time.
|
||||
|
||||
|
||||
e) Examining program state:
|
||||
|
||||
Once you've stopped, lldb will choose a current thread, usually the
|
||||
one that stopped "for a reason", and a current frame in that thread.
|
||||
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
|
||||
|
||||
You can also provide a list of threads to backtrace, or the keyword
|
||||
"all" to see all threads:
|
||||
|
||||
(lldb) thread backtrace all...
|
||||
|
||||
Next task is inspecting data:
|
||||
|
||||
The most convenient way to inspect a frame's arguments and local variables is:
|
||||
|
||||
(lldb) frame variable
|
||||
self = (SKTGraphicView *) 0x0000000100208b40
|
||||
_cmd = (struct objc_selector *) 0x000000010001bae1
|
||||
sender = (id) 0x00000001001264e0
|
||||
selection = (NSArray *) 0x00000001001264e0
|
||||
i = (NSUInteger) 0x00000001001264e0
|
||||
c = (NSUInteger) 0x00000001001253b0
|
||||
|
||||
You can also choose particular variables to view:
|
||||
|
||||
(lldb) frame variable self
|
||||
(SKTGraphicView *) self = 0x0000000100208b40
|
||||
|
||||
The frame variable command is not a full expression parser but it does support some common operations like defererencing:
|
||||
|
||||
(lldb) fr v *self
|
||||
(SKTGraphicView *) self = 0x0000000100208b40
|
||||
(NSView) NSView = {
|
||||
(NSResponder) NSResponder = {
|
||||
...
|
||||
|
||||
and structure element references:
|
||||
|
||||
(lldb) frame variable self.NS(lldb) frame variable self.isa
|
||||
(struct objc_class *) self.isa = 0x0000000100023730
|
||||
|
||||
The frame variable command will also perform "object printing" operations on variables (currently we
|
||||
only support NSPrintForDebugger) with:
|
||||
|
||||
(lldb) fr v -o self
|
||||
(SKTGraphicView *) self = 0x0000000100208b40
|
||||
<SKTGraphicView: 0x100208b40>
|
||||
|
||||
You can select another frame to view with:
|
||||
|
||||
(lldb) frame select 9
|
||||
frame #9: 0x0000000100015ae3, where = Sketch`main + 33 at /Projects/Sketch/SKTMain.m:11
|
||||
8
|
||||
9
|
||||
10 int main(int argc, const char *argv[]) {
|
||||
11 -> return NSApplicationMain(argc, argv);
|
||||
12 }
|
||||
13
|
||||
14
|
||||
|
||||
Another neat trick that the variable list does is array references, so:
|
||||
|
||||
(lldb) fr v argv[0]
|
||||
(char const *) argv[0] = 0x00007fff5fbffaf8 "/Projects/Sketch/build/Debug/Sketch.app/Contents/MacOS/Sketch"
|
||||
|
||||
If you need to view more complex data or change program data, you can
|
||||
use the general "expression" command. It takes an expression and
|
||||
evaluates it in the scope of the currently selected frame. For instance:
|
||||
|
||||
(lldb) expr self
|
||||
$0 = (SKTGraphicView *) 0x0000000100135430
|
||||
(lldb) expr self = 0x00
|
||||
$1 = (SKTGraphicView *) 0x0000000000000000
|
||||
(lldb) frame var self
|
||||
(SKTGraphicView *) self = 0x0000000000000000
|
||||
|
||||
You can also call functions:
|
||||
|
||||
(lldb) expr (int) printf ("I have a pointer 0x%llx.\n", self)
|
||||
$2 = (int) 22
|
||||
I have a pointer 0x0.
|
||||
|
||||
One thing to note from this example is that lldb commands can be
|
||||
defined to take "raw" input. "expression" is one of these. So in the expression command,
|
||||
you don't have to quote your whole expression, nor backslash protect quotes, etc...
|
||||
|
||||
Finally, the results of the expressions are stored in persistent
|
||||
variables (of the form \$([0-9])+) that you can use in further expressions, like:
|
||||
|
||||
(lldb) expr self = $0
|
||||
$4 = (SKTGraphicView *) 0x0000000100135430
|
Loading…
Reference in New Issue