Apple IIgs Debugging Tips and Techniques compiled by David A. Lyons, Apple II Developer Technical Support July 18, 1990 (July 23: corrected "InstallNDA is new for 5.0" to "RemoveNDA is new for 5.0, and be careful about removing DAs. Otherwise this document is what I handed out as the A2-Central Developers Conference.) General Techniques In a Desktop-based program that normally displays the super-hires graphics screen, write debugging messages to the text screen at selected points in your program (using the Text Tools, for example). Then in the event loop, test the mouse position (it appears in the "where" field of the event record after a GetNextEvent or TaskMaster call). If the mouse is in the upper left corner of the screen switch to the text screen using the QuickDraw II call GrafOff. If the mouse is anywhere else, switch back to the graphics display with GrafOn. (Reported by Ron Lichty; technique by Allan Bell, Australia) Check for errors on all toolbox calls that allocate memory. Have a scheme for dealing with low-memory situations. See Apple IIgs Technical Notes #51, 52, 56, and others, and read about the System Software 5.0 Out Of Memory Queue handling introduced (Apple IIgs Toolbox Reference Volume 3). Make sure the Bank register is set right. If you're writing code that all fits into a single 64K bank, you may want to always keep your data inside your code segment and use PHK PLB. If your data is in a separate segment, this is bad (you may not discover it right away, because two segments can wind up in the same bank most of the time, especially if they happen to be small). Use safety checks possible in your development environment. For example, if you use macros to allocate direct-page locations, use assemble-time error messages to check the amount of direct-page space you're using. If it exceeds 256 bytes, complain during assembly; this will be a lot more fun than trying to figure out why your code mysteriously crashes. Watch out for uninitialized storage locations! Random values may allow your code to work a lot of the time, so suspect this problem especially if your code works right sometimes and fails other times. (Developer Technical Support provides "Pointer Check" routines for use with APW C. See Sample Code volume 2.) Tips for using GSBug (Thanks to Tim Swihart for some of these GSBug tips.) Break into your application at a strategic toolbox call, such as TaskMaster, by using the GSBug commands SetTBrk and TBrkIn. When you hit r to resume your application, you will automatically drop into GSBug when you hit the selected call. At that point you can disassemble pieces of your code, start single-stepping it with s, or whatever. You can usually even hit Apple-Ctrl-ESC to enter your favorite CDA (see below). Here's a way to trace your program's code for handling a particular menu item. Set a tool break on TaskMaster. Resume your code and let it break on the TaskMaster call. Type s to display the super-hires screen, and click and hold the mouse button on the menu bar. Press space to execute the TaskMaster call. Select a menu item and release the mouse. At this point, you are still in GSBug, and TaskMaster has just returned. Press T to display the text screen, and press space to step through your code. Debugging a Classic Desk Accessory is hard, because the stack is normally in $00/01xx when a CDA executes. GSBug is not able to trace code reliably while the stack pointer is in this range. Here's something you can do instead, if you really need to trace that CDA code: break into the application at a convenient point (like at a TaskMaster call), set D=0 and start Stepping from the CDA's entry point (one way to determine the entry point is with Nifty List--try c018.5000i to find the right block in memory, and use ;c to display the name and entry points). Debugging a New Desk Accessory with GSBug was hard in the past, because the debugger could not receive any keystrokes while an NDA window was in front. With GSBug 1.5, just push down the CapsLock key, and all is well (the NDA does not receive any keystrokes while CapsLock is down and GSBug 1.5 is installed.) Type off in GSBug to see the top 23 lines of your code's "Real" text screen. Type on to get the GSBug screen back. If you get really fancy, you can build the strings (used in the SetMileStone and DebugStr calls) on the fly and imbed the values of key variables into them to further simplify locating the bug. If your development languages supports imbedding names or other info about your source into your object, use them. This helps you find routines at debug-time. Nifty List Techniques Nifty List is a Classic Desk Accessory by Dave Lyons. It's Shareware, and you can download it from GEnie or America Online, among other places. If he ever happens to be right in the same room with you, be sure to ask him for a copy. Here are a few things I do when I'm debugging some code with Nifty List handy. Pop into Nifty List and type V to see if you've really started up all the tools you think you have, and make sure the Work Area Pointers are valid (most tools use their WAPs for the address you pass to the startup routine; the Control Manager is currently an exception). Most of the other tool sets have valid handles or 0 for their WAPs. This is not guarnateed, but it's a useful sanity check while you're writing an application. (A few tool sets share the same work areas. Don't worry; it's normal for the Window Manager and Event Manager to share, and for QuickDraw II and QuickDraw II Auxiliary to share, for example.) Use the new Nifty List 3.0 \addfree and \check commands in Big Brother module to detect accidental memory stomping. Use c018.1000i to locate the static code segments in your application ("Info on handles with owner $10xx and memory manager attributes $C018"). Use 0/0;w to dump info about your window, including the pointer to the Content Draw routine. Make sure the content-draw routine does not assume that the Bank or D registers are set on entry! If it changes them, make sure it puts them back. If your window doesn't update right, check your content draw routine--you must not assume you are the frontmost window, so using FrontWindow to see what window you're supposed to draw in is wrong. Use GetPort instead, because TaskMaster sets the QuickDraw port to your window before it calls your update routine. Explore the toolbox by making toolbox calls directly from the Nifty List command line. When you Crash When you crash, look on the stack for return addresses to see how you got there. Sometimes things went so weird this is impractical, but it often helps. Nifty List's ;s command looks for RTS and RTL addresses for you automatically. (An "RTL address" is a sequence of 3 bytes on the stack that is the address of the last byte of a JSL instruction your program has executed, but which has not yet returned.) Check the Direct page register on a crash--by comparing against the WAPs for tools, you can often determine which toolset was in control of the machine when it crashes (that doesn't mean it isn't your fault, but it gives you a clue about where to look!). Logic Analyzers Logic Analyzers are hardware that hooks up to your computer and watches what's going on. They're pretty expensive, and you don't need one for most debugging problems. For certain types of problems, though, they come in very handy. For example, if you have found a particular byte of memory that gets changed for no reason, but your best efforts to find out what piece of code is actually changing that byte have failed, a logic analyzer can help. (Debugging code that gets called during interrupts can be impossible to debug with GSBug. If you can step through the code outside the interrupt environment, great--if that's impossible, consider using a logic analyzer.) The general idea is to tell that logic analyzer to "trigger" on a particular event (a read or write of a particular byte in memory) and then to record what happens after that (storing everything that the processor does, or just selected operations). This happens quickly, and then you can scroll through the resulting list to see exactly what happened in the next thousand or more clock cycles. Trick: include accesses to known ROM locations to help you trigger the analyzer at particlar spots in your code (STA $FF0000, $FF0002, $FF0004, etc). Here is some specific information about HP logic analyzers used for debugging on the Apple II Family. The HP 16500 provides more sophisticated trap specification end specification of which instructions to store when a trap is in effect. This provides for more trace mileage out of the 1024 instructions that can be traced than is possible on the HP 1630G, also used at Apple. Also, the 16500 works just like the 1650A for a lot of things. You can call the HP Customer Information Center at 1-800-752-0900, extension779E. Their catalog says that if they don't have an answer they'll put you in touch with someone who does. Also, the software for using these analyzers with the 65816 or 65C02 is available direct from us at Apple along with instructions for wiring the PODs accordingly. There are a couple of San Francisco area companies who rent these machines (see below). If you prefer to rent or lease the models, HP should be able to put you in contact with a vendor in your area that could do this. Engineers at Apple using these systems are very happy with them and generally prefer the touch screen capability of the 16500 model. (Hey, this isn't an endorsement, it's just information!) Also, an in-circuit emulator for the IIe and IIgs is manfactured by the Western Design Center, Inc. At the 1989 A2-Central Apple II Developer's conference Andrew Hall demonstrated this ICE system, called the Toolbox Design System, and stated that they would be open to rentals of the system. You can contact The Western Design Center at 2166 East Brown Rd., Mesa, AZ 85213, (602) 962-4545. These HP Logic Analyzer units should be rentable through the following companies: Continental Resources McGrath RentCorp 1575 McCandless Drive 2500 Grant Avenue Milpitas, CA 95035 San Lorenzo, CA 94580 (408) 263-1775 (415) 276-2626 (Thanks to Dan Strnad of DTS for this information on HP logic analyzers)