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 may have transcription errors.
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 fixed 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 a Nextcode. 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 fixing 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, 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.
So 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 disassembly 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 a 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 three 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 the graphics, we see that it's an 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, FS ref, and some structures. And we have a bunch of about 35 foundation formatters as well. For instance, you saw NSArray, we tell you the count of objects. NSDictionary, we tell you the number of keys. We have formatters for NS point, NS rec, some of the app kit structures.
Now, your user customizations are all stored in your home directory. Tilda library, application support, Apple, developer tools, custom data views, custom data views.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 data formatter plugin.h file, which is actually inside the Xcode.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 format 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 can 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. Now, ExpressionFormatter will look something like this. You'll have your expressions surrounded by curly braces, and then again we have that colon-referenced column. 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 format. It 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-- or including colon 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 in 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 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, dollar sign var dot C underscore 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 dot 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 myBullDescription. $var is going to be replaced with the actual variable. $id is used by Xcode to-- plug-in custom data views manage the allocation of memory so that we have -- because we don't know how long it's going to take for Xcode to go and fetch that data, we can't use a single buffer for that, so we need to keep track of that. So that's something that will be passed to a custom print function that we supply that you can use in your custom plug-ins. Here's some example code.
we see that we have a pointer to our PBXGDB 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 cons up 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? OK. 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. OK, 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 what I like is to keep my value column fairly small, because I have 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 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 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.
You know, 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 we're 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 but because I said so in the demo script.
OK, 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 straightforward. 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 information I'm interested in from the value column to the 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? So that's pretty straightforward. uh... okay cool so now i want to stop here anymore Just some of you. Go under debugger and select. Hey, what do you want to do? Select that twice. Oh, I see. One more time.
Now I have source. Yay! Okay. So the next thing I want to stop at is... I think I want to be in SKT... Go back to you. Okay, so Here's another place, like my document is a type that's mine and 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 grubbing around in structures, because NSArrays hide from me where the number of elements is. And my little accessors are such that 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 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 the "your fun". So 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 and here's so $var, that's the thing that I'm referencing, the document, and I'm gonna 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. I cast the outermost thing. This one is going to come back as an in.
That's fine. And then that-- so that's the circles. That's an NSArray, really, but it's fine to call it an id. And I'm gonna 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. I don't amuse myself that much.
So, then the other example that, oh, Yeah, that's okay. Oh, one other thing to notice, by the way, so here in graphics, the--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, right? Graphics gets initialized in the next line of code that we're going to execute.
So--but this is actually calling, again, a function. It's calling count and something like that. So in most cases, you know, GDB is actually-- probably what happened was that Xcode went and asked GDB to call this function, and, you know, var contains some junk, some, you know, whatever was on the stack at that point. And that probably crashed because, you know, calling a 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, like, if you have a multithreaded program, these are going to be running, another thread might have the resource, okay, and that's the sort of thing that'll go badly, but just like a little minor crash, that really won't affect too much. Uh, so, okay, so... 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 any expression that's valid in your current language is what you're calling.
OK, 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 if the variable is 1, we're going to return yes. If it's positive, we're going to return yes. And otherwise, we're going to return no.
So 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 it 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. Why aren't you working? Hello? Oh, all my typing just went away. What did that happen, Chris? So $var-- SPEAKER 1: Is it running, maybe? SPEAKER 2: 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. Amen. Okay, so then the last thing that we want to do is show you how to do the plugins where you build your own custom plugin. 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 just grubbing around in some more stuff than you want to write here, these can be valuable. For instance, the Carbon stuff was done that way because you want to go and look through a window and pick out the ten things in the window list that are really interesting to you and format them up in some nice way. I mean, that actually would be tedious to write in as an expression in 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. 10. So it's easiest just to make an empty one. And I don't know.
on the desktop so I can find it. Okay. So what I want to make the, 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'll 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, what--whatever you--whatever the point of the--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, OK. Anyway, so you get to watch me type again.
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 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 plist. No, that's this one here. Same thing that Chris showed, you know, we're--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 is 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.
And then here's the actual code. So again, we provide some plug-in functions. In this case, basically, the ones that are useful are there's a sort of a printf, but it printf's to somewhere that we can find it. And there's-- well, this is just a print a string. And then there's an actual printf, which takes all the printf arguments that you can use if you want to do more fancy printing. And then there's one that help you handle memory allocation if you need to allocate memory because it's nice to let us do it rather than just click on your own. So we're not using those two. We're just using the simple message which just prints a message. It's good to check for this thing. That's going to be set by the data format or code that Xcode always runs in the target program but maybe that didn't work for some reason or you deleted it and forgot or something like that. And and we probably won't recover at that point. And then we're just taking the variable that's passed in. So we, you know, we were passing in $var, which was gonna be some bool. So it's a bool, and we check and print true or whatever print false. So it's pretty straightforward. So you can build that. Yeah, we're AppKit. OK, wonderful. OK, 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 P list 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? OK, 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.
So again, I didn't open the other project. Don't look at that. So desktop. 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 programs 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. JIM DICARLO: Let's have this one again.
OK, so in this case, 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.
the same place that I was before. Okay, so we'll run... 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... We can make there be something. So go to Tools, Global Variables. So this is going to be the list of all the stuff that's here. By globals, we mean global variables that have debug information, because if it doesn't have debug information, we don't know how to print it for you, and so we're just not going to list it. It turns out that AppKit has a whole bunch of them, and you can do evil things that you shouldn't do. So I didn't actually show you that. The one thing, other thing that can be kind of confusing is Sketch actually has a whole bunch of modules. And we're building this with Zero Link, so the way that Zero Link works is that each of the.o files, each of the modules in your program comes in as a separate bundle. And they come in on demand. That's the wonderful thing about Zero Link is you don't load everything right at startup, but you load it on demand as you need it. But it means that in the global variables view, stuff is not going to show up until it's actually shown up in your program because before it has been loaded, we don't know anything about it, we don't know where it's going to live, you know, so for instance here, you know, I would expect lots of SKT stuff and I actually don't have much. But in any case of what I have, you know, here's something. So the way that you decide that this is something you're going to view is you just click, check that you're going to view it and then you can close the browser and then it will show up under here. So that's how you selectively view global variables without being overwhelmed by the, you know, huge number, like there were 500 in AppKit. You just--you didn't want to see those 500. So this is a nice interface for showing you that. Just to convince you that the zero link thing works the way that I said, let's take that away. OK. So now I can go up and go back to Sketch and I can turn on, say, the grid and I can, you know, I don't know, change the spacing or whatever. And then if I go back here and pause and now view the global variables again, so now some grid stuff has shown up. So this is what's going to happen. So if you want to view globals before you can discover them the first time, you're going to actually have to make that code show up in your program. And then you'll be able to poke around and set it to be shown.
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. Like, 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.
a memory browser, it'll view memory at whatever address. So for instance, like $R3 here, you can type in addresses, you can type in any expression. $R3 normally stores the object. But I don't know, probably an object. I can't really tell. The other thing you can do is, 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 by this self draw document. 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 to track a location as it changed, you'd need to re-enter the expression every time. The other thing is you can change how much you want to display, 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. 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 10 by 7 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'd choose the mode a fourth time. You'd 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. 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 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 And this is all done because at runtime, we insert a debug version of the malloc library at runtime as your program's loading up in the debugger. and then it 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. 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 guard_malik? 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 dyd_insert_libraries. And then we specify the libg_malik_library. And that will cause libg_malik_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. 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 guard malloc 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 guard malloc. 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. Thanks, Jim. So with fix and continue, which we introduced a year ago, 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. Now this requires that all of your projects need to be built with debugging symbols enabled, so probably just the development build style. Fix continue needs to be enabled. And if you're using C++, you need to enable zero link as well.
Now, all these projects need to be open in Nextcode 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 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. And let's get Jason up here for our fix and continue. JASON KU: 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 and 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, as 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. Thank you. and 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. Square. 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, 'cause red rectangles are what everybody needs more of. Now we're gonna say save it and fix.
files the file, link 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 gonna 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 fixing and continuing 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 gonna-- 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.
There, okay. Fix. Now we get this popup. And this popup is telling us, 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 fixed and continuous supporting projects. Thank you, Christopher. CHRISTOPHER CHI: 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, SSH in, 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. Thank you. 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. And your seed doesn't support fix 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. This means that-- 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 we 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. JIM WALSH: 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. 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. Okay, 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 do whatever. 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 what I wanted to do was I was stroking out a rectangle. And I wanted to actually get away from-- watch the mouse events as I was stroking out the rectangle over here. But one of the things that's kind of inconvenient is, OK, 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 more convenient. So let's go back over here.
So I'm not here anymore. OK, so what you can do is if you go to Universal Access in System Preferences and turn on the Mouse Keys feature-- Universal access in the mouse, 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-- we didn't ever go here. OK, so I hit mouse down here, and see I broke in the down, and then if I continue-- And then I can click and get the mouse move and continue and keep getting the mouse move. And I can go and I can have both hands and I don't have to worry about holding down the mouse button. And then eventually 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 five and that's when I get the mouse up. So that's, that'll 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 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 _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 I want to see that now. OK. 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 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.