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 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.
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 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, 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 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, 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 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.
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.
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, 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, 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.
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.
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.
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 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.
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 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, 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.
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 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.
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 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.
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.
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, 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.
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 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 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.
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 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 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 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 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.
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.
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.
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 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, 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 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 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.
And your NSString is going to tell you what its content is and your class instances will tell you what class they belong to.
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.
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.
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.
So let's see exactly what you can do, how you can plug in into the system.
There's two main types of formatters.
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, 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?
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.
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.
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 [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, 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.
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 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 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.
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 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, 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, 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.
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.
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.
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 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.
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.
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 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 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 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.
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.
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, 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 ]