WWDC2013 Session 413

Transcript

X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
>> Good morning and welcome to
Advanced Debugging with LLDB.
[ Applause ]
I hope you're having
a great show so far,
we've got one last day
of content for you.
So let's make the most of
it by starting with one
of the more important
topics when it comes
to software development, making
sure that everything is clean
and polished in your
application before it goes live.
My name is Kate Stone I manage
the team responsible for LLDB.
I'm going to get things
going here, but I'm going
to spend most of the time in
the session turning things
over to my engineers who
walk you through some
of the exciting things
that we love about LLDB
that you deserve
to know about too.
So what should you
expect from this talk?
Well, the vast majority of
our time here is spent focused
on LLDB as the foundation
for the debugging experience.
LLDB is essentially a library
that knows how to do all kinds
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
of interesting things with
the running application.
It's a command line experience
but it's also the
foundation for Xcode.
So while we'll talk about how
to use it from a command line,
we'll talk about
the Xcode experience
to really understand
what Xcode adds on top
of our debugging
foundation, you should go back
and watch the video for the
debugging with Xcode session,
which unfortunately, it
was earlier this week,
but there's a lot
of good news there.
What we're going to
talk about here are tips
to streamline your
debugging experience.
So you've doubtless know a
lot about debugging already,
but if you haven't worked
with LLDB extensively,
you may not be aware
of everything
that you can do with
the product.
And specifically, we're going to
talk about it not just as a tool
for finding and fixing bugs.
But we're going to talk about,
it is an investigative tool
for looking at your application,
understanding what's going on,
perhaps when you've written a
new feature to walk through it
to make sure that it's working
the way you expect it to.
It's not always about going in
and finding a specific
defect in your code.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
Because our collective
goal is to make sure
that your applications
are as reliable as solid
as they can possibly be by the
time they reach your end users.
So that's our focus
for the session.
Let's keep our eye in
your apps and making sure
that they can be the
best apps possible.
What does LLDB look like today?
Well, LLDB as you know is our
ground-up replacement for GDB.
We both-- from the ground-up
this tool, this is designed
to be incredibly
flexible, this is designed
to accommodate the needs
of applications looking
forward rather than backward.
So with that in mind, we
focused on making sure
that it is absolutely
rock solid, this release.
If you have any issues,
whatsoever,
make sure that we
hear about them
because when Xcode5
shifts LLDB will be your
debugging experience.
What have we done?
We've put in hundreds of
improvements this release.
A lot of them are relatively
subtle, you'll see a lot
of the old features working
faster, more predictably
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
with fewer edge cases
that you need to worry
about than never before.
But we've also focused on
data inspection in particular.
When you're looking at
standard system types,
when you're looking at
anything from foundation
or if you're looking for a
C++ standard library type,
you should get a more reasonable
summary now, you should be able
to get summaries for things
like NSErrors, for NSSets,
things that, again, you
could dig in to before
but now we'll tell
you the information
that you were looking for
right out of the gate.
Our expression parser
is always improving.
It's not necessarily something
that my team is responsible for,
more importantly because my team
took the idea that we wanted
to rely on clang as
our expression parser.
We have a full compiler built
into the product, any expression
that would normally
parse and run as part
of your source code will
work in LLDB as well.
So we're always up-to-date with
the latest language features.
When we added things along
the lines of the new syntax
for Objective-C,
Objective-Constants,
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
they just showed up in LLDB and
that's through going forward
as well, every new language
feature should be part
of our debugger.
One of the things that's tricky
about this is while we pass
the text that you give us
for an expression
directly to the compiler,
the context that we set
up for, we have to infer
from looking at that code.
So as a result, you may
have found in the past
that you needed to
cast the result
so that we knew what
the result type was
and could explore
it appropriately.
You'll find that in most
cases, we can now infer that
and far fewer explicit
casts are required
for the expression evaluator.
[ Applause ]
So let's think a little bit
about the debugging experience.
What is it that you should do?
Well, to start with,
you should go
into debugging a
particular problem
or exploring something
really well-informed.
There are a bunch of
techniques for doing this
that we'll cover
in detail later.
They should be familiar
ideas, things like assertions
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
and logging, static
analysis, and using some
of the runtime tools that
will watch your code for us
and tell you, here's
what's going
on that you might
need to be aware of.
But you should also
focus on unit tests.
A unit test will tell you that
this is the narrow situation
in which your code is
not behaving the way you
expected to.
So if you are already
writing a lot of unit test,
make sure you review the
unit testing in Xcode session
to get some idea
what that intends.
And lastly, we need to trust
the Xcode debug configuration.
Out of the box, a new project
in Xcode will be configured
to build debug information,
you need to make sure that,
that's what you're
feeding to the debugger
that you weren't
stripping that away
or else you won't be
able to find symbols.
You need to make sure that
optimization is disabled
which it is by default or
you'll find that stepping
through your code and
leads to surprises.
If you attach to a running
application, you may find
that these have not
been taken care of,
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
that's why you're not getting
the information you need
if that's why you're
not stepping
through code in a
logical fashion.
Going back in building with the
debug configuration is always a
good idea for debug session.
Secondly, we need to avoid
some of the common mistakes.
You can go and you can do
the brute-force debugging.
Everybody knows how to do
this, set a breakpoint right
at the beginning of our
code and step, step our way
to where we need to get to.
But in practice, that's
not the most efficient way
to take advantage of LLDB.
So during the session, we'll
talk about how to stop exactly
where you want to, not keep
running 20 times until you get
to the right pass,
how to stop actually
under the conditions
you're interested in.
How to then customize
what you're seeing
with custom formatters
and custom commands
because we're going to give
you a reasonable format
for system types, but we don't
know about your types yet.
We'll allow you to
introduce us to your types
and tell us what's
interesting about them.
And lastly, we want to focus
on how you can write debug code
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
without stopping your
project altering your source,
going through rebuild
cycle and then trying
to get back to that state.
Because again, we've got a
full expression evaluator,
you can write incredibly
sophisticated code right there
in the debugger to alter the way
your application is executing
and explore things that
your source may not
yet be set up for.
Along the way though, especially
when you're taking the advantage
of the expression evaluator, you
should watch out for the fact
that while the debugger
goes well out of its way
to avoid side effects.
If you're telling us explicitly
to run some code, we are running
that code in your
live application,
it can change the state of
things that can be a good thing
if your intent is to try to work
around an issue during the
debug session or a bad thing
if you're trying to see exactly
what your application is going
to do without the
debugger attached.
So for the rest of this session,
the focus is this
canonical process
of how do I use the
debugger each and every time
to catch those tasty bugs?
The answer is step one we
need to pick our focus.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
We need to choose what it is
that we're trying
to investigate?
What's the question
that we have in mind
that the debugger
can help answer?
Step two, how do I stop right
before the interesting path
before the problem has
occurred but not so far from it
that we're going to be
stepping endlessly to get there.
Then we need to step
through our live code looking
at the interesting things
that are going on the path
that it's following, and
looking at data along the way.
So we understand the
state of our application
and the changes that
are being made.
So our focus here is to help you
be experts at all of the above.
To get it started, I'd like
to invite up Sean Callan,
one of my engineers
who will walk you
through a few incredibly
helpful tips at the start
of this process, but you should
also tackle them in the labs,
if you have any questions at all
about the expression evaluator
because he is our
expert on the subject.
Thank you, Sean.
>> Thank you very much, Kate.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
I'm really excited to show you
all the great ways you can debug
with LLDB.
But I think one of the most
important things to understand
when you're debugging is when
to use LLDB and what sort
of information can help you
out when you're debugging.
So one situation where LLDB
might not be the first stop
for you is if you're not sure
whether your program has a bug
in the first place.
One way you can check, whether
what your assumptions are,
or actually what's happening
in your code is by
using assertions.
Now what assertions
let you do is express
that you make a particular
assumption
and you believe this
is not only unlikely
but it's actually impossible.
Now remember, as programmers, we
want to be using arrow handling
to count, to handle the cases
that we actually think are
possible just, you know,
that are, that where our
program won't work correctly.
So this is really for
cases where your app is,
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
has encountered something
that just can't be.
Now another case where
assertions can be handy is
if you have internal
APIs between components
and they have contract between
them that shouldn't be violated.
Now remember, that's
for internal APIs.
For external APIs,
you really want
to be using correct
error handling.
What an assertion will do is
if this contract is violated,
your application will
crash right then and there.
Now having your application
crash deliberately isn't exactly
a recipe for good
reviews on the App Store.
So you want to make sure that
the assertions are disabled
when you build release.
Xcode does that for you and
now default project templates,
we've disabled assertions
when you build release.
Now there's one other thing
about assertions you
have to be aware of.
When you've got an assertion
compiled into your code,
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
the condition is evaluated
only if the assertion is there.
So your condition should
not do useful work otherwise
when you build release
that useful work is gone.
All right.
Now let's say, you don't have
a clear red flag that says, OK,
something's going wrong.
You more have behaviors in your
app where over a period of time,
your app gets, you know, through
code pass that look reasonable
but ends up somewhere
where it shouldn't be.
This is where logging
can be really handy.
Now you all maybe familiar
with NSLog, but what I'm going
to tell you about is
the Apple System Log.
Logging let's you review
execution of your code
after the fact and
the Apple System Log,
you can review using the
console.app utility on your Mac.
One great feature of the Apple
System Log is you can indicate
how severe the log messages
are that you're sending out.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
You can distinguish between
absolute emergencies, oh,
my God, stop now,
this is terrible.
And just debug information that
you want to communicate just
to let into the program or
the user know what's going on.
Now I've shown you two
levels, the most severe
and the least severe,
but there's a gradient
in between them that
you can use.
Now another cool thing you
can do with logging is,
you can use hashtags
kind of like in Twitter.
Now hastags are not some
magic, you just search for them
in console.app and you can find
all the logs that are relevant
to that part of your program.
One other single-- to
remember with logs is,
sometimes you get really
enthusiastic and you're like,
oh, I love this logging thing,
I'm going to dump all my data
structures out to the log just
to see what could
might, maybe go wrong.
Now that's going to mean, your
program is going to spend time
in looking through with
state of structures
and printing everything.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
Now maybe, you want to
turn that on and off
so that your program isn't
spending all that time
when you don't care about it.
Now there are a couple of ways
doing this and I'm not going
to tell you anyway this
app is terribly wrong.
I've seen people use
compile-time debug--
compile-time hash defines to
enable and disable logging.
I've also seen people use
environment variables.
One of my favorite
ways of enabling
and disabling logging is using
the NSUserDefault subsystem.
With NSUserDefaults which
you can look up in man pages,
you can set a variable and pick
up from the command line that is
from your shell and
just picks that up
from your app as it's running.
So it's a great way to
turn off and on logging.
Now, I've shown you a couple
of ways of making your program,
use your DDbug by
modifying your source code.
But we've also provided you with
some great ways inside Xcode
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
to find bugs in your program.
Double your everything in clang
and the static analyzer
are great ways
to find problems before you
even start running your program.
Another couple of tools that you
can use while your program is
running are Guard Malloc
and Zombie Objects.
Now there are great
sessions both this year
and in previous years which
cover both of these areas.
So I'm not going to go
into too much detail,
but do check those out.
All right.
Now we've gone on and off
about what to do before you get
into LLDB, I kind of like
spending time in LLDB,
so let's get right in there.
Now in LLDB, there--
you're going to have two
general ways of doing things.
This going to be the way by
clicking buttons in Xcode
which is really nice and
convenient for many cases.
And we also have a command
language that you can use
through the LLDB
console to achieve many
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
of the same things
and a couple more.
The reason you might want
to use the LLDB console even
when there's an equivalent
Xcode function is
that it's a great way of keeping
a record of what you've done
in the past and how you got into
the situation you're in now.
Now commands in the LLDB
console have a couple of forms.
There's the most discoverable
form, for each command
that let's you find it easily
through the help system.
Also the options in this most
discoverable form, very verbose
and you can see exactly what
this command is trying to do.
So for example, if you
want to run an expression,
get the result of it and pass
the description method to it,
assuming it's an
Objective-C object,
then you can say
expression-- object description,
and then type what
you want to output.
Now, after you've used
that a couple of times,
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
you're probably going to say,
well that's a lot to type.
And we provided abbreviated
forms of these for you.
Now this isn't any magic,
you just hacked off the
tail end of expression.
You shortened object description
down to a single letter.
That's a great way of typing
common things very quickly.
Another way that we provide,
when there's a command
that you use a lot, and
you use a particular set
of options with it is aliases.
Now in this case,
we have the PO alias
which probably many of you know.
But the great thing is,
we've also provided you ways
to write your own aliases.
And while I'm not going to
go into this these this talk,
last year's LLDB talk
shows you how to do that.
What I'm going to show you
in this talk is both
the shortest form
which maybe an alias and
the long form if you want
to explore it on your own.
All right.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
Now that I've gotten through the
background, let's show you how
to stop your program with LLDB.
One of the most important parts
of the debugging process is
stopping before your bug occurs.
Now here, I have two
sub classes of UIView
and both implement
the drawRect method.
What I want to see is how
can I stop at these methods,
what different ways
does LLDB provide?.
Well, the most common
one is probably stopping
at a particular line
in the source code.
Now this is very easy to
tell LLDB, I want to stop
at a particular file
in the line.
Now if the same thing
can be done in Xcode,
simply by clicking
next to that line.
That's a breakpoint right there.
Now this is something you've
probably done very often.
On the other hand, if you don't
know the filing by line number,
you can tell LLDB, just
stop at this method
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
and just make sure you include
the dash and the brackets.
But LLDB will stop even
if you don't know what the
filing by line number are.
You can do the same
thing in Xcode
by clicking the little plus
sign at the bottom left
of the breakpoint navigator
and then clicking add
symbolic breakpoint.
In the window that pops up,
you can type the name, again,
remembering the dash
and brackets.
There's a third way that you
can do from the LLDB console
which is stopping whenever
any object receives a
particular selector.
This is great if you've
gotten multiple objects
that implement the same
selector, for example drawRect.
All right.
Now you've set your breakpoint,
but I'm sure you've--
many of you have encountered
breakpoints that you hit over
and over again and constantly,
you're going back and forth
between your app triggering
breakpoints and OK,
back to Xcode, doing something
at the console, then going back
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
to your app doing some what--
this hopping back and forth
can get really frustrating
over time.
To help you out in
those situations,
we've provided the facility
of breakpoint commands.
Breakpoint commands
are a way to tell LLDB,
I want you to do this set
of actions each time
you hit the breakpoint.
Now those actions can
collect some data for you.
In this case, when you
need to redisplay a Rect,
we print the Rect that
you've been provided with,
and you can also get a back
trace of the current thread
to tell you who told
you about this.
Now one other cool
thing you can do is,
you can actually just
continue your process
after you hit that breakpoint.
This is really handy because it
means you can do all your app
interaction that
triggers all these events.
And then go to Xcode afterwards
and see all the output
from your commands.
There's a way to do
this in Xcode too.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
You select the breakpoint,
you right-click,
click Edit Breakpoint, and then
there's the Add Action button
in this little window
that pops up.
You click Add Action, and
then, you can click Plus
to add more commands then
you type in the commands.
The only difference between
the way you do it in LLDB
and the way you do
it in Xcode is
that there's a little
check box that tells you
that you can continue
after evaluating.
Now in this case, we
actually want to do that.
All right.
So breakpoint commands
are great.
But there's another
type of situation
in which breakpoints
are frustrating to use.
If you have a situation where
you hit a breakpoint a bunch
of times but most times
you actually don't care,
that's the time when
you might want
to use a breakpoint condition.
So let's look at
this example here,
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
I'm stopped at the Init function
for a class I wrote and I want
to see when that class is, when
that exact object is the alloc.
Now here's where my favorite
part because we're going to get
to use clang to help us out.
So we're using the
expression command again
and inside the expression
command,
notice we're doing
something interesting.
We are declaring a variable
and setting it equal to self.
Now the only thing we have to do
here that's unusual is we have
to put a dollar sign
as the first character
in the variables name.
The reason we have
a dollar sign is
because that tells LLDB,
hey, remember this.
Then later, when we set the
condition of the breakpoint,
we can refer back
to that variable.
So we can stop it the alloc
only when self is equal
to the current value of self.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
That's really handy and you
can do in the next code too.
So you have to set the
variable at the LLDB console
like I showed you just there.
And then, you set the condition
by clicking edit breakpoint
and putting your
breakpoint condition
into the condition field here.
Now that's going to
cover probably most
of the cases you run into.
But there are rare cases where
you actually want to look
at modifications to a very
specific variable in memory.
In those cases, you may want to
use LLDB's watchpoint facility.
Now watchpoints let you stop
when a particular location
in memory is modified and you
tell LLDB about that location
in memory by giving it the name
of a variable that's
at that location.
In this case, you use the
watchpoint set variable command
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
to do so and LLDB will stop the
program whenever it modifies
that variable.
Now there is a caveat here.
We could implement this by
single-stepping your program
and constantly looking, oh,
is this instruction modified
app location, does this?
The problem with that
is it's really slow.
So we use special CPU support
to make this a lot faster.
Intel CPUs provide four
slots for watchpoints
and on ARM we support two slots.
So remember, the number of
watchpoints you have is limited
so use them effectively and
delete them when you're done.
You can also use
watchpoints in Xcode.
If you have the variable
visible in the variables view,
you can right-click
on it, click Watch.
And then afterwards, if you
click Continue, you'll stop.
Now notice here we've
stopped right
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
after we actually set the
watchpoint because we're--
we had broken first, we were
about to set the variable to No.
That if we click Continue again,
we stop where it sets
the variable to yes.
Now, one thing that I
was mentioning here,
this is a little bit different
from setting a breakpoint
where it gets set to yes because
the breakpoint would trigger
whenever any piece of code
sets a variable called needs
synchronization to yes.
The thing that happens here
is, you've set your watchpoint
on that exact copy of the
need synchronization variable
so you will only see when
your code touches that.
All right.
So now, I've shown you
how to stop your program.
Now, let's see a couple
of ways to avoid headaches
when you're actually
trying to stop your program
and make it go where you want.
One of the most annoying things
that I run into when I'm trying
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
to step is I'm at one place
in my function, I want to get
to another place and there's
like a million lines of,
you know, logging and stuff
that I don't care about,
I have to go steps,
steps, steps, steps.
And the most frust-- it's
even more frustrating
when I can step past
that line and then I got
to restart it, it's frustrating.
So I think, ah I'm
clever, all right,
I'm going to set a breakpoint
at that line and hit continue.
Well, it turns out that
line was in an if statement
and that if didn't get hit.
So now my programs run away
on me and it's frustrating.
That's what cap videos are for.
I-- now if-- I love cap
videos, but we've actually gone
to gone you're one better.
LLDB has a special
feature called thread
until which will stop at the
line you tell it to or if you're
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
about to leave the function
you're in currently thread
until you stop you then to.
So no more steps, steps, steps,
steps, just trust the LLDB
to get you where you need to go.
You can do this in Xcode as
well, let's say I'm stopped
for example at the beginning of
a loop and I don't want to have
to step overall the
loop condition code.
In Xcode I can simply click,
right-click, click continue
to hear, and Xcode
will get me there.
Now here's one other frustrating
thing that I think some
of you have run into,
that I want to tell you is
not such a bad situation.
When you're stepping
through your code
and if you have breakpoint set,
you may step over a function
that triggers a breakpoint.
In this situation, don't panic,
we've actually got a stock
and we remember what
you were doing
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
when you hit that breakpoint.
So in this case,
I'm about to step
over this function
called remove duplicates.
And if you remember
from earlier,
I had breakpoint set in there.
So I step over this and
then I hit that breakpoint.
Now some of you might
say, oh, I just, you know,
disable your breakpoints
when you step,
don't worry about that.
If you click continue here, LLDB
remembers that you were stepping
and gets you back to the
code that you cared about.
[ Applause ]
There's one other cool
thing that you can do just
from the LLDB command line and
that is call your code by hand
to trigger the breakpoints
you care about.
Sometimes you're in situations
where you're testing your code
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
and you're trying to
cover all your bases,
but you can't make one
particular method run.
Now this can be frustrating
and you're like trying
to concoct weird environments.
This is a great time for unit
test, but if you're just trying
to get this one case covered,
LLDB can help you out.
Now again, this is a
part that I really enjoy
because it uses clang and
what can be better than clang?
So the way you do this is you
use the expression command
to run the code that
you want to test.
In this case, we can call the
remove duplicates function
on self just using the
expression command.
But that's not all, we can set
a breakpoint in that function,
then pass-- ignore breakpoints
falls to the expression command.
And then, LLDB will
actually stop
when you've entered function
and you can watch it run.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
Now remember, because we're
integrated with clang,
we're actually running
the code in your program
that you type after expression.
What that means is, you actually
did remove duplicates here,
your program will run
differently after you continue.
So that's something important
to remember as you go through.
All right.
So now you've got your program
where you want it and you want
to see its data and
all it glory.
Now I'm going to call up Enrico
Granata who's developed too much
of the infrastructure
that we used
to present that data to you.
Enrico is a great guy to know
because not only does he know
about this stuff,
but he also knows
about LLDB's Python
interface, and he's going
to give you a little
bit of introduction now.
>> Thank you, Sean.
Hello, everyone.
I'm Enrico.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
I'm one of the engineers that
worked on LLDB and we're going
to be together for the
next, about 30 minutes,
and we're going to cover a
bunch of great LLDB features.
So let's get right started.
We're going to talk about
inspecting your data
and we're going to
cover three things.
We're going to talk about ways
that you can inspect
data at LLDB console.
We're going to talk about the
LLDB data formatter facility
and we're going to
cover a cool technique
that involves the
expression parser as a way
to inspect opaque data.
So inspecting data
at a command line.
Some of you have probably
used GDB quite a while
in the last few years
and you know
that there are certain commands
that you can use to get GDB
to show you your data.
And now you're transitioning to
LLDB and there are some commands
that are the same and
some that are different
and you're really
confused as to what,
you should be using
for each case.
Well, I like to think
of the LLDB facilities
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
to show data as a tool box.
I had a set of tools and I know
that each one is good
for a specific task.
And once I know that,
I can open my tool box
and I can be confident that
for each task I have at hand,
I'm going to pick
the right tool.
So what we were going to
do for the next couple
of minutes is going to
go through the toolchain
and see what we have available.
Our first command
is friend variable,
friend variable allows you to
see all the current arguments
to your function, all
the local variables,
everything that is
currently in your local scope.
If you want, you can also pass
in one or more specific names,
you can say friend variable
RC, friend variable RV,
friend variable flu bar and all
of those names will be
shown by the debugger.
Expression as Sean and Kate
mentioned before is the entry
point to our expression
parser which allows you
to execute arbitrary chunks of
data, arbitrary chunks of code.
We're actually having
clang right there,
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
that means a type
expression, you're typing code.
And that opens a local scope
for your right where you stop
in your code and what
every you take is executed
by the very same compiler that
has taken in your source code
from Xcode and made it
into the app ironic.
If you're like me though,
you're not really like to type
that much on the
command line expression,
you're like to be
quick and efficient.
So you can use B
which is an alias
for expression that we provided.
And if you're casting with
GDBs facility for formatting,
you can also use that Y,
you can say [inaudible],
we totally support that.
And for your Objective-C,
guys in the audience,
if you have an Objective-C
object and you want
to see something meaningful
about them, you can say PO.
PO will run the expression
whatever thing you pass to it
and that if the result is an
Objective-C object is going
to call the description selector
and that option show
you the result.
Description is the select
that Apple implemented
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
for see some classes, but
that you can also implement
on your very own classes
and then will get picked
in the same way by debugger.
You can implement
description to your objects
and that you can po them
at will from the debugger.
So here are the tools available
just choose the one you need
in each case and you look great.
Let's talk about another
way to look at data,
let's talk about the LLDB
data formatter facility.
And first of all, let's see
why we need the data formatter
facility at all, I could just
[inaudible] po my objects.
Well, it turns that
there's cases where raw data
which is exactly what is
in memory is not always the
easiest thing to make sense of.
We're all smart guys here, but
sometimes, it's really just
so complicated for
a person to look at
or maybe it's not our own
types, maybe we got a library
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
and we're trying to
make sense of it.
And maybe it is simply too much
of it and makes sense here,
what doesn't make sense here
just don't know I'm lost.
Let's see an example of what
exactly I'm talking about.
Let's all pretend for a
second that LLDB did not shift
with any data formatter at all.
This is what the variables
view would look like.
IM MMS array and only tells
me is its memory location.
I have an NSString, and
so it tells me it's the
memory location.
I don't think this
is really helpful.
Well, this is what you
actually get in Xcode 5.
Your MMS array is going to
tell you many objects it has,
you're going to see
each one of those.
Thank you.
And your NSString is going to
tell you what its content is
and your class instances
will tell you what class they
belong to.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
But that's just a solution with
the data types of we [inaudible]
to you, it's not a
solution with your types.
We've all been here, we're
in the variables view,
we're debugging, we
have our own objects,
we have the instances
of an address class.
And only tells me, I'm
in this memory location,
that's really helpful if I'm the
computer, but that's not helpful
if I'm the programmer.
So now I flip it open,
open to see something.
Indeed, I do, but what
string would I see here?
I see [inaudible] Enrico
Granata, California,
instance loop, what 95014.
I don't know about any of you
guys here in the audience,
but I am usually branded
and addressed that way
and I don't think the postal
service accepts addresses
written that way.
I'd really like to see something
that makes more sense to me,
I'd like to see something
like this.
I see the names of the people.
I don't see a number
that means nothing to me.
And the way to get here is
with the LLDB data formatters.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
The cool news is, we did all
the work for system libraries.
For you C++ people, your
SDL vectors, your SDL maps,
they'll show correctly.
Thank you.
And for those that actually
write Objective-C code,
we did the work for Cocoa
Foundation and Foundation.
In the Xcode 5, in addition
to what we have NSArrays
and NSDictionaries in
Xcode 5 NSS also show
with data formatters.
Great news is, we just didn't
build some hard coding notion
or what our classes look like
and left you guys
alone out in the dark.
We built a data formatter
subsystem that is pluggable
and that means that what
we did for the data types
that we invent, you
can do the same thing
for your own data types.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
So let's see exactly
what you can do,
how you can plug
in into the system.
There's two main
types of formatters.
They're summaries.
Summaries are a very quick way
to look at an option at a glance
and see what's most important
about it like the number
of items in the array.
You can also write this family
name synthetic children,
synthetic children allow
you to give structure,
aggregate structure,
the data that isn't.
I have an NSS array and I
know that it contains objects
but its underlying structure
doesn't show me that.
With synthetic children, I can
actually see the items that are
into the array as if they
really physically are right
into the array.
And here I see my NS
numbers into there.
We'll focus on giving
an example of summaries.
So let's briefly
see how they work.
Summaries worked by matching a
data type to a Python function
that implement the summary.
The base matching is by
name, you say type name full,
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
LLDB call this function
to summarize the object.
There's a bunch of other
rules and you can refer
to the LLDB website
for further details.
Whenever we need to display
a value of that type,
we call the function and we
pass to that function and object
that we call an SB Value.
SB Value is part of a
larger LLDB object model
that we're going to
cover in greater detail.
It is an object that
represents a variable,
think of it as a variable.
And that function can do
whatever processing it wants
because it's Python code
and that the end is going
to return a string and we're
going to show that string
on the screen as the
summary as the value.
So with that, it's an option
that represents a variable.
So it probably has
variable-like behaviors.
That's probably variable-like
questions that we can ask of it.
In fact, among the many
questions that you can ask
of an SB Value, you can
ask it, what's your name,
what's your data type,
what's your summary
string if you have any?
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
Do you have children?
How many do you have?
Can you tell me about
each one of those?
And each one of those
is an SB Value itself,
the model is total
recursive in this respect.
And if it's a scalar like a
number, integer, floating-point,
you can also ask
what's your value
and it will return
you the number.
So let's see our example,
we have our address class,
we see the number, we want
to see the name,
let's make it happen.
We start writing the prototype
or a function and here we see
that we're passing a value, and
that value is an SB Value one
of the objects we
just talked about.
We can't extract fields out of
that variable and here we get
into first and the last name
which are again SB Values.
That means I can iterate
the reasoning and ask five
of the questions
of these objects.
Since I know these
are NSStrings,
I know that LLDB is going
[inaudible] me a summary
out for those so I
ask for the summary
and now I have two
Python strings
that represent my
first and my last name.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
And since our Python strings,
I'm really free to the--
all the processing
I need in those.
And again, I'll just
return the string
and back to my variables view.
I still see the numbers because
I haven't told the LLDB how
to do the magic.
So let's apply the
secret sauce right now.
The type summary app command
named Python function is the
LLDB secret sauce and it tells
the debugger whenever you see an
option of this type, call this
function to provide a summary,
and from the moment on,
numbers are no more,
strings are on the string.
Thanks.
Expression, the expression
parser is a great tool
to run your code, it's a
great tool to check on state
of things, it can
also be a great tool
for looking at opaque data.
Sometimes you have some data
and you don't really know
its format 'cause they didn't
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
[inaudible] you how
to explore them.
But you can go on Google and
you can probably figure it out.
And now all the knowledge
about the internals
of this data stretcher are here,
but sometimes it's not enough,
we'd also like for those-- that
information to go from here
into the Xcode UI when
I'm debugging something.
An expression parser is a
great tool to make that happen,
let's see a quick example.
I've been banded this
API from a third party,
it's an opaque object and it
says create me, do something
with me and then release me.
I Googled it, I'm really
smart, I figured it out,
that's what the object
really is.
But the fact that I know it
doesn't translate into here.
In the user interface, it's
still just a set opaque object.
Let's shed some light here.
I can type expression
in the LLDB console
and I can define a
full data structure.
Again, this is the power
of having the compiler
the expression parser,
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
you can define a
full native structure
and that will be
accepted, that will work.
I can also define it
as a persistent object,
as Sean was saying, you
put a dollar sign there
and that's persistent.
That's really powerful
because now I can right-click
in my variables view, I
can say an expression,
and I can use an expression
that takes my opaque pointer
and converts it into a point
that was nonopaque structure.
So I define it in a
console and it stays alive
in the Xcode user interface.
And for the moment on,
it's not opaque anymore,
I can actually say the
data that I care about.
All right.
So we've talked about
interesting ways
that you can actually
look at your data.
Let's cover another interesting
topic where the full parallel
to be actually shines.
Let's talk about ways that
it can extend the debugger
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
and make the debugger
experience your very own.
And we're going to cover three
topics on how to extend LLDB.
We're going to talk about
cast on LLDB commands.
We're going to talk
about breakpoint actions
and we're going to cover
the LLDB init file.
[inaudible] Custom
LLDB commands.
I'm sure some of you have
used GDB quite a while
over the years.
And you have a library
of scripts that you wrote
and you used them
all or all the time
and they make you
extremely productive.
Now we're transitioning you
to LLDB and we're telling
that you can write
commands in Python.
What happens on your scripts?
Well, it's going to be
some work to convert them.
You're actually going
to have to seat there
and do the conversion, but the
reward that you're going to get
at the end of this process
is going to be huge.
You're going to get a
huge reward for making
that transition in
terms of how easy
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
to maintain your commands
can be and how powerful
that your commands can
be because they're going
to be full Pythons scripts.
For those of you that really
have not written your custom
library in GDB scripts, this
is also extremely important
because it allows you to do a
number of interesting things.
It allows you to create
a new debugger feature.
You have this great idea
of exactly the thing
that the debugger should
do for you and it doesn't.
You can make it happen.
The default behavior of
LLDB is just debug-perfect,
but if they could change
that one little thing for me,
that will be awesome while
you can change a little thing
yourself, you can implement
your favored behavior.
And let's say, you always doing
the same thing over and over
and over again, you
do the same thing all
over and over, over again.
Well, you can take that kind
of logic, you can make it
into its own building block.
And now every time
you call the command,
the command is a building block
like contains all the logic
and it just automatically
executes for you.
Let's make a quick example
of a great LLDB Command.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
Let's say that my
program is a recursion.
I'm recursing, calling foo,
calling foo, calling foo,
calling foo and I
am stopped somewhere
in the middle of that recursion.
I'd like to know how deep
does recursion has gone.
Is it really too deep
and I can see darn
to be a little coming
monkey 1, 2, 3, 4,
5 or I can actually
let [inaudible]
to become the frames for me.
LLDB is basically computer
programs so it seems
like counting should
be something
that it should be
easily able to do rather
than having to do with myself.
With an LLDB Command
you can do that
and the reason why the LLDB
Command is so powerful is
that they have access to
the LLDB Object Model.
We call it SB which stands
for Scripting Bridge.
It's a Python API, it's what
Xcode uses as the foundation
of the Debugger User Interface
and that means it's not
just a little toy API
that somehow somebody
brought one day
when it was brought
in the office.
It means it's the full power of
the debugger, the entire power
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
of the debugger and you that you
use in Xcode is available to you
when you want to write all
your LLDB Scripts right there.
We'd like to say
that it is a good way
to represent the debugger
session, let's look at it.
You will send this whether
you've got five Apps
under your belt or
you're just starting
to develop for platforms.
You've seen this.
This is the Xcode
User Interface.
Let's look at it with the
eye of a debugger engineer
for a second, will we?
Let's look at that, that
is the after debugging,
that is the thing in which
you put so much effort
and so much passion
and so much love.
That is the thing you want to
rock the stores while we called
that an SB target, it's the
target of your debugging,
it's the thing you're
aiming to make perfect.
And then you click the little
Run Button in the user interface
and this thing that you put all
that passion, all that coning,
all that wet and toiling too
suddenly becomes a live entity,
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
you can suddenly type and type
and click and type and type.
That's a process on the
underlying physical machine.
So we call it an SB process
and processes have
tried an execution
that are all striving
together right job done
and they're all doing
their own thing
and those are an SB thread.
Each one of those
is an SB thread.
And of course a thread is
going to call a function,
it's going to call a function,
it's going to call a
function again and each one
of those things is going to
be a frame on your stacks.
So it's going to be
surprisingly an SB frame.
Now that we're armed
with all these objects
that actually represent a state
of a program and we have access
to them, we see how
easy it should be
to actually get our task done.
So how does a Python
Command actually work?
It works by associating
a name that you type
at the command line
with a Python function
when LLDB is the command,
it calls the function.
That's the prototype
of Python commands.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
They get past the debugger
which an SB Debugger.
They get past the user
input which is a String.
You get the real Python
String that a user a types
so you're free to chop
it up however you like,
whatever library you
like to use, feel free
and then you get an SB
command return object which is
like of a talk-back object.
It's the command
talking to LLDB.
That object allows the command
to tell the debugger, "Hey,
I worked, everything
is fine" or "Love,
sorry I really couldn't
do this today
for you, try again tomorrow."
And could you please tell
the user, "Hello Wilt,"
yes the command return
object knows how to do that.
And that's how you add one
to the LLDB environment.
So, we have all these knowledge.
Now let's get back to
our task calculated
in the depth of a recursion.
What I need to do is I need
to loop over all the frames,
check if each frame is a
part of my recursion or not
and at the end I would not tell
the user I did the calculation
for you and it looks
like there's 10 frames
of your recursion.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
This is how you do
the first step.
It's one line of Python,
it's really powerful
because now you see that
you have this thread object
and you can tell the
thread what are all frames
and these frames object
binds you a Python iterator
so they can loop over each one.
But hold on, I know some
of you are looking at this
and they're perplexed
because they saw
that I was given an SB debugger.
I wasn't given an SB thread.
How do I get here?
Well, the LLDB object
model is extremely powerful
in this respect because
I can ask the debugger
that I could pass
as a Python command.
Tell me the thing
you're debugging now,
tell me your SB target, the
thing at the top of the UI.
And then I can tell that
target, "Give me your process,
give me your live-running
thing and process.
Can you please tell me what
thread I currently selected,
we're currently looking at."
And now I actually
have the thread
and you're not perplexed
anymore.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
So let's get going, I can ask
you to frame the question,
what's your function
and I can ask
that function a question,
what's your name?
If that name is the
name that I'm looking
at is my target name then I
know to update the calendar.
And at the end, I'll
say this is the result.
Now I can print to
that result object
as if it was a Python file
because we went so deeply
with this API Integration that
has become a return object.
Looks just like a file to Python
just praying to it at will.
This is the full code and you
can look at it from the slides,
I'm not going to go
all of these right now.
Let's just look at
the command in action.
We stop, we got a recursion.
I can count the frames,
I can barely see 1, 2,
3 or maybe that's not
good, OK let's not do this.
Let's just ask LLDB, I'll
call the [inaudible] command.
LLDB will think about it,
hopefully very briefly
and it will give us the
answer that's 20 frames.
Some of you probably
have counted the frames
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
and raise your hand
if they're not ready.
No one? OK then I guess
I believe the Debugger.
Let's move on, breakpoint
actions.
Sean has told us a lot of
great things about breakpoints.
He has shown us that
they are really powerful
and there's all these
amazing ways
that he can set breakpoints
in your code.
But by default, it's
at a breakpoint it
stops all the time.
That's why we have
conditional breakpoints, right?
So they don't stop all the time
but conditional breakpoints
unlike looking at your program
from within so they don't have
access to the LLDB object model,
they're like peers
to your program.
Breakpoint action
is written in Python
in a full program inspection
and by full program inspection,
I mean that they have access
to the data, they have access
to the code and they have also
access to the LLDB object model
because they're like running
from above, they're running
on peer with debugger and
looking at your program instead
of on peer with your programs.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
How do they work?
Pretty easy, you probably
hold and got this by now,
breakpoint actions
associated in breakpoint
with a Python function.
Whenever I hit the breakpoint,
the Python function is invoked.
That's one little bit of a
secret sauce here which is new
in Xcode 5 and it's a little
bit of a secret sauce is
that the Python function can
choose to return a value.
If that function chooses
to return the value false,
the logical value false,
that is the equivalent
of checking the automatically
continue
after evaluating check box
in the Xcode user interface.
What's so interesting
about this is
that these can actually employ
arbitrary amounts of logic
to decide whether that little
check box should be checked
or not in this particular
instance
of stopping at a breakpoint.
You read a function with
this kind of prototype
and gets Python as
reframed, and gets Python
as the breakpoint location
which is the location
on which the breakpoint was hit.
And that's how you bind
one breakpoint command at.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
Let's give an example,
let's go back
to our old idea of recursion.
I find it right recursion a lot.
My program is doing
some recursive thing
but I'm not great of recursion
so my program hangs
while doing it.
I don't really know
what's going on.
I get some reports and sometimes
I can actually make it happen
sometimes I cannot
actually make it happen.
It's really frustrating.
I don't know how to set a
breakpoint condition here.
Well here's the idea.
I can make a breakpoint action
that looks at the call stack
and I can tell LLDB you
really should always stop
if that recursion is getting
too deep out of control.
So that's what you get
for actually attending
the LLDB session.
You get these cool ideas
that you can go back
and implement in
your situations.
Let's make it happen, there's
two things that I need to do
to make this magic
happen, right?
I need to see how deep the
recursion is and I need to stop
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
if that's more deep than
I'm willing to accept.
Here's great news, there's
two things that we need to do
and we already did one.
That's the exact same
command that we did before
and since this is
a Python thing,
this is not some little
heart codie [phonetic]
command language.
It means that I can actually
take all these features
that I've read before
and I can reuse them
in these different scenarios.
I'll only need to do
one little thing here.
If I count the depth and I see
that the recursion depth is
smaller than the threshold
that I decided that is too
deep going out of control,
then my breakpoint
action returns false
and LLDB just continues.
It's for lines of code
right here that implement
that breakpoint action that
looks at all the frames,
calculates the depth and
decides if it should stop or not
at their breakpoint
for lines of code.
And here it is in action.
It's the same situation
as before we stopped
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
and there's 20 frames.
I guess we can-- we
have a confirmation
that it really was trying
the frames an example before.
Prototypes and customizations,
why do we need prototypes
and customization?
Well, I hope that by the time
WWDC is over and you're all back
to your offices, you're actually
going to take my word for it
and you're going to start
running your LLDB summaries
and your LLDB commands and then
you're going to click the LLDB
and you're going to type
them again the next time
and then you're going to
type them again the next time
and then you're going to
type them again the next time
until all you're doing is
actually typing this LLDB
customizations and you're
a little typing monkey
and you wish you never
really started doing this
in the first place, it's
horrible, stop this please.
Well, it doesn't
have to be like that.
We thought about the situation
and LLDB has a specific
configuration file
which very unsurprisingly
is called .lldbinit
and sits in your home folder.
That file is loaded
every time we start
up a debug session with LLDB.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
It's a great place to
treat debugger settings.
It's a great place
to load scripts
that you find yourself
using more and more
as you become proficient
with LLDB.
If anything is to be loaded
only when you're using LLDB
from within Xcode, the LLDB
init-Xcode is the place
to go to put those things.
So we covered quite
a great deal today.
We're almost at the end of
this brief journey together.
Well good things must
come to an end I guess
but let's make a recap the
most topics that we saw today.
LLDB is the debugger in Xcode 5.
It's more efficient than
ever before and it's packed
with great new features
for you to go out and use.
We actually covered some of
those great features right
in this room, right today.
Sean showed us great way to
be effective when debugging.
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
How I can use logging
and assertions
to debug even before
actually starting debugging
and how I can set the right
breakpoints to make sure
that I'm looking at just
the code I care about
and I don't waste my time
and I can be a productive
debugger engineer.
Well, then we talked about how
to exploit customizations
properly.
We showed ways that data
formatter has allowed us to be--
to view data in a much more
meaningful way than before.
And we saw that we can
automate repeated workflows
with custom commands and
with breakpoint actions,
has lots of great content.
For more information
about any of these things
and anything else to be really,
Dave DeLong is our
famous evangelist.
You can talk to him.
We have a lot of
documentation about LLDB though
that you can consult
before asking for help.
You can check the quick
start guide or you can log
in to LLDB website or
within LLDB itself,
you can get help about LLDB.
If you don't know exactly
what you're looking for,
X-TIMESTAMP-MAP=MPEGTS:181083,LOCAL:00:00:00.000
you can use the appropriate
po keyword for--
appropriate po command
followed by one or more keywords
and LLDB will look for
help on that thing.
And of course if
you have questions,
the Apple developer forums
are a great place to go.
There's been a couple of
related sessions over the week
that will mention LLDB
and debugging in general,
the new in Xcode 5 and the
session about debugging
with Xcode that Kate
mentioned before
and thank you for
joining us today.
[ Applause ]
Thank you.