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: wwdc2003-310
$eventId
ID of event: wwdc2003
$eventContentId
ID of session without event part: 310
$eventShortId
Shortened ID of event: wwdc03
$year
Year of session: 2003
$extension
Extension of original filename: mov
$filenameAlmostEvery
Filename from "(Almost) Every..." gist: ...

WWDC03 • Session 310

Debugging and Tuning Carbon Applications

Apple Developer Tools • 1:02:05

In this session, we demonstrate how the Apple Developer Tools ease Carbon debugging, showing their use in analyzing C, C++, and Objective-C++ code. The Apple IDE's enhanced source-level debugger are featured as well as the power of Mac OS X's low-level GDB debugger. You'll see enhanced visual debugging in action, as well as the power of the command-line-driven GDB debugger. You'll also learn the best ways to use Apple's performance tools to get the most out of your Carbon apps.

Speakers: Chris Espinosa, Chris Nebel

Unlisted on Apple Developer site

Transcript

This transcript was generated using Whisper, it may have transcription errors.

Morning, everybody. Welcome to session 310, Debugging and Tuning Your Carbon Applications with Xcode. If you do not want to learn about debugging your Carbon applications with Xcode, now would be an excellent time to deplane. This is actually going to be a little more focused on debugging than on tuning. Robert Bodich did an excellent presentation on the performance tools yesterday, and I saw three plugs in sessions yesterday pointing to custom data formatters, so I've changed the content a little bit to focus more on the debugging and custom data formatting because most of the stuff that Robert explained on tuning and diagnostics applies just as well to Carbon applications as to Cocoa applications. So if you missed that, catch it on the DVD. There's some excellent stuff there. All right.

I want to talk about Carbon. It's not just for Code Warrior anymore. We've been designing Xcode so that it's a great Carbon development environment and putting a lot of emphasis on Carbon debugging in the debugging environment. Panther and Xcode have some really great tools built in to help you build and debug your Carbon applications. What you're going to learn in this session today are some basic differences between the Carbon debugging you may be used to on Mac OS 9 with MaxBug and the Code Warrior IDE debugger and what you have in Mac OS X with GDB and the Xcode debugger. There are some techniques for using GDB and Xcode to debug Carbon apps, some secrets that are hidden on Apple's website in plain sight in a file called Carbon Tips and Tricks. If you haven't read it, that's what I stole most of this presentation from. Some new features in Xcode that you haven't seen before that aren't on the web that are really cool that it will not only allow you to debug your application, build custom debuggers in your application, but also see a lot of your familiar Carbon data types right in the debugger with no further ado. And then some Carbon-specific performance and tuning tricks. I have like one or two slides on those, like I said.

Let's go through the steps in debugging and tuning. This should be familiar to everybody. First, you have to define your quality and performance goals. I think if you remember from the Mac OS X presentation, the way we got Safari so fast was that we made no performance regressions a requirement.

So if you really want to deliver a performance application, if you really want to deliver a quality bug-free application, all of the tools in the world won't help you if you don't have the methodology and the discipline to make sure that the tools are used in the process. So everything I'm going to show you today, it's great if you know it. It's even better if you define a process that makes sure that these get used. For example, distributing these custom data viewers throughout your organization or building them into your product build process rather than having them on a per-engineer ad hoc basis. You need to prep your project for debugging. And we're going to show you some ways set up some environment variables and set up some build settings to make your project more debugable that are Carbon specific. Get your basic functionality working.

Run your app in the debugger and isolate bugs. Then when you get the bugs out, run your app under the performance analysis tools to see if you've met your metrics. And it's really pretty important to make sure that your application works before you really start to use the performance tools on it because the performance tools far prefer a running application to a broken application. And then you iterate and iterate and iterate.

Your friend is GDB. I know a lot of you don't believe that, but GDB is the underlying debugger in the Mac OS X system, and it's really going to help you out. Debugging without GDB on Mac OS X is like debugging without MaxBug on Mac OS 9. You can get pretty far with symbolic debugging and with the debugging the IDE shows you, but unless you know what's going on down at the middle level, you'll never really know what's going on with your application. So if you don't have any familiarity with GDB, you really should acquire some in order to do great debugging on Mac OS X. We're going to show you some of the basics today and then some of the interactions between the IDE and GDB. The basic way to launch an application in the debugger is from the terminal. You issue the GDB command and then the path to your application.

And you need to go into your application and all the way down into the package of your application, the.app/contents/macOS all the way down to the DYLD executable. So this is people's first mistake is they tried to GDB the package, GDB the executable. Second thing you can do is just you can attach to a running application, launch your application, launch GDB and then attach to it. So you have two modes, launch it inside GDB or attach to it once it's running.

If you've used any other command line debugger, the commands are conceptually familiar, even though they're probably under different names. B sets a breakpoint. P displays a variable's value. So you have to print variables rather than just type expressions. X examines memory. And that's like DM in MaxBug. C continues execution after a breakpoint. And BT prints a backtrace. If you're used to SC in MaxBug, it's BT in GDB. We're all grownups. We can learn new two-letter acronyms.

What's great about GDB is that GDB, while it's stopped in the inferior, lets you evaluate expressions and call functions within your application or within the framework. And this is very powerful, and this is the first technique we're going to show you, is that there are a lot of debug-only functions built into the Carbon framework that let you figure out what's going on in your Carbon applications in ways you wouldn't normally be able to do. Many of these fulfill roles that were filled by D commands in MaxBug. These are now, instead of being in the development environment or in the debugger, they're built into the framework, and you just invoke them from the debugger.

It's a pretty long list, but you can print debug info for HI objects or window groups. You can print the event queue or watch events coming in. You can print the menu lists or menus or menu items or windows. You can even flash the viz region or the update region of a window just to see what it happens to be at this point. These are all listed in the Carbon tips and tricks document on the web, which I'll point you to at the end, so you don't have to scribble furiously now and get the parameter list right. But the point is you can call any of these from GDB while you're paused in your application to see what Carbon thinks your app is doing. So to demo some of these, I'm going to bring up Chris Neville on keyboards.

We're going to start with an application called Appearance Sample, which is on your Xcode CD. This copy of Appearance Sample has been updated to build a native project. And what we're going to do is we're going to invoke it in GDB. We're going to start it off in GDB without using Xcode. It's already been built.

And GDB loads and it runs the application and there you go. Now, to interrupt a running application from GDB, you just press Control-C and it stops it. And there we go. We're interrupted. You can do a stack trace, see where you are, things like that. Now we want to ask Carbon what a couple of things are going on. So we're going to make the debug print menu list call.

And we just do call void debug print menu list, paren paren. And we see this is our menu list according to HIToolbox. There you go. And it shows the menu ref. Chris is now going to do debug print all window groups. And he's going to get a hierarchical list of all the window groups. It's got the hex address. And it's also got the window group identifier. This will be very helpful in going back to your nib or going back to your code and figuring out what windows have been instantiated at any time. Now he's going to continue the application, go back, open another window.

Go back, interrupt the application again. Print the window list again, and now you see the new window is in the window list. So this is a very helpful debugging technique from GDB to figure out what's going on in your application. We can go back to the slides. Thank you, Chris.

Now I mentioned a little earlier about preparing your application for debugging. And there's a technique we use inside Apple for the Carbon Framework itself to prepare the debug version of the Carbon Framework, which I'll show you a little about later, which you can use in any Carbon application.

It's built into Carbon. There are two header files called debugging.h and assertmacros.h, which are part of the Carbon Framework. And if you include the Carbon Umbrella Framework, You've got these macros defined in your application right now. All you need to do is turn them on. AssertMacros.h, if you look at it, is a whole list of asserts you can throw in your application on various conditions. You can verify that things are certain values. You can verify that things are not values. You can make sure things are conforming, things are non-zero. Large number of macros you can use just to make sure that your data is what you want it to be. And in your production builds, they all fall out and are noop. So if you are considering using-- constructing a whole set of debug macros that are in your debug builds but fall out in your production builds, we've already built them for you. They're right there in assertmacros.h. All you have to do is define a preprocessor flag debug, set it to one, and they're invoked. And then there is an additional preprocessor macro that specifies the level of debugging. And we define four levels for you. And they have different degrees of precision and explanation and verbosity on the debug strings. If you set debug internal, that gives you the source file and the line number in which the assertion has been thrown, which is very useful for internal debugging. If you set debug external, it just gives the assert and the name of the string that was associated with the assert so your users can report that back. If you have debug break only, then when an assert is thrown, it just breaks into the debugger and doesn't log a message. And then if you say debug production, then all of the asserts are silent. And you can set these either from the command line, either include files and header files when you build your project, or you can even set them in Xcode. We'll show you a little bit about that later. There's a second thing, like I said earlier, the debug versions of the Carbon libraries. Every version of every Mako library that we supply in a framework comes in the developer release with two parallel versions, a debug version and a profiling version. And the debug version has perhaps additional calls and certainly additional console logging of what's going on inside that framework. And if you build and link your application with the debug variant, when you make system calls, then those system calls, if you pass them bad values or if there's a bad condition somewhere in the framework, it will do console spew.

This is very, very useful and not enough people do it. Again, you can control this with an environment variable if you're just running in GDB, or you can control it with a pop-up menu in Xcode, and we'll show you how to do that. One thing about using Xcode, you have to turn off zero link in order to use the debug variants of the libraries right now. Okay? And so we'll bring Chris back up again to show you a couple of these things.

So we're going to bring up the appearance sample code in Xcode now and go to a file called MegaDialog. That's right. Go to the switch pane method. And here's some-- there's some crude error checking going on here. This isn't really very useful. If the input value is invalid, then just do nothing. Maybe we want to see when that input value is invalid. So we're going to put an assert here. Just verify what that value is. And that will cause a log message if the pain index is 0. Now that's all we type here. The verify macro in assert macros does the rest of the work. Now to fire that off, we go to our project settings.

get the project inspector and go to our build styles because we want the asserts only in the development build style and not in the deployment build style. So we'll add by clicking the little plus box down at the corner, and other underscore C flags. And it moves, so you need to go select it again. Not that one. That one. And we're going to define the debug macro equals 1 and debug_internal equals 1.

and then we're going to build the project and by defining those were going to activate those macros were going to find verify is going to run well not yet Build errors and warnings. No, no, no, hang on, hang on. Turn off zero, well, Now, zero link is in the project settings. Yes. It's not spelled wrong. It's, it's, it's, it's, um. - Build errors and warnings window. - The build dialogue. Clean build. It's a development release, folks. GDB is also still running the application. That's OK. OK.

So now the application is built with the debug flags. He's going to run the application. And when the application runs, you see that the first time we call that, we get an assert that pain index equals 0. It turns out this function is called with pain index equals 0 a whole lot. Now maybe that's a performance problem or a logic problem in our application. Maybe it's not. But by just silently returning, we'd never know. But by throwing an assert there, we get an interesting log to figure out what's going on. Now you notice a couple other things about this is that it shows you the name third party client. Well, that's the default name. There's another variable that you can declare that's defined in debugging.h, that if you assign that preprocessor macro, it actually puts the name of your application, whatever you assign it in there, into your log so you can get better logging messages. And since we did the debug internal style, we're getting the line number and the source file in which the assert's happening. So these are built in. They're very useful. Now we need to quit the application, and we'll show you building with the debug version of the Carbon Library, which generates a lot more diagnostic output, not just a single assert.

So what Chris is going to do here is go down into the executable configuration, and this configures what happens when we run or debug our application. And you see there's a pop-up menu that says dynamic library runtime variant, the default standard, and we're going to set it to debug. And that means when we link our application and when we run our application, we're going to link and run it against the debug variant of the library. So if we build it and run it, and open up the run log, we see a whole lot of output from the Carbon Framework of interesting things that this application, this sample application that Apple ships on the developer CD as an example of how to write code, all of the wrong values that it passes the Carbon Framework. So use this as a lesson.

This is really very useful if you want to know what the framework is doing. As you mouse around the application and as we do things, it generates even more asserts. These are asserts using the assert macros and using debugging.h that are built into the Carbon framework that are turned on in the debug variant. Okay? Thank you, Chris.

Now he showed you a little bit of debugging with Xcode. First we started out in GDB, and then we did a little bit of GDB style, you know, text spewing from inside of Xcode. Now we're going to show you a little bit of Carbon debugging interactively with the Xcode debugger. The Xcode debugger is a lot better than the project builder debugger was. I hope you saw in a couple of the sessions like yesterday afternoon some of the capabilities of it. I'm going to go a little more in depth into some of the Carbon aspects of that. Like any other IDE debugger, it shows you the execution threads, it shows you the stacks and the back traces where you happen to be in the code, it shows you the source code, it shows you the local variables, and it shows you the input parameters of the functions in a way that you can figure out what the values are and what the variables are. It also lets you set and manage breakpoints. Thank you.

There are some new debugging features in Xcode. We do C++ exception handling where GDB and Project Builder did not. This is going to be very useful if you use C++ exceptions as a routine part of your application structure. We allow you to step through templates. So templates can be really, really gnarly. And if you can't step through them, step through instantiation or use of them, it's really, really hard to figure out what's going on. We do that now in Xcode. We've got some built-in data viewers for foundation data types and the most important Carbon data types you use. And it's an extensible plug-in architecture where you can define your own, not just for Carbon data types, but for application-specific data types as well.

So now I'm going to hand it over to Chris, and he's going to do his demo of C++ exceptions and the stepping through templates. CHRISTOPHER COLE: OK. So what we've got here should look familiar to you if you came to session 307. This is the Power Plant appearance demo, kind of the Power Plant version of Appearance Sample that we've imported into Xcode. So let's just start this debugging. Loads, runs.

OK, so here it is. Again, just shows off the various controls, various kinds of windows. various kinds of windows. This isn't working. It's a bug. How are you going to fix it? How indeed. OK, so when this particular type of bug happens, I know from experience that it's usually because someone is throwing an exception and it's just being silently swallowed. Now, stuff like this is pretty hard to track down, especially in something like Power Plant, because quite often you didn't write either the code that's throwing or the code that's catching.

However, what we can do with Xcode is we can pause and then turn on stop on C++ throw and stop on C++ catch. So we'll continue, go back to appearance demo. And now, oh, sure enough. Thank you. So there's the exception itself, and it's coming from this function here, throwIfNil, because I just set it to nil to force an exception.

Power plant tends to not throw exceptions unless something goes seriously wrong, so that was the simplest way to do it. So let's see where that actually winds up. We'll hit continue. And now we stop in the catch. Or actually, we stop on the function call that generated the exception, process next event. If we step over, we'll wind up in the catch block itself.

So I also wanted to show off some debugging of standard C++ library stuff and C++ standard template library. And to do that, I actually wrote my own project, because Power Plant tends to not use this stuff, which is fair, because it was created before they mostly existed. So what we have here is a fairly simple, stupid STL-- oh, I knew I was going to forget that. Okay, there's a bug. Wherein-- and now I have to-- you have to turn off stop on throw and catch before you run the debugger, or the debugger won't run. We'll fix that in time for GM. All right, let's try that again.

OK. So here we are. I've actually already stopped at a breakpoint. This is sort of your STL 101 application. It sucks a bunch of words out of the system dictionary, uppercases them, and then blats out a few to standard output. So we've stopped right here on a call to foreach. I've already got a breakpoint on the function that's going to uppercase everything using transform. So we'll step into that.

OK, so here we are stopped in uppercase. And we'd like to see the string that we're operating on. So well, here it is. It's s. But if we expand it, this is not really what I had in mind. This is not exactly useful. I want to see the string.

So this is what custom data formatters are for. You've probably seen already how you can use custom data formatters to pick pieces out of a structure, individual fields. But you can also call a function. So what we'll do here is we'll say var.cstr, because standard library strings have a handy thing that will return a C string. And it's going to think about that for a minute. Really, this didn't happen when I was practicing. It worked great in rehearsal, folks. It worked fine in rehearsal. What's going on here?

Well, this is entertaining. Yeah. All right. We're just going to-- Well, while Chris is doing that, we'll go back to slides and explain how the custom data formatters work. The custom data viewers, if you had seen them yesterday, Chris, let me know when it's working. Yep. The custom data format is, if you've seen them yesterday, a simple functionality that has three levels of implementation. The simple functionality is there's a summary column, and you can type an expression into the summary column, and that expression is evaluated. The basic thing you can do is you can extract members from a structure or a class and display them in the summary view, and you can put strings around them. So you can say length equals this member, height equals that member, and that uses this percent sign notation, percent member percent. So anywhere you have a struct or a class or an array, you can use the percent sign notation and get at things inside that structure and promote them to the summary of that structure. That really helps you look at a variable without having to turn down the turn down arrow, especially if it's a very large thing. It gets you a lot more data density in your debug review. The second level is that you can evaluate an expression.

And the basic rule is that you can put inside curly brackets in a summary view anything that you can type on the GDB command line and execute. And that means any C or C++ arithmetic expression and any function call, function calls within your application, method calls on your objects, or system calls to the Carbon framework. This is very, very powerful. Those are evaluated every time that that variable is displayed. So every step, it's going to see if the variable's value has changed, and if it has, it's going to re-evaluate that expression. So you've got to be a little careful about this because it's going to be re-evaluated very, very frequently. So don't make your expressions too complex or too lengthy to execute, and make sure you don't call anything with side effects, for example, because this is actually executing in the context of your application, in your application's process space, in your application's memory space, and anything that this application does can affect, anything this expression does can affect your application.

There are a couple of utility variables that you can use in this expression. $var is the thing itself, the thing that's being evaluated. So you can just do, you know, curly brace $var dot and then get at members of it, or you can call methods on that by $var arrow or whatever. And then for convenience, $parent, if you're viewing a class member or a struct member, that $parent is its owner. So if you're drilling down inside something but you need reference to a sibling, for example, you can do that by $parent and then referring off the sibling. Or you can get information in the parent itself. That's very useful. uh... the third thing that you can are you ready uh... sort of okay if we can go back to chris machine will show OK, so I still haven't been able to get the custom data formatters to work. But what I will show you is the third thing, which is stepping through template code. So we're stopped here in our own function. And you'll notice that we were called from for each. So-- CHRIS BROADFOOT: Wait, wait, wait. Chris, I've got it. CHRIS BROADFOOT: You do? Remove the custom data formatter I threw in right before the demo from the custom data formatters folder and try again. You bastard.

Really folks, I was trying to improve the quality of experience of the demo. Oh, okay. Where is it? We'll show you how to install custom data formatters. Library folder. Application support, Apple, developer tools, custom data views, C list plugin dot bundle. Yeah, just drag those to the trash. Quit and reopen Xcode and try again.

I was up here until five minutes before the presentation started trying to debug something that many of you requested yesterday. I want to show you. I'll show you the source code, but I'm not going to show you it working because it crashes Xcode. OK, so let's try this again. So we stopped in transform. We want to see the actual value of this string. So let's see if this works this time. var.cstr, function call. Aha, now it works.

Mayor Cooper, Mayor Maxima Cooper. OK. So that's all fun. So now, like I said, we were actually called from foreach. So we'd like to see what's going on up one level. So let's remove this breakpoint so we don't keep hitting it. And if we just step out-- ooh, template function. And we can just-- step through this. Now again we've got sort of a similar problem here except this one is even more complicated. I'd like to see the thing that first points to. This is an iterator and again this is another obscure structure that has all sorts of weird bits that I really don't understand. But custom data formatters can deal with these too, even though it's a template type. So let's see. *var And there it is. So we can see this changing and getting uppercased as we step through the loop. Thank you.

OK, back to the slides, please. So we've shown you the two kinds of custom data view formulas. First, the simple member access, and then second, the function call. And the function calls are very powerful. They can work within your application. They can work on template types. They can work on C++ classes. They're really powerful. But there's one more thing that's even more powerful, so powerful that it'll bring down Xcode if you do it wrong.

and that's writing a custom data view bundle. A custom data view bundle is, as the name implies, a bundle. And it's a bundle with really only two parts to it. There is a plist, and there's a dynamically loaded library. And the dynamically loaded library just has functions that you define, and it has one special static variable. And the plist is simply a plist of types, type names, as they appear in the debugger, and formulas, formulas exactly as you'd enter them in the custom data view formula. In fact, the best way to build one is when you type your formulas into the debugger and experiment with them iteratively there, they're saved automatically in a plist in your applications configuration file. And you can just go there, open up the plist, copy and paste it from there, and put it in your own custom application specific one, and have it there permanently. So the same expression syntax. What you generally do is you build a small executable, a small dynamic library, with a function that you want to call only when you're debugging.

Not something you want to build into your application, but something you want to call only when you're debugging. And then you invoke that from the expression in the plist. And we've done this to build the Carbon foundation formatters which are pre-built in. They're put in your library application support folders and you can build your own in and put them in your home directory application support folders or put them in your machine specific application support folder if you want. Now these library functions, as I said, like any other function call, these library functions are called in the context of your running application when your application is stopped at a breakpoint, which means you're in a very, very delicate situation. Do not allocate memory. Do not grab a lock or pend on something else being locked. Don't side effect any application variables.

Don't leak. There are a lot of things you do not want to do when the debugger has invoked you when your application is stopped at a breakpoint. So you need to be fairly careful about writing these. When I was writing the data viewer to view an OS error or OS status, I was looking at all the ways to handle the 1900 different values in display and intelligible strings for them, and it turned out that the simplest, safest, most straightforward, fastest way to do it was with the 1900 case switch statement. let the compiler generate the tree to figure out which string goes with which OS error. It didn't allocate any memory. It was very fast. It didn't side effect anything. And it was very safe to use in any context. So build these for safety. We provide some functions to help you do this. There are two functions that we provide as callbacks into the Xcode debugger that you can use from your custom DataView bundles.

One just allocates memory that is associated with that particular line in the display, and you can use that as scratchpad memory. You can put a struct inside it and put some temporaries in there, or you can use it to build your string if it's a several-step process to build your string. And then when that variable goes out of scope, Xcode will release that memory so you don't leak. That is much safer than doing mallocs yourself inside your custom data viewer.

The second one is essentially an sprintf. You can give--pass this function this ID and then sprintf type arguments and it will print it to that line and then free the memory that's used for that printf afterwards and these are very powerful. So use these callbacks for the printf function and the buffer allocation. Don't do anything else except make safe non-side affecting function calls in your application or access data members.

So here's a simple example of one. This is the custom data viewer for-- this is the actual code of the data viewer for a Carbon handle inside the Carbon data viewers package. There are really two parts to this. One is the plist entry, and the other is the library code. And then the top is the plist entry. All you see-- it's basically the invocation of the library code, the bundle code, with the variable and the ID. And that's all. Very straightforward.

And then the library code, the first two lines are to get me access to my callbacks. There's a special variable called PBXGDBPluginFunctions that when Xcode debugger loads my plugin, it plugs in a pointer to an array of callback functions into that static. And then I jump through that in order to get to my callbacks. And then you see my function, the data viewer's Carbon handle, expects to get a handle and the ID. It checks to see whether the handle's valid, because I don't want to do anything like jumping through 0 if I don't have to.

And if it is, then I essentially S print f through this function to print the size of the handle by calling get handle size, which is usually pretty safe. Then I checked the H get state and mask it against the lock bit. And depending upon the state of that, isprintf lock or unlock. So this way, whenever I see a handle in my debugger data viewer, I get its size and its state of whether it's locked or unlocked. And if it's null or the handle is invalid, then I get invalid. Okay? So this is a very simple data viewer. And we have built in a lot of these for the foundation classes, and we have built in a lot of these for Carbon classes. And if Chris is willing to come up again, Then he's going to show you some of these, again, in Appearance Sample, which has a little more support for these things. So we're going to bring up Appearance Sample in the debugger.

And he's going to set a breakpoint. And I think that we figured out proxy dialog.cp line 106. and i think i'll be continued that's the assert okay That's the assert we introduced in the first step. Just keep continuing. I think we should go remove this. If you are bugged by asserts, stop it, and I'll show you how to turn this off. You have this turned on.

So stop? Right. Project-- no, go to executables, turn down executables, appearance sample, double click, scroll down. Yeah. No, double click. You were there. Scroll down. break on calls to debugger debugster, uncheck that box. And that makes your certs not break in the debugger. We gave them something additional, unplanned. There you go. OK, so go find proxydialog.cp.

And go to line 106. There should be a command key to go to a line. which is invalid now for some reason. Yeah, I used to know what it was. Well, it says it's Command-L, but it doesn't let you do it right now for some reason. Yes, now it does. Focusing problem. 106. And hey, we've got a break point there. Great, that's all we need. So then go back to the application. And we're going to pull up Window Proxy and click the Add Proxy FS spec. And pick a file, any file, don't tell me what it is.

That's fine. And we should hit our breakpoint in the debugger. There we go. Now, notice a couple of things. The file spec variable, the summary is the name of the file. That's very useful. Turn down the file spec and see what you could see otherwise. Well, there's the vrefnum and the parent ID. Those are nice. But the name, it's a str255. Or it's a str64, which is not a str255, which we haven't wired up. But just turning it up and seeing just the name and the file spec, that's very nice. See, also, err is no error. Just change that to like negative 39 or something. And now it says EOF error. So it'll show you what your errors are.

Like I said, it knows all 1900 errors that are in the Carbon headers, and that's through a 1900 case switch statement. But the next thing, though, you know that Nav Services returns your file spec in an AE desk. Well, isn't this interesting? Look at the file spec desk, and it says it's a type FSS. Okay? So it tells me what type the desk is right at the top. Now, if I turn it down, it'll show me that it's a type FSS, and that's the contents of it. - It.

When you turn down AEDesk, it goes and gets the data out of the AEDesk and then displays it in that line, but it only does that when you turn it down, so it's not expensive unless you really want to see the contents. And it does this with the $parent variable I told you about earlier. It goes back to its parent to get its descriptor type, which is not an OS type. It's an int, unfortunately, so it doesn't show up as a four-character code. But you also see unused keyword down at the bottom, if you could select that, Chris. That's an OS type, and instead of showing up as a long decimal or a hex number, it shows up as four characters in the variable view. That's something we've put for Carbon debugging in Xcode for you. Okay? So that's custom data viewers. If we have a little time at the end, I'll show you how to construct a data viewer bundle that crashes Xcode, because that's what I've got to show you right now. And we're working on some better samples for this to post on the web. But what we've implemented in the Carbon Data Viewers is all of the file types, alias, FS spec, FS ref. We've implemented the AE desk types. We've implemented inspectors for all of the opaque HI toolbox references.

Window shows you its name and position. Menu shows you its title. HIObject shows you what kind of HIObject is as the identifier. We've implemented basic supports for the Carbon Events that shows you the event class and the event name. For Apple Events, the same thing, the event class and the event name if it's a known Apple event and the four character code if it's not. And just a whole bunch of things, all the date time things show up as date times instead of 64-bit decimal numbers. So I think you'll find when you're debugging an Xcode, your familiar Carbon data types show up as the values you think of them as, rather than the value that GDB thinks of them as. And I think you'll find that that's very powerful. OK, back to the slides, please.

Now I spoke a little about Carbon Events and a little bit about Apple Events. Now Carbon Events and Apple Events are large things. They're large and they're complex and we couldn't fit them into single lines in the debugger display. There are some things that you can do when debugging a Carbon Application to see what's happening with your Carbon Events and with your Apple Events other than just to see the class and the particular event type. Right now they're accessible only via the GDB style interface because they stream a lot of text. We're going to try to find a way to integrate that experience better to do a little better logging of it. But for now I want to give you some pointers on how to do this. There's a function for Carbon Events called setEventTraceEnabled. That is, once again, it's one of these GDB calls from the GDB command line into the Carbon framework. And that gives you exhaustive information on what Carbon events are happening. There's some similar things that you can do. There's environment variables you can set to turn on and off Apple event debugging, and we'll show those too. Those are done with environment variables rather than with the call. And the output of both of these goes to the standard I/O window, which is available in the console drawer and also available-- highly recommended you do this-- as a separate window in the Xcode environment. As I said, for Apple events, there are two environment variables you can set.

AEDebugSends will print out any event that you send. And AEDebugReceives will print out any event that your application receives. There are also some functions you can call from GDB. If you want to see a full AEDesk rather than just the summary, if it happens to be a custom one of yours, GDB.printAEDesk will print that desk. And if you want to know more about this, we've even put in a function called the GDB print help debugging Apple events, which spools some help text to standard out. And then you can read that and follow the instructions in it. So let's show you those.

Are we still in the appearance sample? Yep. We should remove those breakpoints. Already done. Great. And have you set up the aEdebug receives environment variable? Partly. There it is. An environment variable you can either set up in the shell before you launch your application in GDB, or you can set it here in the Xcode API. Just create it, check the box, set the value, and then when your application is launched, the shell that launches that application has that environment variable set. That makes it very convenient. So we're going to run this application again and the first thing we're going to do is to throw an Apple event at it. And my favorite way to throw Apple events at an application is by using Apple Script. I'm going to show the run log first so we get to see when it shows up. Clean, pristine, empty run log. Now Chris has written a simple Apple Script here. I'm sure you had to hit the books to learn how to do this. And he's going to run the script and he's going to send That's the error we expected, but we're not-- The error is expected. The absence of the run log is not. No, not underscore. I did turn this on. against the debug version?. We didn't in rehearsal. We'll try that suggestion. Fine, we'll show you the Carbon spew. Or that. He's going to turn on a debug just to make sure.

send the affluent and still no joy i can't tell you what i broke this time but it's obviously not your fault it worked in rehearsal it worked in rehearsal There it is. Is that? - Oh. - No, it's there. It's just not in the run log. Oh, it's not in the run log. Chris, it's in standard IO. Show STD IO.

There it is. Oh, OK. My mistake. We were looking in the wrong place. It was there all the time. So here are all the multiple events that Chris was sending to the application. And when he turned on AEDebugging, it gives you even more information for what handlers it's looking for, what tables it's looking for the handlers in, and what order it's looking for them in. So if your Apple event handlers are firing in an unexpected order, or the wrong ones are firing, turn on AEDBUG1 in your environment variables, and this information is logged to the output. This is very useful if you've got a scriptable application in figuring out what AppleScript sends you or what other applications send you in terms of events. And once again, it comes up in the standard I/O log, just like it says on our sheet right here, not in the run log.

Another thing that comes up in the standard I/O log is the Carbon debugging, Carbon events debugging spew. So what Chris is doing now in the little GDB terminal window is he's calling set event trace enabled. it's just parin parin but I guess. No, it's not. It's not? You tested it?

We'll talk about that later. So now that he set the event tracing enabled when we go back to the application start doing things that cause Carbon events to get sent, we see a large amount of diagnostic information about what Carbon events are being sent to whom and when, with what arguments, who's handling them, and what happens as a result of it. Sending event, called handler, event was handled, leaving target, send event to event target entered. It is more information than you probably need. But if you are trying to debug your Carbon events, this is the first tool to use because it shows you explicitly, step by step, everything that is happening. Thank you. Okay, and I think that that's all for the demos.

Now, I know you say, but I like MaxBug. Well, it's a transitional experience, but I think that you'll find many of the things that you want to do inside MaxBug are present in GDB. Quinn wrote a great tech note, TN2030, GDB for MaxBug veterans, which really helps you transition from one tool to another. GDB is not as quick. It does not run down at the chip level.

It doesn't take over the machine, And so you have these process lags. It loads all the symbol files because it's a symbolic low-level debugger, not just a machine low-level debugger. So you won't get the snappy response time from GDB that you expected with MaxBug. GDB, by its base nature, is not Carbon savvy. It doesn't have all the things built into it. We're layering things on top of it to make it more Carbon savvy. And GDB doesn't necessarily show you the whole machine because it only attaches to a given running process at a time. But GDB is much better at symbolics, much better at what types your variables are. It has not just better conditional breakpoints, but it has future breakpoints. You can set a breakpoint in a library that hasn't been loaded yet. And when that library is loaded, the breakpoint will be set in it automatically. That's very useful to use. GDB is better at evaluating expressions and calling functions. And it's better at not crashing the machine if you do something wrong in the debugger, mainly because it's running in a different process than the application is.

But I hear you say, but I like CodeWarrior IDE debugging. Well, this is a lot more valid because CodeWarrior IDE has a lot more windows that do useful and interesting things. Interestingly enough, when you're debugging Mako with CodeWarrior, it's using GDB for a lot of the underlying machinery to step and to control the execution flow of the application, though it's using its own functions to get the symbolics information and to display the variables and stack traces. These debugging entry points are available from CodeWarrior expressions too, so all the things that we've showed you from the GDB command line, those are available from the CodeWarrior IDE debugger as well, if you happen to be using that. Thank you.

And if you like Zone Ranger for memory diagnostics tool, well, you know, Zone Ranger really is great for debugging heap zones, and heap zones are just not that relevant in Mac OS X anymore. In order to really understand what's going on in Mac OS X memory management, it's less of a static looking at what's happening in my heap zone and more of a dynamic looking at who's calling malloc and when and are these things getting released in time and by whom and on what threads. And some of the Mac OS tools like malloc-debug and like samplers memory allocation viewer, those are much, much more relevant to debugging Mac OS X memory problems than static views of your heap like zone ranger and is my heap fragmented or has my heap been stepped on are.

Memory diagnostics with Carbon, you know, new pointer, a new handle, just get down and call malloc. So if you debug with malloc, you're debugging new pointer and new handle. That's really the important thing to remember. Your handles are just not going to move around. So this whole class of problems that you used to do on Mac OS 9, they just don't exist anymore on 10. Your low-level memory handling code is not going to be called because until you hit that 4-gig barrier, and on a G5, not even then, you're not going to be asked to compact your heap. It's just not going to happen. Your big problem will be leaks, scribbling on your own allocations, you know, getting a wrong pointer somewhere, and trying to use something after you've freed it. And those are things that the malloc debug tools and the sampler tools are really good at doing.

So let's summarize. We've gone through a lot of stuff on Carbon debugging. You've seen the C++ exception handling, the throw and-- break on throw and break on catch. You've seen stepping through templates and using custom data views in order to see the contents of templates, which is very useful.

You've seen some built-in Carbon and foundation data viewers that show you your Carbon data types in a very familiar way. You've seen how to build your own either with a simple member access or with a complex expression or even with a bundle of code that you write yourself and drop in to do your own custom data viewers. We hope that you'll be able to use some of these tools in debugging your Carbon applications. We will be down in the Van Ness room to help you get up on Xcode and get your projects on Xcode so you can take advantage of some of these tools. We'll be there for the rest of the day. And we're going to bring up Godfrey. Oh, we've got actually a lot more to talk about before I call up Godfrey. Because I've got 18 minutes and I'm not going to let you be bored.

We've got a lot in Xcode right now in the developer release. In the 1.0, the features you've seen are going to be polished, and they're not going to crash, and they're going to be a little more robust. That's what 1.0 is about. We know what you need. We know you need a more flexible type viewing system. We get very spoiled by using the CodeWarrior view anything as any type system, and by the CodeWarrior memory viewer. That's our aim. We're working on it. It won't be in the 1.0, but it should be in the next release after that. That's certainly on our list. Getting these tracing tools to debug more voluminous things, getting them built into the IDE so you don't have to spool them out to another text window and then scroll through it, that's another priority. We're going to work on that to find a better integration of those tools. Of course, we can never step or view too quickly. We've got the problem now of the more data you want to see, the slower you step, and so there's a tipping point there between fidelity of data and speed of stepping. One of the things you can do is you can turn off custom data views while you're stepping and then turn it on again in order to look at the values. That we found is a useful compromise. And then watch points and event points, we know those are very important to you. We're working on those. You can do those at the low level GDB command line. We're working on bringing them up into the IDE interface.

There are a lot of resources you can use for more information on this. Godfrey is your main contact, and the development tools engineering feedback, as we've told you all week, xcode-feedback at group.apple.com. Use Bug Reporter to post bugs. 1.0 is only going to be as good as the bug reports we get.

And we'll be talking about these on mailing lists. The public information now and nondisclosure information should really come to the Xcode list. There are a couple more sessions. There's a session right after this one called Software Testing Tools for Mac OS X, which will go more into how to use automated testing tools, both Apple and third party, to do automated testing of your applications and especially your applications UI. I know that's a very important issue for a lot of you. If you are bringing your Carbon app to Mac OS X, you really, really have to go to How to write a modern Carbon application session at 2 o'clock today in the Knob Hill room.

If you're still using mbar resources and you're not using Carbon events and you still have whole big hunks of code that does memory management in your application, you really have to come see that a Carbon application on Mac OS X is different than a Carbon application on Mac OS 9. There are a whole lot of things that you are freed from, a whole lot of new capabilities that you can use. And please come to the ADC feedback forum today if you're not going to the How to Write a Modern Carbon App session and give ADC some feedback on the information that ADC has been providing to you.

The reference library. Go to the CD set and see the presentation from last night on basic debugging to go deep into the generic debugging capabilities of GDB. Go to the debugger services reference in the Carbon Performance Directory. There's a lot of information on debugging with GDB, GDB internals.

The GDB release notes are always very helpful. Quinn's tech note is very helpful. And here's the Carbon tips and tricks document. It's at developer.apple.com/carbon/tipsandtricks .html. It's a very long document with a lot of things, including all of those APIs, the names we called, to print out diagnostics from the Carbon frameworks. It's a very, very useful technical note.

If you haven't used it before, the Chud Toolkit is an incredibly useful set of tools for doing machine-level, instruction-level debugging of what your performance profile of your application is. There have been a couple of demos so far this week, and you can go back to the DVD set and watch those. Or on your Developer Tools CD, open up the Chud Tools package and install them, and just see what miracles they can show you in your code.