Debugging


How do I find out what happened when I get a Method Not Found error?


When you get a Method Not Found error, that usually means that you called an operation on an instance of a class that doesn't define that operation, or you passed in an object that no longer exists. The object in question is what would have been the self parameter if the method was entered successfully. To take a look at this object to try to figure out what went wrong, single step past the RTS until you are back in the code that failed. Then issue the "ip" command and you will see the name of the method that was not found (right before the PC). The object is still at the top of the stack, and you can enter the command "dobj @sp" to dump the object.


Every now and then I get an exception failure. How can I use Telebug to figure out what they mean and why they happened?


Exception debugging isn't an exact science, and you'll usually wind up spending five or ten minutes doing different stack crawls to find the right return address to look at, but here's the basic jist of what's going on.

Exceptions happen when some piece of code calls Fail() to throw an exception. If you're running Telebug, this will land you either at a tst.l d2 instruction inside of Exceptions_Warn, or at a Debugger() statement inside the routine _CommonExceptionHandler. In theory, you can type "exc d0" to get an English description of the exception that occurred. In practice, this command returns "Cannot find attribute" more often than not, which isn't very useful.

What you'll have to do in this case is do a stack crawl to find the routine that called Fail to determine the type of exception it failed with. You need to be careful because you could be in supervisor mode because you're in the exception handler. In this case, if you do a stack crawl, you'll be looking at the supervisor stack, which is probably (but not definitely) not where the return addresses for your call chain are. You can compare sp with the value returned by usp. If the two are the same, you're looking at the right stack. If they're different, you'll have to execute a usc (user stack crawl) instead of a normal sc command to get the right stack.

You might see something like this:

# Exceptions_Warn
I 0E08A90C # +0084 * TST.L      D2                            

sc
  CallerPC   Caller                          A6 Link   Params
I 0E06D948 # UserActor_Main+00FA             0001F66C  D400 001F 0000 0000 FFFF
I 0E13490A # TouchTool_TouchTarget+0010      0001F640  D440 00BF 0000 0000 D400
I 0E144206 # Viewable_Touch+0060             0001F614  8400 0773 D440 00BF 0E06
I 0E056A62 # Icon_Tap+003C                   0001F600  8400 0773 D440 00BF D440
I 0E05689E # Icon_Action+004C                0001F5C4  8400 0773 D440 00BF 8400
I 0E14376A # Viewable_SetSuperview+0016      0001F504! 8400 0773 8400 0773 D440
I 0E1436F2 # _SetSuperviewAndOrigin+014C     0001F4D8  8400 07F2 8700 2000 0000
I 0E14358A # _AboutToHideOrShow+0044         0001F4A4  8400 07F2 0000 0001 0000
I 0E1406CA # Viewable_EachSubview+0036       0001F470  8400 07F2 0E14 34D2 0001
I 0E0B6856 # Card_AboutToShow+002E           0001F3E0! 8400 07F2 0E14 062C 0001
I 0E11AC68 # TextField_AdjustSize+0010       0001F384! 8400 25C1 8400 25C1 8400
I 0E117222 # TextFormatter_LineHeight+0012   0001F310! 8400 0D81 0000 0000 0E0B
I 0E08A90A # Exceptions_Warn+0082            0001F310! 8400 264F D440 00D7 0E11 

This would suggest that TextFormatter_LineHeight failed, or some routine that was called by TextFormatter_LineHeight.


From time to time I get a "Cleaning up" message for apparently no reason at all. Sometimes, I'll get an announcement afterwards that tells me I'm getting low on memory. When I look in the storeroom, I have over 200K of main memory left, so I think I've got plenty of space available. What's going on here?


Whenever you get a cleaning up message followed by an announcement that says that memory is getting low, that almost always means that you ran out of transient memory. You can verify that this is the case if you're plugged into Telebug. In this situation, you will stop at a Debugger statement inside of _WellKnownReset. The problem with running out of transient memory is that unless you've set up an exception handler, the device does a reset, and by the time you're at the debugger break, you don't know what routine was executing when you ran out of memory. If you find yourself at _WellKnownReset, you can look at the exception and exceptionReason fields of the user actor (by doing dobj iUserActor), to see what caused the reset. In the case of running out of transient memory, the exception value is 1, for cannotAllocateMemory, and the exceptionReason should be 5, which is the slot number for the transient RAM metacluster.


I would like to use "GetObj" to look at objects with ID's like $B400000C, but when I try to do this MacsBug complains that it is "unable to access that address". Lower addresses, like those starting with $8... seem to be fine, but the $B... ones just won't make it. Why can't I see certain objects?


If the object doesn't exist, or the object's context is not the current context, then the dcmd will usually just respond with "object not found" (or something to that effect). Sometimes, though, in trying to find an object that doesn't exist the dcmd will dereference an address that is invalid, causing Macsbug to issue the message about being "unable to access that address". Also, if Magic Cap is not the current application then you're almost certain to get this response from the dcmd. (Macsbug shows the current application, so you can see if you're inside Magic Cap or not)

An object ID starting with `B' represents a package object. In order to get at it with GetObj (or its many macros, such as dobj, do0, do1, etc) the package's context must be the current context. You can tell if a package context is current by issuing the `con' command and noting whether any package clusters are listed. Note that if you interrupt the system when it is "at rest" (i.e. just sitting there) then the package context will practically never be the current context. There are a few ways to pop into Macsbug while your package context is current. One way is to but a debugger break in one of your methods. Another is to put a breakpoint on one of your methods. Yet another way is to press on a package viewable, and while still holding the mouse button down, break into Macsbug. In any of these cases, the system will switch to your context as part of dispatching to your method. Another way, less deterministic, is to tap something that you know will run some of your code and break into the debugger as soon as you can (via the interrupt switch or Programmers' Key).


Where does Telebug keep its parsed symbols? I've pasted new symbols into the ROMEquates file, but the old symbols are still being used. How do I get rid of the old symbols?


The parsed symbols are stored by Telebug in the resource fork of the ROM equates file it is using. Load time for Telebug decreases dramatically when the pre-parsed symbols can be read directly instead of parsing the whole file.

You can't erase selected symbols, but you can erase all of them at once by deleting the resources. A quick way to do this is to quit Telebug and then execute the following in MPW:

echo "delete 'Regs';" | rez -a -o "{MagicTelebugFolder}"ROMEquates

The next time you start Telebug it will reparse the symbols and save new resources.


Is there a way to load the Telebug savestate of a RAM card into the Magic Cap simulation on the Mac?


What you need to do is use the save command in Telebug instead of savestate. You can then use the "Insert card into slot" command in Magic Cap to open this file. The syntax for the save command is:

save fileName 04000000 00100000

The first number is the base address for a PCMCIA card in slot one. (To save the image of a card in the second slot on an Envoy, use 08000000.) The second number is the size of the image you're saving. The number used in this example is the size for a one meg card. Both numbers are in hex.

Note that the default size for simulated PC cards is 600K, which is smaller than a typical PC card. You can change the default size the simulator uses with the "Set Simulated PC Card Size" item in the Magic menu.


If my package is in main memory, why is Telebug is unable to find the symbols for my methods?


The problem is that the PackageEquates file that is generated assumes that the package lives on a PC card. You can make the symbols work when you package is in main memory by changing the address of your package cluster that appears in the PackageEquates file (it's usually right after the EndOfROM declaration) to the address where the package cluster wound up in main memory. This means that you'll need to start Telebug, do a quick cdump, quit Telebug, change the equates file and restart whenever you put a new copy of your package on the device.


Is there a good way to look at (ie. dobj) an indexical in Telebug? On the Mac, I can use the inspector to look at indexicals. In Telebug, I can find my package context in the RAM metacluster (no easy task) and dobj its Rootlist to see package indexicals. Is there an easier way? I know no way of finding out system indexicals in Telebug -- is there one?


Once upon a time, you could dobj indexicals by symbol in Telebug. Sometime during the development of Magic Cap 1.5, this went away and no one knows why. You can dump indexical objects if you do the bit shifting that MakeIndexical() does manually.

Given a system indexical {x,y}, it's corresponding object ID is 0x87000000 | (#x << #13) | y. The # specifies a decimal number. You need to type that in, otherwise Telebug (and Macsbug) interprets your number as hex. For example, iCurrentScene, which is {22,1}, would be 0x87000000 | (#22 << #13) | 1, or 0x8702C001. Flat indexicals follow the same formula; just drop the y index.

You can do the same thing to dump package indexicals as long as you know you're in the right context. You would use 0x87800000 for the object bits to specify a package indexical.