442 ❘ CHAPTER 18 DEBUGGING The debugger window includes an editing pane, so everything you can do in an editing pane can also be done in the debugger window. In addition, the debugger window provides: A structured list of all in - scope variables The CPU registers Access to global variables Advanced data inspectors A stack frame list Thread selection The debugger window is where you turn if you want to explore other stack frames, switch to another thread, want to see a list of all variables in scope simultaneously, see global variables, want to examine variables in more detail, or want to modify variables. The third interface is the mini - debugger. It ’ s a minimal debugging interface designed for use with full - screen applications and other situations where getting to the debugger window is awkward or inconvenient. The mini - debugger is described in later sections. You can see where you can debug from almost anywhere in the Xcode interface, but you can also debug your application anytime; you can launch your application normally and then later decide that you want to debug it; Xcode will interrupt the process, attach its debugger, and hand over control to you. In fact, that ’ s really the primary reason for the Run ➪ Run - Breakpoints Off (Option+ Command+R) command. After starting your application, all you have to do is create, enable, or reactivate (Run ➪ Activate Breakpoints) a breakpoint; Xcode will invoke the debugger, have it attach itself to your running executable (if needed), set the requested breakpoints, and let the debugger take over — just as if you had started your application under the control of the debugger in the fi rst place. In Mac OS X 10.6 (Snow Leopard), Xcode keeps the GDB debugging running all the time, so it ’ s even more responsive. Before any serious debugging can take place, you must fi rst prepare your project for debugging. BUILT TO BE DEBUGGED The take - home message of this section is this: Before debugging, profi ling, or analyzing your code, you must fi rst build it using the Debug build confi guration. It ’ s an essential requirement for doing any kind of debugging or analysis. If you ’ re in a hurry, switch your active build confi guration to Debug and skip to the next section. If you ’ re interested in knowing why, keep reading. How you build your application affects its ability to be debugged. The quintessential quality of a modern programming language is that it allows a developer to express procedures symbolically, letting the compiler deal with the ugly details of how to accomplish those procedures in machine code. Listing 18 - 1 shows just how obtuse the machine code for a few “ simple ” lines of programming source can be. The source code is shown in the listing, followed by the resulting Intel machine code. ➤ ➤ ➤ ➤ ➤ ➤ ➤ c18.indd 442c18.indd 442 1/22/10 12:54:08 PM1/22/10 12:54:08 PM Download at getcoolebook.com The debugger has the unenviable job of reversing this process — it must examine the raw machine code and translate that back into something that corresponds to the functions, methods, code blocks, classes, structures, and variable names defi ned in your source code. (You see this process at work later in Figure 18 - 6.) LISTING 18 - 1: Compiled source code SOURCE CODE - (void)dealloc { free(byteArray); [super dealloc]; } COMPILED ASSEMBLY CODE pushl %ebp movl %esp, %ebp pushl %ebx subl $36, %esp movl 8(%ebp), %ebx movl 4(%ebx), %eax movl %eax, (%esp) call _free movl %ebx, -16(%ebp) movl L_OBJC_CLASS_SieveOfEratosthenes+4, %eax movl %eax, -12(%ebp) leal -16(%ebp), %edx movl L_OBJC_SELECTOR_REFERENCES_2, %eax movl %eax, 4(%esp) movl %edx, (%esp) call _objc_msgSendSuper addl $36, %esp popl %ebx leave ret To accomplish this feat, the debugger needs a lot of help. That help comes in the form of debugger symbols produced by the compiler. Debugger symbols are a kind of massive cross - index. They contain information like “ the machine instruction at byte offset 12,738 corresponds to line 83 of the source fi le breakme.c. ” If you set a breakpoint at line 83 of breakme.c , the debugger knows it needs to stop your program at the instruction found at offset 12,738. If your program crashes at (or near) the machine instruction at offset 12,738, the debugger can tell you that your program crashed at (or near) line 83 of breakme.c . The debugger symbols contain similar information about data structures, classes, automatic variables, and so on. You must request that these debugger symbols be produced when your application is compiled. If you have created your project using one of the Xcode templates, you should have a Release and a Debug build confi guration. The Debug build confi guration, shown in Figure 18 - 5, for your program ’ s target has the following build settings: Generate Debug Symbols: On Debug Information Format: DWARF with dSYM File ➤ ➤ Built to be Debugged ❘ 443 c18.indd 443c18.indd 443 1/22/10 12:54:09 PM1/22/10 12:54:09 PM Download at getcoolebook.com 444 ❘ CHAPTER 18 DEBUGGING Optimization Level: None Fix & Continue: Off ➤ ➤ FIGURE 18-5 Generate Debug Symbols enables the full array of debugger symbols in the compiler, detailing every aspect of your code for the debugger. Without it, the debugger is next to useless. This information is produced when each source fi le is compiled, it takes a little extra time to compile, and produces a lot of data — quite often more data than your actual program — which the debugger has to load. All of this slows down both compilation and launch time. If you are debugging a massive amount of code, you may elect to generate debug symbols only for some modules and not others. For example, you may generate debugger symbols for your main application code but not some well - tested library routines. This speeds up building and debugging, but limits your debugging to the portion of your code that has debugger symbols. The Debug Information Format defi nes which fi le format to use to write the debugging information. DWARF with dSYM File is the modern format and should be your fi rst choice. DWARF and Stabs are older formats that embed the debugging information in the executable. If you ’ re using the modern DWARF with dSYM File debug symbols format, the legacy build settings Strip Linked Product and Strip Debug Symbols During Copy are largely superfl uous. Legacy debugging symbols were stored in the executable fi les themselves, and later stripped off during the deployment phase of your Release build confi guration. The modern dSYM fi le writes the debugging information to a separate symbol fi le, so the executable is essentially already “ stripped ” of its debug information. If you ’ re developing a legacy application created with an earlier version of Xcode, update your debug format to DWARF with dSYM File and make sure the Strip Debug Symbols During Copy build setting is set to NO. Leaving Strip Debug Symbols During Copy on will interfere with code signing, which is critical to iPhone and modern Mac OS X applications. c18.indd 444c18.indd 444 1/22/10 12:54:10 PM1/22/10 12:54:10 PM Download at getcoolebook.com While you ’ re debugging, the optimization of your code should be set to None. The reason why goes back to how debuggers work. Optimization, by its very nature, is logic in the compiler that reorganizes, reorders, rewrites, and often eliminates code that it fi nds to be ineffi cient or redundant. Take the following code fragment as an example: Line 100: int i=0; Line 101: for (i=1; i < argc; i++) With optimization turned on, the compiler eliminates the statement i=0 because the result of that assignment is never used. In the debugger, it now becomes impossible to set a breakpoint at line 100 because the code that corresponds to that line of source code doesn ’ t exist in your compiled application. More advanced optimization techniques, such as loop unrolling or instruction reordering, can produce even more bizarre aberrations, such as programs whose statements execute out of order (for example, line 101, then 103, then 102). It might be impossible to stop an application at a certain point in your source code, or step through your code one line at a time. Skeptical readers are invited to enable full optimization and then attempt to debug their application. Fix & Continue is a feature, covered later in “ The Magic Fix, ” that allows you to make limited code changes in your application while your application is running. That is, you don ’ t have to stop your program, change your code, rebuild, and restart. You simply change your code and keep executing. To use this feature, your compiled object code must contain additional information that the Fix & Continue feature needs. If you leave this build setting off, you can still debug your code, but the Fix & Continue feature is disabled. The Release build confi guration for new projects has the opposite build settings: no debug symbols, symbols stripped, normal optimization, and no Fix & Continue. If you have created your own targets or build confi gurations, you ’ ll need to set them up accordingly. Note that Xcode project templates defi ne many of these settings in the target ’ s build settings. If you have a multiple target project, you can easily misconfi gure the settings in one target and not realize it. Or, you can set them in the project build settings, where they will be promptly ignored. For these reasons, I recommend moving these basic debug settings into the project build settings level for multi - target projects, and then override these settings only in those targets that require something different (which is rare). This way, you can adjust the level of debugger symbols produced (for example) with a single build setting, rather than having to change this setting in every target. TIP TO REMEMBER If you think you ’ re having problems getting your build settings right, create a temporary build confi guration to experiment with. After you have everything working, you can compare that to the original, or just delete the one that doesn ’ t work. If you ’ ve made a lot of changes and really want to know what the differences are, export all of your build settings by copying and pasting them into two separate text fi les. You can then compare them visually or using a diff tool. Built to be Debugged ❘ 445 c18.indd 445c18.indd 445 1/22/10 12:54:16 PM1/22/10 12:54:16 PM Download at getcoolebook.com 446 ❘ CHAPTER 18 DEBUGGING DEBUGGING EXECUTABLES With the preliminaries out of the way, you ’ re ready to debug your application. Getting started is as easy as running your program. Choose any of these commands to start your application under the control of the debugger: Build ➪ Build and Debug (Command+Return) Build ➪ Build and Debug - Breakpoints On (Command+Y) Run ➪ Debug (Option+Command+Return) Run ➪ Debug - Breakpoints On (Option+Command+Y) As mentioned in the “ Running Your Application ” section, the two unqualifi ed “ Debug ” commands change to “ Run ” commands when breakpoints are inactive. The two “ Breakpoints On ” commands simply activate breakpoints and start debugging, identical to Run ➪ Activate Breakpoints, followed by Build/Run ➪ Debug. All of these commands start your program under the control of the debugger. The time from which the debugger starts your program until it fi nishes is referred to as the debug session . An alternative is available in the targets group if you would like to build and then run or debug a target that is not the active target or executable. Right/Control - click the target ’ s icon in the target smart group and choose either the Build and Start or the Build and Debug command. The effects are the same as changing the active target to the one selected, issuing a Build and Run/Debug command, and then switching the active target back to what it was originally. You can have only one debug session active for a project. However, you can have concurrent debug sessions from separate projects. A Client and a Server application, both built using separate projects, could each be running in separate debug sessions simultaneously. The Process Behind the Curtain Like most modern integrated development environments (IDEs), the Xcode application doesn ’ t perform the actual debugging — or compilation, or linking, or profi ling — of your application. Xcode simply provides an intelligent interface to the command - line tools that do the bulk of the work. In the case of debugging, the work is usually done by gdb , the GNU Debugger. I say usually, because Xcode can also use other debuggers. It understands the JavaBug and AppleScript debuggers, but if you ’ re doing Mac OS X or iPhone OS development, you ’ ll be using gdb . Xcode doesn ’ t try to hide the debugger; there are plenty of places where you can interact with the debugger directly. What it tries to do is eliminate much of the tedium of using command - line debuggers by replacing the command line with an interactive, graphical user interface. So while you ’ re working your way through this chapter, keep this in mind: Almost every debugging task you undertake in Xcode is eventually translated into a com- mand sent to gdb , or whatever debugger you ’ re using. ➤ ➤ ➤ ➤ ➤ c18.indd 446c18.indd 446 1/22/10 12:54:16 PM1/22/10 12:54:16 PM Download at getcoolebook.com Debugger Spoken Here Another great advantage to using an intermediate debugger is that your debugger interface remains largely the same regardless of the target application environment. Xcode can debug an application in any of the following environments: A local process running in Mac OS X A remote process running on another Mac OS X system An iPhone application running in a local simulator process An iPhone application running on a remote device Debugging an application running on the same computer system is the most common scenario, but by no means the only one. The section “ Remote Debugging, ” later in this chapter, shows you how to debug a process interactively that is running on a different computer system. iPhone application development would seem like it is worlds apart from desktop application development. While the design and implementation might be substantially different, the development tools remain almost identical. You might have expected a substantial portion of this chapter to be dedicated to the iPhone simulator and iPhone native debugging, but there ’ s really very little to say. Though there ’ s some prerequisite confi guration required before an iPhone or iPod Touch can debug applications (see Chapter 22), there is virtually no difference between debugging an iPhone application running on an iPod Touch and debugging a Cocoa application running on your development system. Almost everything in this chapter applies to both. ATTACHING TO RUNNING EXECUTABLES As mentioned earlier, the Xcode debugger can attach itself to an already running process on your local system, extracting debug information and taking control of its execution. Xcode may do this for one of four reasons: You create a new breakpoint or enable an existing breakpoint You reactivate existing breakpoints An application you started in Xcode crashes or encounters a trap You choose a process from the Run ➪ Attach to Process menu The fi rst three all apply to the currently running executable started via Xcode, but the behavior is a little different depending on which operating system you ’ re running. If you ’ re running Mac OS X 10.5 (Leopard) or earlier, your application is launched normally and the gdb debugger is started and attached when requested. If your running Mac OS X 10.6 (Snow Leopard) or later, Xcode preemptively starts gdb when it launches your application, but lets your application “ run free. ” When you enable breakpoints, gdb steps in, enables breakpoints, and assumes control of your application ’ s execution. The primary advantage is speed; gdb is launched quietly in the background, and springs instantly into action when requested. ➤ ➤ ➤ ➤ ➤ ➤ ➤ ➤ Attaching to Running Executables ❘ 447 c18.indd 447c18.indd 447 1/22/10 12:54:17 PM1/22/10 12:54:17 PM Download at getcoolebook.com 448 ❘ CHAPTER 18 DEBUGGING Whether gdb is preemptively started ahead of time or launched post hoc is largely immaterial, except in a few circumstances. Some of the system frameworks include anti - piracy code that either resists being debugged or disables certain features in the presence of the debugger. If you ’ re working with QuickTime or similar libraries, you may have to manually launch your application and then use the Run ➪ Attach to Process command at some strategic time. Once your application is running, creating or enabling any breakpoint signals to Xcode that you want to take control of the application with the debugger. The workfl ow you ’ d typically use this in looks something like this: 1. Write some code. 2. Build and run the application. 3. Discover that something ’ s not working right. 4. Start the debugger and have it attach to the already running application. 5. Debug the problem. The Run ➪ Attach to Process menu lets you attach the Xcode debugger to a process that Xcode didn ’ t launch. In this menu are all of the running applications. If you need to attach to a background process, choose the Run ➪ Attach to Process ➪ Process ID command and enter the process ID you want to debug. These commands are useful when you want to debug a process that you started outside of Xcode (say, from the Finder) or for processes started programmatically; for instance, you ’ ve written a Cocoa application that executes a command - line tool. When attaching to a running process, Xcode does its best to match the executable with a target in the current project. If it can ’ t it will still attach to the process, but the amount of useful debugging information will be extremely limited. The third reason Xcode will attach to your running application involves a trap, uncaught signal, or other exception that would normally cause the process to exit immediately. Xcode automatically intercepts these exceptions and — rather than letting your application terminate — attaches the debugger. You are left in a debug session with the program suspended at the location that caused the fatal problem. You can examine the threads, stack, variables, and other information in an attempt to determine what went wrong. You might fi nd it useful to intentionally cause a trap programmatically. To do this, you can add a debugger trap or a hard trap instruction to your code. The Debugger() or DebugStr() functions request the debugger. For the most part, they act like programmatically defi ned breakpoints. They will cause the debugger to stop the application, or attach the debugger to an already running application. If left in your code and run in the absence of a debugger, these functions will write a message to the system console every time they are executed — but they won ’ t terminate your application. c18.indd 448c18.indd 448 1/22/10 12:54:18 PM1/22/10 12:54:18 PM Download at getcoolebook.com A machine trap instruction is essentially a programmatic crash. It can be inserted using an assembly directive, as depicted in the following listing: #if defined(__ppc__) || defined(__ppc64__) asm { trap } #endif #if defined(__i386__) || defined(__x86_64__) __asm { int 3 } #endif These machine language trap instructions cause your application to immediately stop. If launched from Xcode, Xcode will attach the debugger as it would for any unrecoverable exception. If a trap is executed outside of Xcode, your program will immediately terminate. The system will treat your application as if it had crashed. Also see the “ Custom Executables ” section. Whether Xcode stops for Debugger() calls or automatically attaches itself when the process crashes can be disabled for individual executables. IN - EDITOR DEBUGGING Xcode ’ s in - editor debugging tools let you perform basic and common debugging actions right in your editing window. This means that in many situations you can edit, compile, run, and debug your application without ever switching to another Xcode window or view. When a debugging session starts, the debugger strip appears at the top of your editor pane, as shown in Figure 18 - 6. Combined with breakpoint controls in the gutter (which, more than likely, were already visible) and additional symbol inspectors (called datatips ), the in - editor debugging controls allow you to do three things: Modify breakpoints Control execution Inspect variables ➤ ➤ ➤ FIGURE 18-6 A setting in the debugging pane of the Xcode preferences enables the in - editor debugging controls. If you don ’ t see the in - editor debugging controls, check your preferences. In - Editor Debugging ❘ 449 c18.indd 449c18.indd 449 1/22/10 12:54:24 PM1/22/10 12:54:24 PM Download at getcoolebook.com . massive cross - index. They contain information like “ the machine instruction at byte offset 12, 738 corresponds to line 83 of the source fi le breakme.c. ” If you set a breakpoint at line 83 of breakme.c. usually, because Xcode can also use other debuggers. It understands the JavaBug and AppleScript debuggers, but if you ’ re doing Mac OS X or iPhone OS development, you ’ ll be using gdb . Xcode doesn. application environment. Xcode can debug an application in any of the following environments: A local process running in Mac OS X A remote process running on another Mac OS X system An iPhone