Configure player

Close

WWDC Index does not host video files

If you have access to video files, you can configure a URL pattern to be used in a video player.

URL pattern

preview

Use any of these variables in your URL pattern, the pattern is stored in your browsers' local storage.

$id
ID of session: wwdc2004-315
$eventId
ID of event: wwdc2004
$eventContentId
ID of session without event part: 315
$eventShortId
Shortened ID of event: wwdc04
$year
Year of session: 2004
$extension
Extension of original filename: mov
$filenameAlmostEvery
Filename from "(Almost) Every..." gist: ...

WWDC04 • Session 315

Debugging in Xcode

Development • 1:13:54

In this session we examine the latest concepts, improvements, tips, and tricks for debugging in Xcode. Learn how to configure, run, and debug applications using source-level debugging within Xcode. Also learn more about Xcode's powerful "Fix and Continue" feature, which allows you to make changes to a running application, as well as how to use the debugger's formatter to make your debugging experience even more productive. This is an introductory to intermediate-level session.

Speakers: Chris Friesen, Jim Ingham, Jason Molenda

Unlisted on Apple Developer site

Transcript

This transcript was generated using Whisper, it has known transcription errors. We are working on an improved version.

Good morning and welcome to Debugging in Xcode. What we'll cover this morning, first we'll have a bit of a tour of debugging services in Xcode, and then we'll talk about how to use custom data formatters, a little bit of how you write the various formatters. Has anyone here actually customized any of the data formatters other than people that work at Apple? Well, hopefully we'll increase that number after today's talk. Then we're going to talk about guard malloc and how you use that with Xcode.

And then we'll cover "Fix and Continue" enhancements that are new in Xcode 1.5 and 2.0. In fact, everything we're going to talk about today is in Xcode 1.5 and 2.0. And then we're going to do a little remote debugging. We'll talk about the setup and show you what you can do with it. And of course, we have lots of demos for you. So getting started.

The debugging service is in Xcode. We have, of course, a graphical UI. That graphical UI is shared by the Java debugger and our C code debugger. That C-based code debugger is GDB. So when you're debugging your C code, it acts as a GUI interface to GDB. Of course it has Thread Picker. You can view your stack, variables, and also we have an expressions window.

You can also set and remove breakpoints right in your code, right in the gutter there. You can click on your breakpoint, it'll remove it. Set one if there isn't one there already. You can control-click and get a little menu item so you can disable it if you want.

And of course you can control your program execution. There are toolbar items for stepping, starting, restarting, and of course there are menu items which you can bind your own key shortcuts to. And of course it lets you access the cool features like "FiX and Continue" and remote debugging. Now, our support for non-C-based languages include AppleScript and Java, which are not the topic of this talk. So let's do a little tour now. Go to the demo machine, and we'll show you what we have.

First we'll open up Sketch. It's launching a little slowly because we're booted off of one of those tiny FireWire hard drives. So one of the first things you'll probably want to do is to edit your executable. In the executable inspector, you can change the arguments that you're going to be passing to your executable. So-- and also your environment variables. So you can create sets of these, and then toggle them on and off as you like.

However, if you get too many, it's a little difficult to manage large sets of them. So you might want to go ahead and create a new executable item in your project. And then you can name it appropriately, and then debug it that way. So let's start up the debugger here. We'll click the Debug button.

When we hit our first breakpoint, we'll disable that here in the breakspoint panel. and continue. So here's Sketch running. And we'll open up a document I made before. And go back, enable our breakpoint. And now when I interact with the program, we see that we hit the breakpoint in the debugger, and up here above the stack in the column header is a little pop-up, and it says "Thread 1." If there's more than one thread, then the pop-up will be active, and you can switch between the other threads. Then the stack will update, the variables will update, and your source will update to reflect that.

So you'll notice that some of these stack frames are grayed out and some are bold. If they're bold, that means we have symbols for them so that we can show you source lines and your variables that are in them. If they're grayed out, we don't have symbols, but we'll go ahead and show you the disassembly down where the source view is. So let's go back to the top of the stack.

And if you want to view the disassembly with your source, go up here to the Debug menu, and you can toggle the disassembly display. In the seed, you're going to need to click on the stack frame that you're looking at, and then it'll update the PC pointer over in the disassembly view.

But here we have your source code and your disassembly in the same view. And if we go up to the toolbar and we do-- Step over instruction, you'll see that the PC and the disassembly is changing as we go through the code, but those lines that we're stepping through are all on the same line of source.

If you do a step over, you'll see that we've stepped over in the source view, and then the PC and the disk assembly is also updated. Now, if you'll notice in the variable view, We have variable graphics here. It's an NSArray, and it's just been set, as you can see from the source code where our breakpoint is. Whenever value changes between stepping, we'll highlight it in red for you so it's easier to see.

If we step again, you'll see that "i" has changed and highlighted in red. So now we can actually go and edit the value of "i" and we can set it to 4. And just to prove to you that it's set to 4, for those of you that don't like the GDB console, you can avert your eyes now. We can open the console, print "i," and sure enough, it's been set to 4, as you would expect.

As you can see, that's not going to be a good idea because we're going to iterate through our for loop there, and we'd probably cause an exception as we access the array. So we can drag the PC back and then execute that line of code again. Just another way, we could have gone and edited that value and set it to 3 again.

But it's a useful technique to be able to move the PC if you've accidentally gone past a line of code that you want to step into. Say there's a function you wanted to step into and you've gone past it. You can simply drag the PC back and then click "Step Into." So with graphics, we see that it's in NSArray, and it's telling us that there are three objects, but there isn't much more information there. So what we can do is, using contextual menu, we can print the description to the console. The console automatically comes up for us.

And if we scroll up to the top, where it displays the variable, we see that NSArrays have a description where they'll give us the count and then tell us what the values are. And then it'll go through each element of the array and do a description on those. And we see that the elements inside the array each have a very verbose description, giving us the bounds, the class-- in this case, it's a circle-- and some other attributes. Now, I like my GDB prompt to be a little bold, so we can go to the debugger preferences.

And we can set the font size. And we can change it to bold. Then click "Apply." So you can go through and you can customize your standard in, standard out. You can have different fonts if you want, different colors even. And as you can see over here in the source code view, I've actually changed the instruction pointer highlighting to a light green. You may have been seeing red in all the other demos.

One other important item to keep in mind is that we have key bindings. So if you don't like the default key bindings for the various debugger functions, the stepping, that sort of thing, you can define your own. Now let's go back to slides. As I click-- one more. And you also see that when we're running the debugger, and if you were to quit Xcode, we say, oh, we're running. This also works for the run panel. It's been much requested, and that's fixed in Xcode 1.5 and 2.0. So let's go back to slides.

Custom data formatters. We introduced them a year ago. And how many of you know when you're looking at a custom data formatter in the variable view? Of course, the Apple guys. So basically they'll let you summarize the information so you don't have to turn down the variable. For instance, structures can get quite long. You can summarize exactly what you want to see. It saves vertical space, which is very precious on a lot of screens. And you can add your own custom text to the data values.

And you can also evaluate expressions. You can make calls to functions as part of your simple expression data formatters, and you can also create custom plugins, which can be more complex. Now, custom data formatters, they're bound to a type. So if you change the variable formatter for one-- change the formatter for one variable, it's going to change the formatter for all variables of that type.

Just something to keep in mind. We have about 35 Carbon formatters. For instance, OS error, FSREF, and some structures. And we have about 35 foundation formatters as well. For instance, you saw NSArray. We tell you the count of objects. In this dictionary, we tell you the number of keys. We have formatters for NSPoint, NSRec, some of the AppKit structures.

Now your user customizations are all stored in your home directory: ~library, application support, Apple, developer tools, custom data views, customdataviews.plist. So if you have a great set that you want to share with other people, you can give it to them, they can then insert it in the same place in their home directory.

And then they'll have the same data formatters that you have. And for plugin support, you should look at the dataformatterplugin.h file, which is actually inside the Xcode.app app wrapper. So you have to search down inside that, probably with terminal, or you can use open package contents in Finder.

Now, summary formatters, they're lower overhead than the other formatters. They're basically percolating values that we've already fetched, or are easy to fetch, into the summary. The recursive. So if you have one formatter for one structure that has another structure that also has a formatter, then that formatter can be used as well, and you don't have to drill all the way down into those children.

The basic format of a summary formatter is a child path surrounded in percent signs, colon, and then a referenced column. Now the child path is a dot-delimited path to the child data value, a lot like you would reference a structure in C. In C++, child paths can leave out private, protected, and public. You don't have to reference those. We'll skip those automatically for you. Now the reference columns all refer to the columns in the variable view. For instance, there's the name variable column.

There's the value column, the type, and the summary column. So this is going to reference which of those columns of the variable you want to display in your summary. We'll cover that in a little more detail. So here's an example where we have an NSPoint, has two elements, an X and a Y.

And you might write a formatter that looks a little bit like this. So you might have X equals percent X percent and Y equals, which is some custom text. You could put anything there. And then percent Y percent. And it might look something like that in the variable display. I have a similar thing for an NS size, where you reference the width and the height, surrounded by percent signs, and some custom text before or after it. And that would display something like this.

As we talked about before, they're recursive. So if you have an NSRect, which has an origin, which has an NSPoint, and an NSSize as two elements of that structure, you can simply reference those elements and their data formatters will be used. So you might have custom text, parentheses surrounding, a reference to the origin, as well as the size. And then it would look something like this in the variable display.

Now, expression formatters are a bit more complex. They're higher overhead, because you're actually asking GDB to go execute some code or do some logic for you. Usually you're executing a function and that can have side effects, since you're actually evaluating something in GDB. So if your variable formatter has something like I++ in it, then I will increment. And if I is a variable in the stack, it'll have changed. So be careful what you do. You might also be able to do something interesting with that.

And you should always cast your expression formatter to the correct type. GDB can be a little unhappy if it doesn't know the type for the return value of the expression you're calling. So it's always safest to cast the proper type. If you don't enter the type and the formatter doesn't work, cast the proper type and try again.

and avoid taking locks. Avoid anything that will take a lock, avoid anything that might need a lock. It's just not a good idea to do that in your expressions. and avoid taking locks. Avoid anything that will take a lock, avoid anything that might need a lock. It's just not a good idea to do that in your expressions. The dollar sign "var" is used to reference your variable in the expression that you write.

Now you want to think--you can think of your expression formatter as though it were a variable of the type that you've cast it to in the variable display. So if it's a char star, char stars happen to show up always in the summary column. So we'll get to an example of that in a minute.

For an NSArray, if you've ever gone and double-clicked on the summary column of an NSArray, you might have seen the formatter looks sort of like this. So we have some custom text. We have curly braces surrounding our expression. Dollar sign bars replaced by the actual variable when it's passed to GDB for evaluation. So we get back an integer, which we're casting to be safe. And we're casting-- we're We're including ":v" at the end, just to be pedantic. It's the default. If you don't include any reference column, then that's the default. So, just for correctness.

Now you could do this type of formatter for a bool if you were tired of seeing ones and zeros for all your bools. You wanted to see true and false, because that's what you're used to programming it as. Or you might want to see it as yes and no if you're into Cocoa. So here again we have our custom expression, and we're casting it to a char star. And because we're casting it to a char star, we need to reference the summary column.

So for an STL string, for a standard template library string, If you have a simple null-terminated string, you could use a formatter like this to be able to view that string in the summary column. So here we're simply calling--have some custom text, C string equals curly brace, casting our expression to a char star, $var.C_STR function call. Close it up and end it with colon S. Now for custom data formatter plugins, you can do more complex things.

Basically allows you to do a custom print for a debugger on types that you may not have access to, or somebody's given you a framework and they don't have custom debugger printing. It's automatically used. So once you create one of these bundles, in it is a plist that specifies which type it's for, and Xcode will automatically use that data formatter for that type.

And this code runs in your program. So you want to be careful what you're doing. If you're not comfortable with allocating memory or being careful that you're not overrunning the buffers that you're creating, then you might want to be careful with these. Be sure to handle invalid input. Oftentimes these variable formatters will be called before your variables have been initialized, so you want to be safe with what you're doing.

Now in order to create a custom data formatter plugin, you need to start with a new project. We'll have a demo of this, so you don't need to write it all down. Then you need to add a bundle target to it. For instance, a Cocoa bundle. And then you'll need to add a header search path.

In this case, you can see that it crawls down into the Xcode application app bundle itself. That's where the dataformatterplugin.h lives. This way we can simply reference #include dataformatterplugin.h in our code. And then you also need to add a custom data formatter views.plist. This is the plist I was talking about that specifies which type this custom data formatter is for, and also what summary string to use.

So here we see dictionary with a key, which is bool, and that's the type that this formatter will be used for. And then summary string is the next key, and that's the summary string that will be used in the summary column. So in this case we're calling myBulletDescription. $var is going to be replaced with the actual variable. $id is used by Xcode to

[Transcript missing]

Up top we see that we have a pointer to our PBX GDB plugin functions. Those are the plugin functions that we support for you.

And we declare our function, which is myBullDescriptor. And we have our type, which is bool and int for the identifier for that memory call. And if you look at the code, we see that if a bool is yes, then we're going to construct this print function. which is going to concept the message for us, allocate some memory, and take care of managing that for us so we can return any string we want. Now we have Jim Ingham on to give us a demo of custom data formatters. Can we have this one? Okay. So, we're going to go over these kind of in order of dangerousness from not very dangerous to very dangerous. Let me open these.

So the ones that are the percent ones, that's really doing nothing. That's just taking information that's already fetched on your behalf and using it. So I'll show you those. Those, you know, you can play around with those for free. They're really, it's really nice. You can go in and, you know, as you're looking at something, you know, change it for a little while, change it back.

They're really easy once you get, the syntax is straightforward, just like your C syntax. And kind of once you get into the habit of just, "Oh, I want to see these two fields now. Oh, I want to see these two fields now." It really becomes an interactive thing that you can go and do as you're going along. It's really a nice workflow, I think. Okay, so let me find somewhere interesting that I want to be.

So we got Sketch again. That's what we're using as our example all the time this year. So I'm here somewhere. So I have this bounds, which has got custom data formatters already, you can see. If you want to see what the custom data formatter is for anything, remember, you just double-click on it and it'll show you what the current data formatter is.

But maybe my--what I like is to keep my value column fairly small because I have, you know, a lot of strings or something like that in the summary field. I want to make that big. So we chose to put this particular set of custom data formatters in the value column, and that's annoying to me. I don't want to do that. So I want to move it over to the summary column. So that's--that's what I'll show you how to do first.

So that's pretty straightforward. Let me actually do it for the constituent elements first. So a bounds has, you know, a point and a--and a size. So let's take this one, and you can just copy it from here and double-click and put it over there. So now it's going to show up over there. So that's all you have to do.

And, you know, it's a little bit of a challenge, but once you get used to it, this is something that's mine, right? You can really change in a nice way all the stuff that you view. So I put this one over here, right? Then now I've got redundant information, so maybe there's something else I'm interested in here.

Like, since it's a structure, maybe I want to see what the address of the structure is. So that one would be pretty straightforward to do, too. That's going to be an expression because we didn't fetch the address of the structure in a way that you can get at it.

So--but you just write an ordinary C expression surrounded by the curly brackets. That's our little syntax which says this is an expression I'm going to send to GDB, and I'm just getting, you know, the address of that array. For some reason, it's not updating right away, but it'll update in a second. Don't worry. And then maybe I'll do the same thing here because--well, I don't know, but-- because I said so in the demo script.

Okay, so I've got that. But then notice over here, so this is the deal with the columns that's a little bit confusing at first but it's actually pretty straight forward. You know, I changed the value contents of the origin structure that was contained within this bound structure. So then all of a sudden, what started showing up as the summary for origin in the bounds structure that contained origin is that address that I wrote in.

And the reason for that is because the summary here that I'm getting is coming from the value column by default because I haven't put a colon, which column am I referencing in the origin, right, which is this one, that I'm pulling the formatter out from. So if I want this to come now from the summary column, because again, I've moved the summary column to the value column, and I've moved the information I'm interested in from the value column to the origin column, then I have to say that's from the summary column.

And the same thing here. I have to say that's from the summary column. So now that shows the contents from the summary column, which is the one I want for the outer summary. So again, I can move this over here. And I don't know, you know, I could take this one and put it over here just to make everything look pretty. So, okay, so that's the two things. One, you know, double-click to find them. That's how you discover them.

The notion of, you know, when you have a substructure like this origin substructure, you can use it in the parent just by referring to it. And again, the column says in the substructure that I'm pulling values out from, which column am I referencing? Like, am I referencing the stuff that's here, or am I referencing the stuff that's here in the formatter up here? Okay. So that's pretty straightforward. Uh... okay, cool. So now, I don't want to stop here anymore.

Uh... okay, cool. So now, I don't want to stop here anymore. Now I have source. Yay! Okay. So the next thing I want to stop at is... I think I want

[Transcript missing]

Here's another place, like, my document is a type that's mine, and, you know, it's the one in Sketch that contains the circles and squares and so on and so forth.

So, I actually might want to see some useful pieces of information about it, like, in this case, maybe what I want to see is, how many circles do I have and how many squares do I have? That might actually be a useful piece of information. So, it turns out that what the document contains is actually NSArrays, and it contains an NSArray of circles and it contains an NSArray of squares. And then it has an accessor method called "rectangles" to get the NSArray.

So, there's no way that I'm going to find out those numbers by, you know, grubbing around in structures, because NSArrays hide from me where the number of elements is. And my little accessors are such that, you know, I'm hidden where the NSArray for rectangles is. So, I'm going to have to call some code to do that.

But it's pretty straightforward accessor code, so it's really not too much worry. It's unlikely that I'm going to crash my program, you know, calling for circles or squares, or change its state by getting the number or something like that. So, that's the kind of function call that you can call into the inferior that's actually pretty safe.

It's not going to do any harm. On the other hand, me trying to type while you're watching me would do infinite harm, so I'm not going to do that. I'm just going to -- oh, is it you, bastard? This is not going to let me copy. Oh, you're going to watch me type. Okay, that's going to be fun.

So, for instance, maybe I just want the number of circles here, just to limit your fun. So, you know, I have to call to get the number of, get the array and then get the number of elements in the array. So the number of elements in the array is going to be an int, Variable, so the dollar var, that's the thing that I'm referencing in the document, and I'm going to have to get the circles out of that. I have to get a curly brace on the outside. Yep. So you really don't want me to type here. And then now I've got the circle, so that's great. Note I cast the outermost thing. This one is going to come back as an in.

That's fine. And then... So that's the circles. That's an NSArray, really, but it's fine to call it an id. And I'm going to count on that. You've got an extra square bracket. Yeah, I probably do. This is one of those, you just keep typing until it works. Okay. So, yay! That shows me circles, and if you wanted to watch me type in that horribleness, then I'd do the other one, but I'm not going to. Um, I don't amuse myself that much.

So, um, then the other example that, uh, oh, uh, Yeah, that's OK. One other thing to notice, by the way-- so here, in graphics, what we have is kind of this little grayed out version of the variable formatter, but we don't have anything. And the point for that is what Chris said, namely that graphics is actually not initialized yet. Graphics gets initialized in the next line of code that we're going to execute.

But this is actually calling, again, a function. It's calling count and something like that. So in most cases, GDB is actually-- probably what happened was that Xcode went and asked GDB to call this function. And var contained some junk, whatever was on the stack at that point. And that probably crashed, because calling selector on some junk generally crashes.

But GDB is pretty good at cleaning up that sort of crash, so as long as what goes on in the functions you call in the formatters don't change state, it doesn't really matter too much if they actually don't go terribly well when you call them sometimes. Because GDB just wipes up the stack and goes, I didn't see that, and everything's fine. So you don't have to worry too much. What you have to worry about is stuff that might change state or stuff that might acquire resources. Because if you have a multi-threaded program, these are going to be running. Another thread might have the resource.

And that's the sort of thing that'll go badly. But just a little minor crash, that really won't affect too much. So OK. We want to stop somewhere else. I'll show you the bool example that we showed before, just so that you can see that it actually does work, and that you're really calling, you know, any expression that's valid in your current language is what you're calling.

Okay, so here we're somewhere that has a bool, and that looks really, really ugly, so let's make that look a little nicer. So again, we're going to write an expression. It's coming back as a char star. And what we want is, you know, if the variable is 1, we're going to return yes. Yeah, if it's positive, we're going to return yes, and otherwise we're going to return no.

The only funky thing about this is that we had to put backslashes before the quotes. And the reason for that is that this has to be passed down to GDB, and GDB has a command line which has certain syntax. And one of the things is the quotes delimit arguments. So if we passed unprotected quotes, then when they got down to GDB, GDB would think that those were argument delimiters, and the line wouldn't parse and it'd get all ticked off. So any time that you're passing a quote down, just backslash it.

That's the only one that you have to worry about. And again, it's one of those, you know, you just keep typing it until it works kind of things. Chris, why aren't you working? Hello? Oh, all my typing just went away. What did that happen, Chris? So $var. Maybe? No, it's running. Question mark.

I'll get it. Yeah, yeah, yeah. Got that one. Isn't typing on stage fun? Oh, I typed something wrong. I'm not going to try to type it right on stage because I can't type. But anyway, that would show up. The other one I wanted to show you, just to make the point, and this one I can type because it's pretty straightforward, just to make the point that you really are playing with power tools here, is that you could do something like this. Okay, that's a nice little expression. And then, you know, three, four, five. Okay. So, you really are changing the state of your program, so you want to be careful about that.

Okay, so then the last thing that we want to do is show you how to do the plug-ins where you build your own custom plug-in. And so as I say, you know, from the percent ones, which are just information we've already fetched, so there's no way you can screw it up, to the curly bracket ones, which you're calling functions and it's getting a little more dangerous, to the ones where you're actually injecting your own code into whatever program that you happen to run under the debugger where, you know, you're getting really dangerous.

But on the other hand, if there's stuff that you can't get from the external level calling functions or something like that, or if there's kind of a formatting that you need to do which is time-consuming or, you know, just grubbing around in some more stuff than you want to write here, I mean, these can be valuable.

For instance, the Carbon stuff was done that way because, you know, you want to like go and look through a window and pick out the 10 things in the window. So you can actually write in the window list that are really interesting to you and format them up in some nice way.

I mean, that's actually--would be tedious to write in as an expression. The summary view, you probably could write some really long thing that did it, but you'd surely get it wrong. Writing it as the plug-in is easier. So for that, we have to go and make a new project. So it's easiest just to make an empty one. And I don't know, we'll call it empty.

it on the desktop so I can find it. So what I want to make the--depending on--you want to make a bundle because it's something that's going to be loadable into your program. But if, for instance, you're going to be doing another Carbon data formatter, you want to make a Carbon bundle because that'll set it up so it'll link to Carbon correctly and have all the stuff you need. If you want to view some, you know, app kit types then you want to make a Cocoa bundle, whatever you--whatever the point of the formatter is.

So we're just going to make a Cocoa one, a Cocoa loadable bundle, and we'll call it-- So one of the things that we have to do, as Chris said, is we have to go and set the header search path to point into this horrible location, which I nicely put on this thing, but I can't get it! Oh, okay. Anyway. So you get to watch me type again.

That's roughly right. We'll just find it out when it doesn't compile. So you have to add that search path, because that's where we store this, the, the, the, The data plugin .h file. And then what you need is the plist file and you need the C file that actually implements your code. So, because I couldn't possibly type those here, so I have them already made.

Wake up, little Firewire drive. Okay, so here's the P list. No, that's this one here. Same thing that Chris showed. We could actually, within a given plug-in, define formatters for a whole bunch of different types. In this case, we're only defining one for one type. And then here's the name of the function that we're defining, so we're just, in the same way you would do any variable formatter, what's happening is that this code gets inserted into the target program, it provides a bunch of functions, and then you use the normal variable syntax to call out those functions.

The one thing to be careful about, of course, is remember that you're going to be inserting this into whatever code you happen to run in the debugger, so you probably want to be a little careful about choosing some gnarly name, like my bool description's probably not a good choice. XXXX underscore some numbers and what, I don't know.

But anyway, choose something that you're not going to collide with other symbols. And then the little ID token, which is how we manage memory and resources for each instance of the running data formatter.

[Transcript missing]

Yeah, we're AppKit. Okay, wonderful. Okay, so then you have to find your build products, which in our case are here.

And move this into the proper place for where plugins go. Where that is, is in your home directory, library, application support, Apple, developer tools, custom data views. So that's where the things should go. This is, by the way, where also the custom data plist that stores the ones that you've typed in, like the percent ones and the var ones. They're all actually stored in here. So if you want to see what you've got, or if you want to get rid of them all at once for some reason, go into the same location. Just delete that file.

Was that there? Okay, well, anyway, that was the finder. I think you have to quit Xcode to get it to reread these. It looked like you didn't one time, but it's a demo, so I'm not going to try that. So let me open the two ones I had here.

[Transcript missing]

So what's going on here is just the breakpoint that I wanted to stop at was set in a framework, not in the main app, so... You have to actually have the framework open for it to know that they're there. Let's see. I put something there. So it was overriding the default one. Again, anything you type in at the console is going to override any built-in ones. But then when I deleted it, it switched back to the default one, which was calling my function, and that printed false. So pretty easy to do.

Let's go back to slides. We'll go back to slides now. So, thank you, Jim. Now, we have some new ways to display data in Xcode 1.5 and 2.0. We now display file statics right in the variable display. So if there are any file statics-- thank you-- if there are any file statics, we'll display the file statics turndown. If there are no file statics, then it won't be there, or if we can't detect any in the symbols. So it's just like the arguments and the locals. If there are no arguments or locals, then those turndowns don't show up in the variable display.

So we also have the Global Variables Browser, which was shown on Monday. Once you browse global variables by library, you simply go into the debug menu to Tools and bring up the Global Variables Browser. Inside that browser, you can then search and filter on the various fields. Multiple selection doesn't work yet. We're working on that.

And then you can click in the View column for the items they actually want to view in the variable display. So it's a good way of filtering down from possibly hundreds or thousands of global variables that could be in your program's space, down to just the ones you're interested in.

We also have the simple memory browser. And you can either type in addresses, you can type in variables, you can also type in some expressions, which Jim will probably show us. So let's get Jim back up here for file statics and global memory. Let's have this one again.

Okay, so in this case, you know, of course, we're a nice object-oriented application, so of course we have no globals and almost no statics. So actually constructing the demo is a little bit hard because there really wasn't much interesting, but in any case, I can find someplace. So let's see.

[Transcript missing]

No, well, we stopped there instead. That's okay. So if you want to see, well, this one doesn't have any statics, but if you want to see globals, again, there's nothing here right now, but...

[Transcript missing]

So that's that. Yeah, and then statics just show up under statics. I can hit the other breakpoint, and then I can find statics for you.

So this one actually has some statics. They're just listed under the file statics. So these are the ones that are defined statics to the file, and they'll just show up all automatically. You don't need to pick them or anything like that. So that's that. And then the third new thing that I was going to show was that we now have a little memory browser.

So, the memory browser, it'll view memory at whatever address. So for instance, like $R3 here, you can type in addresses, you can type in, you know, any expression, $R3 normally stores the object, but, yeah, I don't know, probably an object, I can't really tell. The other thing you can do is, you know, if you have accessors which are pulling out stuff and you want to see the stuff at the accessor, like for instance, you know, we pull out the document here.

"So, we could just say self... Draw a document, and it's going to resolve it to whatever the address is, and then print it. It doesn't stay live. It resolves it to the address, and then it prints the address. So if you wanted, you know, to track a location as it changed, you'd need to reenter the expression every time.

The other thing is, you know, you can change how much you want to display, you know, bigger or smaller. This is a little stepper, so you can step through pages of memory based on the size that you have. That's pretty much that. Okay? OK? All right. Let's go back to slides, please.

So, new in the debug menu, we've had to reorganize it a little bit. We have some more menu items for you, and we want it to still be able to fit on a 10x7 screen. As we had before, we still have Stop on C++, Catch and Throw. You can control the disassembly display. There are actually three modes there. Whenever in the default mode, if you click on a stack frame with source, it will just show the source.

And then you can do the mixed view as we showed you earlier. The third mode is that will show you only the disassembly whenever you are clicked on a frame that has symbols. So if you want to stay in disassembly mode, or you don't want to split your screen, then you can choose that mode.

And then you choose the mode a fourth time. You choose that menu item a fourth time, and then that would get you back to the original mode. And that's specified by a check mark and then a dash next to the menu item to show you what state you're in.

Now you can enable and disable the data formatters either using the contextual menu in the variable view or in the debug menu. Under, we have the same contextual menu that shows up in the variable view in the debug menu, and you can select it there. Now if you're in the middle of debugging your program and you disable the data formatters, you can re-enable them later. If they're disabled when your program starts, then we won't have loaded our introspection library, and you'll only get the summary formatters whenever you enable the data formatters again. Just something to keep in mind.

We also have stop on debug string call and debugger call right in the debug menu, so you don't have to go to the executable inspector and switch it on there. It is still available there, and we track the two and keep them in sync. And now you can enable guard malloc right in the debug menu.

All of these settings are now stored per executable. Some of those settings used to be stored per session of Xcode. So if you had two projects open and you enabled "Stop on C++, Throw," then it would be enabled for all of your programs. So let's talk about guard malloc a little bit. What is it? Basically, it causes your program to crash. And that's a feature.

What it's detecting is it's detecting memory access exceptions beyond your allocated buffers. It can also detect access of freed buffers. What it's detecting is it's detecting memory access exceptions beyond your allocated buffers. It can also detect access of freed buffers. and then uses the VM system to add guard pages around your memory allocations.

Now it also overwrites freed memory with bit patterns so you can detect when you've read that memory in. A little bit of an assistant there. However, your code's going to run a little bit slower because it's doing extra memory allocations in order to put guard pages around the allocations you've done. In fact, it pushes your allocations so that they end right at the end of a page. So there could be potentially more memory being allocated than what you've asked for.

However, it's still thread-safe, which is good because a lot of applications you're writing today have other threads getting launched for them, either via AppKit or Carbon. So how do you use guardMalloc? Well, it's best to use it with the debugger, because it's going to cause your program to crash on these memory access exceptions.

So then that'll give you the backtrace that you can then go use to find out what the problem is. As we said earlier, you enable it in the debug menu. And this is essentially causing us to set two environment variables. The first is dyld_insert_libraries. And then we specify the libd_malloc library. And that will cause libd_malloc library to be inserted at runtime.

The second is force-flat namespaces. If your program will not run with flat namespaces, then you won't be able to use guard-malloc. Again, you debug as normal, exercise your program, and then we'll bus error, throw up an exception, we'll catch it on your bad memory accesses, and then you can just follow the stack right to the problem.

So GuardMalloc has a lot more options. You can put guards against buffer underruns. You can allow allocations over 100 megabytes. And you can do extra checking before free and realloc calls. You can also fill allocations with bit patterns. So you can tell which memory you've filled up, you've allocated, and then you can detect if you've read it by accident.

And there are more options in the libgmalic man page. These options are all environment variables, which you can then go set using the executable inspector and set the environment variables like I showed you in the first demo. And now let's get Jim back up here real quick for a guard malloc demo.

So again, this one. So I'm not going to show you anything particularly interesting, just to show you that it works and how you turn it on and stuff. You know, this is the classic mistake. I made a buffer to hold a string, but I forgot to allocate the space for the null, right? And then I wrote some stuff into it and overwrote it.

So if you do this and you just run it, then, I mean, it just runs fine. Nothing happened, right? There was no mistake. But there actually was a mistake, which as your program got more and more complicated, you would eventually come across. So what's better is to run under GuardMalloc when you're worried about, I have some weird behavior, or maybe it happened upstream, I don't know where, but I can catch it.

And again, that's easy to do. That's just a menu pick, enable GuardMalloc. If you want some of the fancy options, you need to go into the executables tab and set environment variables, as Chris said, but we're not going to need to do that here. All we need to do is just debug it.

So we get a bad access right when we did the strcpy, which is what you expect because we went one character past the end of the buffer we allocated to write the null, which we hadn't allocated, and it just gets us right away. So that weird zero, which ended up showing up in some other data structure somewhere, you can't figure out why. You figure out why immediately. So that's what guard malloc is for. Let's go back to slides.

Go back there. MIKE MCCURRY: Thanks, Jim. So with fix and continue, which we introduced a year ago, it allows you to change your code while you're debugging your application. You can make the changes while you're running the application, and you can continue your debug session without having to do a recompile and relink. So it allows for more of a prototype style development. It's extremely useful for those long debugging sessions whenever you have a bunch of program states set up and you want to do some simple changes to try and fix your program.

However, it requires that you use native targets, which is the default for most new targets that you create in Xcode. And of course, it requires GCC 3.3. Now new in Xcode 1.5 and 2.0, we have support for fixing and supporting projects. So if your application is in one project, and you have supporting frameworks in other projects, you can now fix the code in those frameworks while you're debugging your application.

This requires that all of your projects need to be built with debugging symbols enabled, so probably just the development build style. "FiX and Continue" needs to be enabled, and if you're using C++, you need to enable ZeroLink as well. Now, all these projects need to be open in Xcode at the same time, so we can go find which target has the file that you're trying to fix.

So what can you fix? You can change logic, you can add new calls, you can delete code, you can change constants, and some other common operations. Things that won't work. You can't change the size of structures, or class layouts, or function signatures. You can't add global and static data.

And if you happen to be trying to fix the frame that's at the top of the stack, you can't add local data. And if you do make changes that require initialization, then you need to be-- after you do the fix, you need to make sure to move the PC back to execute the line of code to initialize your data.

Let's get Jason up here for our "Fix and Continue." Thanks, Christopher. So, can we get the demo machine up, please? Thank you. We're going to be looking at the Sketch project again, because it's our favorite project of all. Christopher has split it into two parts, a framework and an application, so that we can show the support for the supporting projects in "Fix and Continue" that's new in this release.

Unfortunately, it's not actually working in the Tiger seed, but we're going to have it fixed by the end. So just bear with us for now, but it's going to be in the final Tiger. So here, you see on the screen, we have the framework project, right here, and we have the application project. Both of them have been built already. So we're going to launch them in the debugger.

in the little hard drive spins. Here we go. So the basic thing, we get a circle, it's filled with blue, probably not what we actually intended, so this is a great chance to use fix and continue to change the behavior of the program without having to restart it and relink it and recompile and all that other stuff that you have to do normally.

So the thing that we're going to fix is over in the framework, so over here we're looking for SKT rectangle, which has the rectangle class. Here it is, and we have the setup function right here. So let's set a breakpoint there. And let's draw another circle, square, rectangle.

Here we have a chance to change the color that it's using for the fill. Right now it's setting blue. Let's change that to red. Because maybe that's what we actually intended, because red rectangles are what everybody needs more of. Now we're going to say "Save it" and "Fix." "Piles the file, links succeed, and fixed." Now, if I continued at this point, as you can see, the PC is already past the point where it sets the color. So even though we fixed it, the color's already been set. We need to move the PC back a couple of lines so it's going to set it to the new color.

If we drew another rectangle after this, it would get the new color, but we want it on this rectangle. So let's drag the PC back. Up towards setting red color, and then continue from there. Unfortunately, I drew a really small rectangle. Let's just disable that breakpoint for a second.

There would be a redirect if it worked. Now we have read. It's "Fix and Continue" just like you've always seen it. But you'll notice that the application, which we're debugging, is in a separate project from the framework where we're "Fix and Continuing." So the supporting project is the really exciting new thing here. One caveat that's important to understand is that a file can belong to multiple targets.

So what you have to do if you're "Fix and Continue" a file that's in multiple targets in a supporting project, you're going to have to give Xcode a little hint as to which target it is you're fixing. So for instance, let's do this again. Over in the framework, let's duplicate the target so we have two targets with all the same files in them. Duplicate it, and we'll just call it a separate name so that it's clear.

Now we have two frameworks with the same file in it. Again, we're going to--well, we won't stop at the breakpoint. We can fix and continue without getting to the breakpoint. In fact, it has fewer limitations. Fix and continue when you stopped in the middle of a function has a number of limitations on changing that particular function. So instead let's just run in the main event loop and do the fix from there. So instead of red color, I think green color would be a much better color. Save it. Now when we try to fix it, which we'll do from the debugger, Thank you.

There, OK. Fix? Now we get this pop-up. And this pop-up is asking us which target it is we're trying to fix so that it knows how to process it and get it back into the executable. So we tell it that it's Sketch Framework. "Build succeeded. It's fixed. Now we get the green one." One really nice feature is that once you've told it which target it is, it's going to cache that and remember it in the project.

So now if you do a different color, we fix it again, it remembered that we're working with Sketch Framework. So you only have to actually do the selection once, and from then on, it's just the default. and we get a brown one. So that's the new "Fix and Continue" supporting projects. Thank you, Christopher. CHRIS FRESEN: Thanks, Jason. We can go back to slides.

So now, whether it be across your cubicle or maybe just down the hall, we bring you remote debugging. This is great for debugging those full-screen applications, games, screen savers. In fact, some games we know have had bugs in full-screen mode only, and so the only way they've been able to debug these is to go to the terminal on another machine, SSHN, and fire up GDB. So they don't have the advantage of the graphical debugger.

It's also great for debugging event handling. So you're trying to drag the mouse, and you want to debug at the same time. Now what happens normally is, Xcode's going to have to come up if you've hit a breakpoint. And now you aren't going to be able to move the mouse anymore in your program. So, with remote debugging, you can now continue to use the mouse as you debug your application.

And it supports nearly all of Xcode's features. In your seed, it doesn't support "Fix and Continue." should be pretty easy to fix. For now, one thing you won't be able to do is you won't be able to send standard in to your remote process. So you won't be using this to debug your command line applications remotely on another machine.

There's a little bit of setup for remote debugging. You need two machines, of course. And remote login, SSH login, needs to be enabled on the remote machine. Now you need to share the build products, especially if you built with ZeroLink. That's because ZeroLink's looking for the other .Os that it's created A specific path.

So if you're using a network home directory, that's quite easy. Both machines will have access to the build products with the same path. If you're using AFP to share from one machine to the other, then you might have to use symbolic links in order to fix up the path so that it's the same access on both machines. Note that finder aliases won't work currently, so you'll need to use symbolic links.

To enable remote debugging, you bring up the executable inspector, you check the debug executable remotely with SSH, and then you fill in the host text field with the user name on the remote machine that you're going to log in as, and either an IP address or a host name. Now you need to make sure that the user that you're logged in as is the same user that's logged in at that machine. Otherwise you won't have permission to write to the Windows server, and your graphical application will not launch.

So we're using SSH public key authentication. You need to set up your public and private keys on the remote machine. Xcode is SSH-agent aware, so you can encrypt your private key, and it's not a big hassle to enter your passphrase once, and then you don't need to enter it again until you quit Xcode or reboot the machine.

There's some documentation on how to set all of this up, because we don't expect you to pick it up the first time you run through it. In fact, we're not going to run through the whole setup here. And that documentation is called "Remote Debugging with Xcode," and that's at connect.apple.com, Reference Library, and Tools. Now let's bring up Jim for a quick demo of remote debugging. Quick, because we're running out of time. So let's start over here.

So we have one already set up. Let me just open up the application and the framework that goes along with it. So this machine is another G5. This is the one we're working on here. I just want to debug. I'm going to set-- OK. So the first thing you have to see is this is the Sketch.app.

That's the main project, and I need to make sure that the current executable is set up for remote debugging. That's what I have to do on the host machine side. So there's that nice little Edit Active Executable. You can get up to here. Look in the debugging tab. So you check this checkbox, Debug Executable Remotely via SSH. You have to type in the host and username and IP address of the host.

And that's all. I have to get that right. You had to set up the SSH. I'm not going to show you that, because that would involve typing. And you saw how that worked last time. So we're not going to do that. OK, but then once that's set up, then it's just a matter of debugging.

It's going to ask me for my SSH password because I don't have an SSH agent running, and I don't have any of the freeware that does SSH and passes it down to applications or shareware. But it'll only ask me once. Once I've typed it in, if I debugged again, it wouldn't ask me again because it sets up an SSH agent itself and then uses that agent for the rest of the session. So we'll wait a little bit.

OK, can you switch to this machine for just one second? So just to prove to you that it is here, it's running, it's running under the debugger, you can, you know, do whatever, set, and... That's interesting. OK. Hit breakpoints over here. So let's go back to this one for a sec.

So see, I hit some nice breakpoint, now I'm here, I can step around or whatever. The one thing that we saw here was, you know, what I wanted to do was, I was stroking out a rectangle and I wanted to actually get away from, you know, watch the mouse events as I was stroking out the rectangle over here. But one of the things that's kind of inconvenient is, you know, okay, so I click down and then it was great. I stopped immediately at the mouse up event here, which is what you see, the event is mouse down, mouse down event rather.

But now, you know, this mouse, I've got to like, you know, put a sock full of rice on the mouse to hold the mouse button down and then slowly move it and then take the sock off for the mouse button up or whatever. There's actually some, one thing that's really neat that you can use in the universal access stuff which can make this kind of event level remote debugging, which is, that's what remote debugging, if you're, full screen games and then for regular applications, just like, you know, I have a tracking loop and I want to debug through a tracking loop, you know, how do I do that, then there's one thing that I want to show you that will make that that more convenient. So let's go back over here.

So what you can do is, if you go to Universal Access in System Preferences and turn on the Mouse Keys feature, "I have universal access in the mouse keys. So you turn that on and then what that does is that makes the keys into the mouse movement, but one of the really cool things is that it has separate keys for the mouse down, not mouse click, but just mouse down.

That's the zero key. And then the five key is the mouse up and then the arrow keys are the movement keys. So if we switch back over to this machine, oh we didn't ever go here. Okay. So I hit mouse down here and see I've broken the mouse down.

And then if I continue, I can And then, I can click and get the mouse move and, you know, continue and keep getting the mouse move. And I can go and I can, you know, have both hands and I don't have to worry about holding down the mouse button.

And then eventually, you know, when I get to the point where I want to make the rectangle, I have to continue, of course, and I can finally click the 5 and that's when I get the mouse up. So that's, that, that'll, you know, free your hands and you don't have to get your child to come and hold the mouse down or whatever.

The one other thing that's here, by the way, this was not one that we added. I mean, the event is an NS event and as we were going along, it was really convenient. I wanted to see what type of event I was getting because I was, you know, making events over here and then looking at them over here.

So again, we just added a custom data formatter. It turns out that under the event, one of the member elements is the underscore type that has the type of the event and I was annoyed at having to turn that out. So I just put it up there. So that's just, again, the data format is really close. Like, I want to see that now. Right.

Okay. That's good. Can you go back to slides? Thanks, Jim. So now we need to finish things up so we can take some of your questions really quick. This is the reference library. There's remote debugging in Xcode, which we talked about earlier. There's a document on "Fix and Continue." There's debugging with GDB, which is more in-depth than GDB, command line commands. And of course we have Xcode Help, which is built right into the application. It's a great resource to go look at. We encourage you to do that. And now who to contact? Matthew Formica.