Debugger Tutorial

This short tutorial is a way for you to try out the debuffer and start to get familiar with its commands. It is based on sample.asm by Darrin Massena, an example program he wrote for his Pilot Assembler. NOTE: there is a bug in seed version 2.1d23 of the Poser in handling breakpoints, and breakpoints are a big part of this tutorial. I recommend you use the latest release version 2.1d3.

First, you will need to either download the compiled sample.prc or get the source and build it. To follow along with the tutorial, you can get the main source file locally.

It takes only a few steps to get started debugging. Start by running the debuffer. It will hang, waiting for a debug event from the emulator. Next, run the emulator and load the sample.prc application. As soon as you start sample, you will hit a hardcoded break and get a prompt in the debuffer. Let's have a quick look around (output is elided):

ok> pc @ 10 dis[ENTER]
...
ok> bt[ENTER]
...
ok> .regs[ENTER]
...
"pc @ 10 dis" disassembles the next 10 instructions from the current program counter. "dis" takes as its arguments an address and a count, but notice that to get the address we use "pc @" and not simply "pc". All emulator registers are mapped directly to FORTH variables in the debuffer. This means that you can modify a register just by assigning to its corresponding variable. FORTH syntax for accessing a variable, however, uses a "@" to "fetch" its value - that's what we're doing here.

Now that we've seen where we are, we can take a look at where we've been. "bt" does a stack backtrace and shows you the call history.

Lastly, we have a look at the state of the CPU by displaying all the registers with ".regs".

Once we've gotten our bearings, it's worthwhile to look at more of the program being executed:

ok> pc @ 25 dis[ENTER]
...
1001a4a2: 4eba 0040 jsr.l $40(pc) ; ApplicationHandleEvent
...
Among the output, we can see the branch to our main application event handler. We can verify this branches to the main event handler by disassembling the target of the branch and looking at the code there.
ok> 0x1001a4a2 0x40 + 0x02 + 10 dis[ENTER]
...
This command builds an address by adding the location of the branch instruction (0x1001a4a2), its offset (0x40), and the size of the instruction word itself (0x02). There are a couple of things to note at this point. One, while the debuffer usually shows its output in hexadecimal, we can enter numbers either in decimal (the default) or in hex (with 0x...). Two, we start to see that the command language is in fact a complete programming language.

Now, let's set a breakpoint in that routine.

ok> 0x1001a4a2 0x40 + 0x02 + bp[ENTER]
ok> bl[ENTER]
...
ok> go[ENTER]
...
We build the target address in the same way as before, but this time we pass it to the command "bp" to set the breakpoint. "bl" lists the breakpoints, allowing us to confirm our action. Lastly, "go" resumes execution in the emulator.

Alternatively, we could have saved a little typing by using another language feature:

ok> 0x1001a4a2 0x40 + 0x02 + dup 10 dis[ENTER]
...
ok> bp[ENTER]
ok> bl[ENTER]
...
ok> go[ENTER]
...
"dup" duplicates the item on the top of the stack (the last result), which in this case is the address we're interested in. Having duplicated it, we can use the address once in the disassembly and again in setting a breakpoint. Had we decided we weren't interested in the breakpoint, we could have discarded the result with "drop".

Of course, the breakpoint gets hit almost immediately. Look around with "bt" and you can see that you are indeed in the ApplicationEventHandler. Let's get rid of the breakpoint.

ok> bl[ENTER]
...
ok> 0 bc[ENTER]
ok> go[ENTER]
...
"go" resumes execution. Since there are no breakpoints set you will not regain control in the debuffer. Hit Ctrl+C to kill it.
Last Modified: Jan 9, 1999
sessoms@pagesz.net