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

WWDC01 • Session 706

Debugging on Mac OS X

Development Tools • 1:03:16

Learn how to configure, run, and debug Carbon, Cocoa, and Java applications in the Project Builder IDE. Learn advanced features of the GDB debugger and useful techniques for getting the most out of this powerful tool.

Speakers: Dave Payne, Rab Hagy, Dave Ewing, Jim Ingham, Klee Dienes

Unlisted on Apple Developer site

Transcript

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

Good morning. It's Friday morning. Have a good time at the party last night? Great. OK, we have a rather full schedule for you today, so I'm not going to take any time. One thing I will remind you is that we have a feedback forum this afternoon. I'll also tell you that at the end of the session, so we'd like as many of you as possible to show up for that. And without further ado, let me introduce Dave Payne, the manager of our developer applications team.

[Transcript missing]

So what we're going to take a look at today is mostly concentrating on debugging with Project Builder for both C-based languages and for Java. We'll also be getting into some advanced debugging situations with GDB. But before we really dive down into that, we'll also take a look at how to look at applications that just crash on your system or if they're hung, what can you do about that.

So let's just dive right in with that. So on Mac OS 7, 8, 9, previously, you're familiar with if an application crashes, you can have MaxBug installed on your screen or on your system, and you'll crash and catch the crashes in MaxBug. We do now have a facility in Mac OS X to catch crashes and give you stackback traces and things like that. In order to enable this, you have to go in as an admin user.

And add a configuration line to the etc.host config file. So the facility is called crash reporter. And if you go in and set crash reporter equals dash yes dash, which is the format that all those lines are in, then you'll automatically get this facility turned on. So what happens then, if you're running the console application, it'll ask you, hey, an application just crashed, do you want to see the stackback trace? And you'll see the crash log, yes or no.

There's a little dialogue that pops up there. And if you say yes, then it brings console to the foreground. You've got the console window, but now you've also got a crash log window as well that shows you the stackback trace for all the threads in your application. And it shows you the register state. If you want to look at this sometime from terminal outside of the application, you can do that.

So this is a little bit of the console application. The file is actually kept in slash var slash vm crash dot log. So one thing to be aware of, though, is it just appends the crash information to the bottom of this file. And it retains that across reboots. So you can have a week's worth of crashes stored in your file there. And you fire it up.

And, huh, I thought we fixed that one. Well, that's because you're looking at the start of the file. So you may need to clean it out on occasion. But that can be a reason. It's a really useful facility. You can then have people, you know, if you've got beta testers or whatever, they can enable this on their systems and send the back traces back to you.

Actually, if I could have a quick poll of the audience. I'm considering just automatically enabling this when we install the developer tool CD. What do you think of that? Okay, we'll try and do that for next time around then. That's not happening this time on your CD, but you can do this yourself.

So another one is, gee, my app is just hanging. What's up with that? How can I take a look at that? I've been running it. Is there anything I can see? Well, in some of the sessions, you've seen the sampler graphical application for doing CPU monitoring, profiling, what's going on. There's also a command line version of that called sample.

From the command line, in a terminal, you could execute sample and then the process ID. And it also understands just the name of your binary as well, if there's only one copy of it running. And then just the number of seconds that you want to sample. So I typically say sample my app for 10 seconds. It tells you where it puts the file into slash temp. And then you can go off and take a look at, again, the stack backtraces to see where your app is spending its time.

Again, that can be a very useful thing that you could have people send the samples back to you. If you do perchance ever happen to find any bugs in any of our stuff, it's helpful to attach these crash logs or these sample outputs into any bug reports or emails that you would send in to us to tell us what you might have found with our code as well. There's also a facility with GDB. Where you can attach to a process.

And if you've got source code for it, then even though you didn't start it up under the debugger, you can attach to it later. We don't have that wired in through project builder at this point. But you can do this. You'll see usages of GDB attached later in the session.

So many of you are familiar with some of the debugging facilities of Project Builder. It's full graphical debugging for C-based languages, so C, Objective-C, C++. And Zem inspires me to say Objective-C++ will be supported there too. And also Java. We support all the different types of macro binaries that you've got on your system. And we'll see how to do that through the course of this session.

For the C-based languages, we'd use GDB as the low-level debugger to communicate with the OS. Architecturally, this is what it looks like here. As Project Builder communicates with GDB, GDB handles all the complexity of working with the operating system, so the Unix P-trace and Mach exceptions and your target application. It's a fairly complex interaction. So it takes care of all that for us.

Because that is fairly complex, we also work with the MetroWorks folks to get the CodeWarrior debugging working well as well by handling the same level of interaction and then using a debugging protocol. If you're using CodeWarrior at all, you may have heard that they no longer require the use of the debug knob.

That aspect of it is built directly into CodeWarrior now. But at the lower levels, we share the same facilities. So without further ado, I'd like to bring out Rab Hagy, senior engineer on the Project Builder team, to actually show you Project Builder debugging in action. Thanks, Rab. Thanks, Dave.

All right, good morning everyone. In this section of our presentation today, I'll be giving you a bit of a status on where we stand with debugging with Project Builder, talk about how to configure your project for debugging, how, where, and what of setting up your project. Talk a bit about breakpoints, and then my colleague Dave will come up and talk about debugging Java.

All right. If you're new to Mac OS X and to Project Builder, welcome. I hope you've seen through our other sessions at the conference that we have a full-featured IDE, and with respect to debugging, we have a nice GUI for showing the threads, stacks, and variables in stack frames. And we have a full-featured breakpoint model and support for debugging multiple projects. If you've been with us for a while, the changes from last year's conference, you won't see too many changes at the user interface level.

We've been concentrating on improving the infrastructure, so we have much better C++ support. We've been tracking changes to Mac OS X, and we've improved the way Project Builder communicates with the underlying debugger. And of course, last year we showed just a

[Transcript missing]

All right, let's talk about the how of building for debugging. With this release of Project Builder, we've introduced build styles, which were covered in detail in the Project Builder in-depth session.

Build styles allow you to configure a single target for multiple uses. Out of the box, you get two build styles, one called development and one for deployment. We encourage you to set up your development build style tailored towards debugging and your day-to-day development. Use the deployment build style for when you're getting ready to actually build your product for shipping.

Now, the... The two key aspects of the build style and building for related to debugging are the compiler settings for optimization and generation of debugging symbols. So, naturally, to do full source level debugging, you need to ensure that you, in fact, have...are telling the compiler to generate symbols. And you can also vary the optimization level.

Now, just because you can mix generation of symbols and optimization, you need to be aware that at the higher levels of optimization, the mapping that the symbol information provides a mapping from the machine state to the logical state in your source code. And that mapping begins to break down at higher levels of optimization. So we recommend for debugging either no optimization or optimization level one.

And I'll give you-- in our demo, I'll cover that a bit more. All right, here's a quick look at the user interface for the target build settings, just so you can get oriented. I've highlighted the pop-up for the development optimization level and down below the checkbox for including debugger symbols.

All right, now let's talk about the where of building your project. Out of the box, by default, Project Builder builds each project in its own build folder, which contains the intermediate results of the build and the final product of the build. So here we have app project that builds in its own build folder and a framework project that builds in its own build folder.

Now, most projects that you'll be working with are larger ones and you'll probably have multiple Project Builder projects. In that case, when you have a set of related projects that you want to build and debug together, the default is not suitable. So what we recommend is that you create what we call a common build folder on your system. And then you need to configure each project to build in that folder.

And this is a per user setting, so each user on the development team needs to configure his or her instance of the project to point to a common build folder. It's a little tricky to find where the setting is. You select the top level item in the groups and file view, which represents the project. And then you need to configure the instance. And then use the project show info menu.

All right, so now we've talked about how to build, where to build. Let's talk about what gets built.

[Transcript missing]

Executables hold the persistent state that you set of the program, kind of the environment of the program. Because commonly when you're debugging, you want to run it multiple times, and it's convenient to set up command line arguments and environment variables that can control how your programs run.

Another aspect of executables is you can set at runtime which variant of the Apple standard system libraries or system frameworks, which variant is used. The standard variant, which all apps that are launched from Finder use, has minimal symbol information, a high level of optimization. The debugger is a very simple application.

The debug variant can do additional error checking. It can do consistency checking within the library to try to tell you of problems before they arise. And, for example, core foundation provides a lot of verbose output and error checking that might be useful. And finally, there's a profile variant for use with the Gprof profiling system.

Here's a screenshot just to get you oriented on the executable setting. You can see on the left we've selected a target and then gone to the executables tab. There's the add button for adding an external executable and I've highlighted the run tab, run time tab to show you how to change the library variant.

Okay, now just a quick note about breakpoints. We have two kinds of breakpoints in Project Builder. File-oriented breakpoints that you set when you're editing or looking at source code, you can click to the left of the source code and set a breakpoint at a particular line in the file.

And symbolic breakpoints, where you enter the name of a function that you want the debugger to stop at when that function is first executed. And this is a good way of working, stopping in functions for which you don't have the source code. All right, now I'm going to give you a quick demo of debugging. Let's see.

I'm going to demonstrate debugging a plugin. This is a palette that goes into Interface Builder. That's what Interface Builder calls its plugins. This palette is an example in the Developer Examples Interface Builder Progress View palette. It's a UI control for representing a progress view. Just a little demonstration of how to write a palette for IB. Let's do a quick tour of Project Builder as to what's related to debugging.

Up here we have the debug tab. Contains the output of the previous run so you can Refer to it later. This is a pop-up for the list of threads. We're not running anything. Stack frames and variables. Here are the control buttons that get enabled when we're actually running.

And we have a A breakpoint summary tab to show you all the breakpoints in your project. And let's add-- A new symbolic breakpoint. So you click there and you need to enter the name of the function. For Objective-C programmers, it's sometimes handy to break on NSExceptionRays so you know if an exception gets raised inside your program.

And let's see, go back. All right. Let me show you one thing. We have done a few changes in the user interface. We've added a second little tab up here for the output of the running program's standard input and output. And that appears up here. If you're working at the command line tool level and you want to type something at your program while you're running, you would bring this down and type in there. And we've added a few preferences to let you set the fonts and font color for everything. And due to popular demand, you can set the color of the highlighting of the current line. So I'll change that to a nice shade of blue or something.

And before we start running this program, let's look at its target, which builds-- this is a plug-in. One of the problems you'll have working with plugins is you build them in Project Builder, and now the program you want to run looks for plugins in specific locations. How do you get your plugin into that location? Well, there are two approaches.

A kind of Unix low-level kind of hacky approach that works very well is you go to the directory or the folder where the plugin or where the containing application expects to find your plugin, and you use a symbolic link to point back to your build directory and your built plugin. Another approach is to use... I've just... I've taken a standard set of build phases that builds our plugin and added a shell script build phase that copies our built plugin into the directory where, in this case, Interface Builder will be looking for it.

How do you get your plugin into the directory? On the build settings for the compiler, we've set optimization level one. We'll see what that does. And right now, you'll notice that the run and debug icons are not highlighted. That's because we don't have an executable. So I'm going to add in-- crawl around and add in Developer Applications Interface Builder.

And now our icons are highlighted. I'm going to add an environment variable. It's called doLogin. And this is a good way to take your code. When you're doing development, you want it to be a little more verbose, tell you what's going on. So I've put in an environment variable that will cause this example to do a little logging, generate some status information.

So let's see, we've got a break point, so let's start up the debugger. and give Interface Builder a minute to start up. It's got to find all its plugins on the system. It comes up, we'll create just an empty window. Drag in our little progress view control. And now when I click on this inner region where the actual progress indicator will be drawn, see over here this inspector has come up tailored towards that.

This means that this is our plug-in running now, putting up its own custom inspector. So if I type in some code to change the increment, we hit a breakpoint. Now we're in our code executing in the context of this plug-in, or in the context of another application. Let's see.

As we step along, you can see that in this case we assigned a value to F. And as variables change their values, they show up in red. We'll step over this. You can see we're asking the environment, do we have this environment variable? Yes, we do, because we're doing development. We'll step along that.

And we can see that MSG, our message we're going to print out, has been assigned. The folks at O'Reilly say they've sold out of all the Cocoa, learning Cocoa books. So if you're new to Cocoa with respect to debugging, you need to know that many Cocoa objects are opaque.

If you inspect them in the view here, you maybe see just-- That fact that it has an is a pointer, that's a pointer to a class, but that's all you can see. So how do you determine what your Cocoa object is? Well, we can use the power of GDB to send a message to this object, ask it to generate a string description of what it is, and then convert that description to something that can be displayed in GDB. So we use the print object command, or PO, the name of the object, and that's actually invoking code in the inferior, running that code, and returning that into GDB, into our console here.

And fortunately we have the string we've just set up here, current increment is five. All right. So we step along, we call NSLog, the output of the log, which is going to do the, in this case, NSLog, and then we call NSLog. So we have the interface builder, standard out, or standard error, shows up in our log. We've set it up to have a different font. are different color that can be useful. Let's step along. And now I just want to show you a few things about debugging optimized code.

here. You can see that we've just assigned a value to an inter -- a variable called f at an interscope -- a nested scope level. We have -- we can show variables with the same name at different scope levels. And you can also notice that this obj, which was a parameter into this function, changed too. Well that's because the optimizer was reusing that register.

If you look carefully at the code, you can see we declare both an F and an I at the outermost scope. But when we look in the variable view, we see there's only one I, and that would correspond to this if block. And that's because the outermost scope, the I at the outermost scope has been optimized out.

So, Let's see. I think, yeah, we've got a full day, so I'm going to stop here. I hope you've got a quick introduction to Project Builder and debugging with it, working with optimized code and plugins. And now-- Let's see if I point it right. I'd like to bring up Dave Ewing to talk about Java debugging.

Thanks, Rab. All right. Okay, well, you actually just saw most of the debugging features in the Java debugger and Project Builder 2 because they are the same. The user interface is the same. It's shared between the two. So I'm going to go through just some differences, some things you have to do differently when you're debugging in Java.

So the first thing, well, the three things I'm going to show in my slides before I do a little demo are setting up a project to debug in Java and what you need to do that's special about that. What you need to do to set up the application and its command line arguments, and a little bit about Java exceptions.

Java has a very nice exception model where there's a class, Java lang throwable, and every exception that you can throw has to be a subclass of that. So it actually is a very nice Very nice way to program. So setting up your project for debugging. The one thing you really want to do For Java debugging, is turn on the indexer. In future versions, we'll have that turned on by default.

But besides giving browser information-- we have a class browser coming in the next version-- right now you can command double click to go between symbols, and you get function pop-ups and things like that. So besides getting that when you turn on indexing, you actually get build dependency support for Java builds. And you also get a few enhancements to the debugger support.

So one thing you may not know about class files and what's produced when you compile a Java source file is that there's a source file name in there in the debugger tables that you need for the debugger. But there's not a full path. You don't know exactly what source file that might be on the disk. And Project Builder can try real hard to figure out which source file you mean, but if you have two files with the same base file name, it can't be sure.

If you have indexing on, we can be sure. And the other thing you get if indexing is on and you have breakpoints set is your debugging speed will be vastly improved. It's about 20 to 30% faster on a small project and it only gets better for larger projects.

Okay, Java executables. You can create a standard Mac OS X application. If you do that, one of the files in your project is an mrjapp.properties file. And inside that file, there's a main class setting. And that is the, it's really the name of the class that gets run. So you, you know, when you create a new project, there's a default name there, but you actually may be adding sources and want to change what that is.

There's also the class path, which jar files get loaded. Command line arguments actually go into that file as well. For Java tools, tools that are meant to be run from the command line, you basically give it standard command line arguments that you would give to the Java executable in Java being user bin Java.

If you actually have a manifest file in your project, which contains a main class entry, then you would give -jar and then the name of the jar file on the command line. And if you don't have a manifest file, then you would just give the class path for your jar file and the name of the main class on the command line.

OK, so our debugger does a few things to handle Java exceptions nicely. It's not all the way there. We have some UI that we want to wrap around some of this. But by default, we stop when there's an exception thrown that is not caught in your code somewhere. Now that's really cool.

But it turns out that sometimes there's code out there that catches these exceptions that the debugger can't detect. If there's Java native code, meaning like code written in C, they can actually catch exceptions, and the debugger has no way to determine that ahead of time. So you actually might stop in a few places that are a bit of a surprise. So this last point here, there's a console just like a GDB console. In our debugger inside Project Builder. And there's a few commands that help you take care of exceptions when you're debugging. And with that, let's show a few features that are specific to Java.

Oh, what a nice screensaver we have. OK, so when I was trying to come up with a demo here, I actually had this really teeny little demo. And I was thinking, that's kind of boring. I need to do something flashy. So I went out and was looking for a quick time for Java demo. And I couldn't really find anything. All of them have little teeny pictures and kind of boring. So instead of doing something flashy, I'm going to do something geeky.

So here I have a little project that uses the Antler parser generator to parse Java source files. And I don't really want to get too much into how a parser works. I mean, this is a debugging session, not a parser session. But it's a cool little program. We have a main class here that basically just takes some command line arguments. At the bottom, there's a routine called-- oh.

Some of these are somewhere near the bottom called parse file that creates a lexer which tokenizes the source file and creates a parser which then actually does the parsing. And then we have this other routine do tree action which actually creates a swing tree view to look at what the parser parsed. So let's take a quick look at the target for this project.

You can see it compiles a bunch of Java source files, no big deal. In the executable setting, it runs the Java command line tool. And the arguments, it passes the class path pointing to the jar file that's built by this project. And -show tree is what causes this particular program to build the swing tree. And then I actually have two more arguments over there. That are source files to parse. It's actually parsing the main class file for this demo.

So let's just run that so you can see what it's doing. Comes up reasonably quickly. At the top level, this is basically the root of the file. There's nine import statements here. There's a class declaration, Java parser demo. Inside that, there's a variable and four methods. OK, now I've set a breakpoint. Let's just go ahead and debug.

And we hit the breakpoint here. Now it turns out one of the cool things about this parser, the handler parser, is that when it's looking ahead and it sees something that's confused, it actually throws exceptions back to a, and those exceptions are caught in a method which can handle the errors. So in order to see where it might be throwing exceptions, We want to turn on the catching of exceptions, so catch all, and we'll continue.

We stopped pretty quickly. We actually stopped in system class loader code. In this case, this is a case where it's actually catching the exceptions in Java code, and we can continue on and see it's just going to keep catching exceptions, catching exceptions. So let's turn that off for a moment.

Not much of a typer, I'm afraid. And let's go on. We should get to the break point here in a second. So one of the things it's doing right now is it's debugging very slowly. And that's something that's actually fixed in the Java patch that should be live today. It uses the 131 VM while you're debugging.

So that speeds things up a lot. I actually wanted to get that on here, but we were having other problems configuring these systems. So I didn't bother to get it there. OK, so we hit the break point. And let's turn on the catching of exceptions now. So I've run through this twice.

The first time it went and parsed this file, there were all those class load exceptions. And we didn't want to see that. So the second time I hit this break point, all those classes are loaded. So we're not going to hit exceptions for that anymore. So I can turn on-- just use the up arrow-- turn on exceptions again.

And just a moment here. OK, we caught an exception in the routine antler.poster.match. If we look up the stack, we can see we're actually trying to match an identifier on the input. The one thing you'll notice about this is that there's no source code down below. The PC's not showing up there, and that's sort of irritating. Well, it turns out I have another project file that has the Antler source code in it, so let me open that up.

Just need to open it up, don't have to do anything with it. Now if I click on that line, it goes to the code in the other project. This is not a feature that's specific to the Java debugger. I just wanted to sneak that in because it's actually one of the cooler things about our debugging system. And you know what, that's actually about all I have here.

All the other standard stuff in the debugger is pretty much the same. You can actually set variables in this version of the debugger for Java. That's coming in the next version for the GDB debugger. But that's it. And with that, we can switch back over to the slides. I actually have the clicker here. I want to bring up Jim Ingham and Klee Dienes. And they're going to talk about the gory details of debugging with GDB. Thanks, .

Well, that's fast fingers Klee over there. I'm Jim. So we're going to tell you something about GDB, which is the underlying debugger that both MetroWorks and Project Builder use to run and control applications under debugging on Mac OS X. First of all, a couple of words. They said something about this in the MetroWorks session, too, and it got some applause, so Our goals for Project Builder are that if you are a GUI type debugger person, you're used to MetroWorks, things like that, we're not going to make anything that you need to do as a user of debugging require the GDB command line. You'll always be able to get useful features from the Project Builder just straightforwardly.

But the other thing is that GDB is actually a pretty powerful environment and there are some things which using GDB you can actually get a lot of leverage of its capabilities. So we also want to make it possible if you're a GDB user that you can live in the Project Builder environment, get advantages of locating sources and stuff like that, and still be able to use the nice features in GDB that if you've come accustomed to them, you love them or you might learn to love them at some point.

We're not all the way there yet. There are some things in the project that we're going to be able to do that are going to be useful. So we're going to be able to do that. There are some things in the GDB console window that don't work the way they do in the terminal, which is why in our demo we're actually going to be using terminal, but we'll get there.

So why would you want to use GDB as opposed to Project Builder or in the context of Project Builder? It's actually a very good low-level debugger. It knows everything about your application. It's been hacked on by people for years and years, both in the embedded environment and in the Unix environment. So there are a lot of features for locating.

Learning about your program, poking around, and various things like that. It's the low-level debugger that everybody uses, so the features that are going to be in Project Builder will already be in GDB most likely. So if there's something we haven't gotten around to yet in Project Builder, it'll probably be available in GDB. So just if you need something that we haven't gotten around to yet.

It's also scriptable, so if there are sort of actions that you want to attach to things that happen, in the course of your debugging, you can do that within the GDB command language, which is a really nice feature. And finally, it's extensible, so if you have some special purpose things that you want to do, and we'll show an example of that a little later on, it's possible to extend the GDB debugger to do those things for you.

It's an open source debugger, so the extensions, you just get the source. We have a plug-in architecture, and you can make commands, but also the source is available to you. You can look at it, see everything that's going on, and so on. So the first thing is sort of what kind of things at this stage are there, which we haven't yet gotten into PB, which you might want to use GDB for. We'll give you three examples of that. One is remote debugging, which we certainly intend to get PB able to do, but it doesn't do yet.

The other is debugging PEPF binaries, which in all likelihood won't make it into PB, but we'll see. And then the third is kernel debugging, another thing that we'd like to do in Project Builder, but that's going to take more work because just the setup for kernel debugging is a little bit grody. So first of all, remote debugging. This is where you have the, you're running the, controlling the debugger on one machine. You're actually running the debugger and the application on another machine. We don't have the situation like MetroWorks where they have a little nub.

But in any case, the point is that you are not typing, you're not switching the debugger into the foreground or anything like that while you're running the application. So this is good for full screen applications like games or situations where you're trying to debug, kind of mouse tracking and stuff like that, where having the debugger come to the foreground is obviously not going to help you figure out what's going on. So the way that you do this is that you would start the application on the remote machine, and you have to do that.

You can't actually start an application remotely if it connects to the Windows server because the Windows server doesn't allow you to do that from Telnet or SSH. So you have to go to the machine that's going to run the application, start it up, and then you go to the machine you're going to be debugging from, and you Telnet into the machine, running the application using Telnet, SSH, whatever your favorite thing is.

And then you use GDB's attach command. So the way that that works is you say attach, and then you can give the PID, the process ID of your application, which you can find through top or whatever. But actually we've made it a little more convenient than that. If you type the application name of your application and then hit tab, it'll actually go and look at the process list, find your process for you, and fill it in. If there's more than one process of the same name, it'll offer you the choice of, and you can figure out which process it is.

Again, processes are listed sequentially, so if it was launched, the latest launch one is going to have the highest PID, so you can kind of figure it out that way. And as I say, we have a few more infrastructure things that we have to do in GDB to make this available in Project Builder, but it'll be available in Project Builder in the future.

So the other thing is using GDB with CarbonPath. So, you know, Maco is the preferred format for Mac OS X. That's the one that our tools will support fully and enthusiastically. But there are some cases where, you know, if you're debugging a CarbonPath application, you might want to get some features which aren't available in Code Warrior.

For instance, up until Code Warrior 7, it didn't know about Maco binary. So if you wanted to set a breakpoint in a function in Maco binary that was called on your behalf, and it wasn't, you know, exported to path through one of these vector libs, then the only way to do that was to run your application under GDB instead and set the breakpoint there. So that's kind of the main use for it. I haven't actually played with the new Code Warrior yet, so I don't know how easy that is to do in Code Warrior.

Maybe you can do that fine, and this is irrelevant. But also it's nice because, you know, you can connect remotely if that's important to you and other such things. So the way that you do that is, first, as Robert said, if you want to use really complex applications, like, say, any of the Apple tools with CarbonPath binaries, then you should build with inline traceback tables in Code Warrior, because that records information about the functions such that the debuggers and all the other performance tools can find the names of your functions.

And then the next thing is that the loader itself is not the thing--the application loader on Mac OS X doesn't actually load CarbonPath binaries. It's actually an application, a Maco application. Which is responsible for loading the CarbonPath binary. So that's this thing called LaunchCFMApp. That's the thing that you have to run GDB on.

And I say long path because if I actually typed it out on the screen, it would actually fill this whole slide. But if you look at the little URL, it's in the URL, so just cut it and paste it. And then when you run, the way that the LaunchCFM application works is that it takes as its first argument the name of the CarbonPath application that you are running. are actually attempting to run. So in GDB, you say run and then you give it the name of the application that you want to run. And as I say, there's much more details about this in this tips and tricks URL.

So then the other place where you need to use GDB and Project Builder doesn't support this yet is kernel extension debugging. This is a two machine debugging situation. In this case, GDB runs on the machine that you're sitting on because of course you're debugging the kernel and GDB is a user space program, so it's really not going to be able to run on the machine. The two machines talk to one another through a protocol called the KDP protocol.

You don't need to worry too much about that. The only thing is kind of conceptually what's going on is that the kernel has a little agent that lives in the kernel and GDB connects to that agent and talks to it with some protocol and that's how the GDB sitting on your desktop machine is able to control the kernel that you're connecting to. The only restriction is that the two machines have to be on the same subnet to connect.

When you're running the kernel under GDB, it's just like you're running any other program. There's nothing particularly special going on. You can do backtraces, you can control execution. Everything works just like GDB running on a normal application and it's kind of hidden to you that you're talking across this protocol.

The only thing to keep in mind though is that you are talking to a little agent that's living in the kernel, so if you do something really heinous to the kernel in the course of your running your kernel extension or whatever and that causes the kernel to lock up, then you could very likely kill the little agent and then GDB is just dead because it has nothing to talk to anymore. What you'll see is it will start reporting timeouts talking to the kernel agent and that means that you've completely hosed the machine and you'll have to reset. Sorry. And then there's much more information about this in the tutorial.

Okay, so now we're going to just show you a few of the neato reasons why you might want to use GDB, even if you have a nice, fancy IDE to control sort of the more common aspects of debugging, like inspecting variables and stuff. So there are a few features that we'll talk about. One is the expression evaluator. We'll talk about how you can have commands which fire when breakpoints are hit.

We'll talk about how to set up conditional breakpoints so that you can have breakpoints only hit when certain things happen. You can take a bunch of actions and can them up into your own user-defined commands to extend the GDB language. And finally, if you're really ambitious, you can write your own extensions to GDB and see and load them in. For all of this, the GDB manual is in the developer package.

It's in developer documentation, developer tools, and it's a pretty nice manual. It gives you, you know, tells you about all the GDB commands, has some nice examples, things you might like to do. So if you get interested in this, that's a good place to go for information. So now, Klee is going to, this is Klee Dinas. He's my cohort in GDB things. He's going to show you some cool GDB stuff.

So the first thing is the expression evaluator. Basically, you can call any function that's in your target from GDB. And you just use the syntax of the language that's involved. So we'll use the appearance sample, our favorite little demo. And in this case, what we're going to do is call the print functions that are in Carbon, which help you get access to all of the opaque stuff that you're not supposed to look at anymore. So first of all, there are a bunch of print functions. I can never remember the names of things. And I refuse to remember the names of things if I can remember how to find them.

So it's actually info function. So there's a gdb command info function. You give it a regular expression. Don't worry about that. And just copy this down. And it'll tell you everything that's there. So there's all the lovely debug print functions you can poke around and use any of them. Let's print the window list. See what's there. Nothing yet.

So if we step one step, or next-- OK, now we've created a window. So if we look at the window list this time, hey, there's a window. And so then we can look up and then, hey, there's a debug print window. So let's see about that one. So we're going to call debug print window.

The first entry is the actual window token. And since it's hex, we have to tell gdb it's hex. So there's all your information about the window. A couple of other things to remember is that the functions that you call do change target state. None of these debug functions do, obviously, unless the guys in the Carbon are pulling some kind of joke on you.

But in general, a function will run in your program, which may be good. You may actually want to change target state. But if you call a function that crashes, you'll crash your program. Also, you can call these functions anywhere you use a gdb expression. So you can set variables to the value of a function called and so on and so forth. So the next thing which is really useful is breakpoint commands. We're going to give a silly little example here where you might want to use it. Although for this, there are other tools like ObjectAlloc that probably do a better job of it.

But you've got a problem with retains and releases with CF, with core foundations. Somebody is over-releasing something, and your program is crashing. And what you'd really like to do is know all the times that an object gets retained and all the times that it gets released, some of these are not under your control because they're called on your behalf by various other CF functions.

So you need some other way to get when that actually occurs. So what we're going to do is we're going to run-- we built this little string example. And if you notice, there's a bug that we've got to release the str1 twice. That's down at the bottom. That's the bug.

So what we want to do is we want to break on the CF retain, break on CF release every time it occurs. And then when that occurs, we'd like to print out a little information for ourselves so that we don't have to go grub around every time. To do that, you set a command. So you say commands. And then if you don't give an argument, it's the last breakpoint you set is the one that the commands register for. You can also give a breakpoint number. In this case, what we're doing is we're, again, calling inferior functions on our behalf.

We're getting the retain count. The little trick is that the arguments that are passed to a function in the PowerPC ABI are stored sequentially starting in register 3, register 4, 5, and so on. So since we know that the CF retain takes one argument, which is the thing that you're retaining, that's got to be in R3. So we say CF get retain count of $R3. That's just the argument that's passed to CF retain. And then we're going to print some information about what's going on there. And we're going to print the backtrace.

So Klee is also-- because he doesn't want to have to type all this stuff in-- he's using the source command in GDB. He put this stuff in a file and is just using the source command to bring that file of GDB commands in. So it made a couple breakpoints. So this is cool. Now every time he continues, we hit a CF retain, CF release call.

We print a little information, and we can step through code this way, sort of automatically printing out the stuff that's interesting to us. But if you were in a big program, and this was going to happen hundreds of times, you probably wouldn't want to step through each time, because that would get really old very quickly.

What you might want to do is sort of do an on the fly logging facility instead, to log all the calls to retain and release. So you can do that also. You can just put a continue command in your breakpoint command, and that says, hit this breakpoint, do a little bit of logging, print out some stuff, and then keep running.

I have a little log of all our cf.retains and releases. This also is a little bit overkill because, I mean, you know, there might be hundreds of these. This is going to just totally swamp the screen. It would be nice if you could be a little more discriminating about what you are watching.

So that's the point of conditional break points. You can tell GDB to stop only when certain conditions are true. The conditions can be basically any expression which is valid in the language that you stop at when you hit that break point. And the condition gets re-evaluated every time you hit the break point.

So you can basically write some C code, whatever you want, and GDB will evaluate that C code and then either stop or not based on whether it's true or false. So in this case, what we're going to do is, again, we have a suspicion that it's str1 that's the bad guy.

So we want to only watch retains and releases of str1. Remember, since the condition is getting evaluated every time the break points hit, str1 is no longer in scope. So we have to actually store away str1 so we can use it later on. And GDB allows you to use convenience variables. Any variable that begins with a dollar sign is actually a variable that GDB stashes away on your behalf.

So we're storing str1 when we first create it in this watch variable, and then we do the regular stuff. We make our break. And we actually are also including the command in the file he's going to source in. And then finally, we set a condition on this break point. $bpnum is another of these magical convenience variables.

It's just the number of the last break point that was set. So if you want to store away a break point number for later use in your commands, you use the bpnum variable. And we're going to break when $r3, again, the argument to the cf retain is equal to this watch variable that we've stored away. So-- So that's cool, nothing printed.

Now we only see the ones for the token that we were interested in. And finally, this would get really old to type after a while and also, you know, notice that he was able to call a start watch, stop watch to actually watch just one particular thing. If you were going to do this over and over again, it would be nice to can the set of operations that did the watching and then just reuse them over and over again.

For that, you can use what are called user-defined commands in GDB. The syntax, this is not a particularly useful example, this is just to show the syntax, is you say define and then you give any name of the command that you want. If you name it the same as the GDB command, you'll override the GDB command which may or may not be what you want, probably not. And then you give any valid GDB commands and finally the end statement.

So the more complicated one that we're using is actually over on the screen there, the start watching command. The other thing about the GDB define commands, you can actually pass it on to the user. You can pass arguments to them and they are stored in convenience variables, $arg0, $arg1, and so on and so forth.

So we want to say start watching in the string we're interested in watching and that gets stored into this watch variable. And then we've set the breakpoints up in advance so they're just sitting around for us. Our start watching command just enables those breakpoints so you can enable and disable breakpoints in GDB just like you can in Project Builder. And finally we set the conditions on those breakpoints. And then we, for convenience, defined a stop watching command. You can say, okay, I'm not interested in watching those things anymore. You just type stop watching and you're done.

That's convenient. Yeah, that's this. So we define these two commands, start watching and stop watching. And finally, you can put all this in a file, and then there's a GDB source command. You can just say source and give a file name, and all these commands will be sourced into GDB. They'll be available to you. So if you have a bunch of special purpose tasks that you do in GDB, you can make a whole directory full of useful little files and source them in as you need them, and you don't actually have to type stuff.

So the last feature is this allows you to do things in the GDB command language. The one thing to be a little bit aware of is that GDB's command language is not designed to be a high-performance interpreter by any means. So if you're doing something really, really complicated, it's probably going to get slow on you.

And at that point, you might think about whether you wanted to write an extension to GDB in C, C++, Objective-C. I mean, the nice thing is you get access to all of GDB's internal functionality. On the other hand, GDB has a lot of internal functionality, not all of which is terribly well-documented, so there's a fairly high learning curve.

But if you have a job to do, you got a job to do. You know, this might help you. The other thing to keep in mind is that GDB is under the GPL. It's an open-source piece of software. So if you are thinking about writing GDB plug-ins which you want to make commercial things, then realize that they're going to have to be distributed under the GPL. So the GPL license as well.

If you want to just use it for in-house, it doesn't matter. The GPL allows you to do whatever you want for in-house use and only restricts what you do if you're trying to sell or distribute commercially or whatever your software. They're faster and they have much more capability, much more flexible than GDB.

So here's our example. You know, the guys at--various people at Apple have MaxBugs wired into their mental processes and their fingers just type MaxBugs commands. And so the people who were using GDB, a bunch of the guys in our group just couldn't type the GDB commands. They needed the MaxBug commands. They needed MaxBug.

They needed it. So one of them actually went to the trouble of-- Making MaxBug. So it's got the complete MaxBug command sets. It updates properly. It has all the instruction listing and everything that you've come to love. It's got a nice little help so you can figure out what they all are.

Actually been a lifesaver for some of the people here. The one thing about it is that it's in this user lib exec GDB plugins max bug, and you just source that file in. In the version that's on both GM and the CDs, there was a bug in the file that you source in. A path was set to be wrong. So you just need to go change that if you want to use this.

And there's a tech note on the developer website. Please, typing in the address now. That tells you what you need to do. But actually, if you fire it up once, it'll say, can't find this file. And you'll look, and there's bogus stuff in the file, obviously. So it's pretty easy to fix. OK. And with that, I'll bring Dave back up to tell us the last little bits about debugging on Mac OS X.

Okay, so we've seen quite a lot of different powerful features here today. If you've been to WWDCs the past couple of years, you've seen me standing up here saying we're committed to delivering great developer tools. It's fun this year to actually be up here saying, well, you've got them now. And you've seen a lot of power here under the covers that there's a lot more we can do in terms of extending what we've got in Project Builder.

What we've got there today is very powerful for C-based language debugging, for Java debugging. But a lot of this capability of GDB, we just need to provide more user interface to it, and we can bring some of this more out into the Project Builder UI as well. So there's a lot of additional improvements that we plan to make in the product for debugging and across Project Builder as a whole. A lot of what we do is guided by the feedback that we get. All of my team monitors what's going on on the projectbuilder-users email list.

That's the best way to broadly communicate with us. And the entire rest of the community. If there's just feedback you want to send directly to us, actually I should move on to the lists here. There's ways to do that as well. So let me actually bring Godfrey back on stage.

I was going to yank his chain this morning and have him introduced under the wrong name like we had done on Tuesday as well. My new name is Jonathan. Jonathan DiGiorgi. Here we are. Well, thank you very much. It's very good to see such a large crowd here on a Friday morning. Pointing to the information resources page, you have the clicker. I have the clicker.

The first is our master page for all Mac OS X tools. We try to put everything up there. We have a number of additions to make, both third-party and internal, and we continually develop it. We put the latest things on each of the pages for each specific technology. Below that, we have Apple's master mailing list page and the Project Builder users page. What do we have now, almost 1,000 users? I keep waiting. We were at like 944 last night. Come on, give me over 1,000 here. So go sign up. We're reaching here.

Roadmap. We have a feedback forum for all the developer tools this afternoon at 3:30 in room J1. Not on the roadmap, but other important sessions that are still technically part of the tools track. Right after this session in A2, we have the Darwin Documentation Project and Head of Doc.

And also at 2 o'clock, we have the Apple C++ Framework session, which talks about the Apple Class Suites and Mac App. For those people interested in those areas, those are going to be very good sessions. And my contact information, if you have any questions, any interests, any needs in tools, you can always contact me at [email protected]. And we have the Mac OS X Tools Feedback Mailing List, which actually distributes an incoming email to all of the engineering team. So if you have feature enhancements, ideas, we love to hear this stuff. We really want your feedback.

So that's a great address if you don't necessarily want to send it to the whole community, but just the 30 or so of us on that list. The Interface Builder folks are on there as well. And I know everybody to distribute other requests to on that. And also, send bug reports in as well. That's how we actually fully keep track of everything.