FORTINP%BNR.CA@FORSYTHE.STANFORD.EDU (Pierre Fortin, P.) (08/09/88)
Wellllll.... being a new-comer to the wonderful world of C (pronounced "see" or "sea"? ;-}), I don't know how you C-soned (;-}) veterans ever got along without it. However, in my first see-project (program to find and display the BOMB information (registers and stacks)), I found that CSD will not single-step within code which is executed while in Super() mode. Am I doing something wrong, or is there a definite and undocumented restriction to MW_C's CSD? Pierre Fortin FORTINP@BNR.BITNET
leo@philmds.UUCP (Leo de Wit) (08/16/88)
In article <8808090237.AA22529@ucbvax.berkeley.edu> FORTINP%BNR.CA@FORSYTHE.STANFORD.EDU (Pierre Fortin, P.) writes: >Wellllll.... being a new-comer to the wonderful world of C (pronounced >"see" or "sea"? ;-}), I don't know how you C-soned (;-}) veterans ever >got along without it. However, in my first see-project (program to >find and display the BOMB information (registers and stacks)), I found >that CSD will not single-step within code which is executed while in >Super() mode. Am I doing something wrong, or is there a definite and >undocumented restriction to MW_C's CSD? Some remarks: When a debugger single-steps through your code, a commonly used technique is to push your program's current status word and program counter onto the supervisor stack, setting the trace bit in that status word and performing a RTE. When the instruction at your program's program counter gets executed, a trace exception occurs - and the debugger takes over control again because the trace vector has been set up to point into the debugger. The 68000 clears the trace bit in the status word whenever an exception occurs (otherwise your debugger would get single-stepped, but only the first instruction, recursively... 8-). This implies that you cannot single-step exceptions (this includes traps, and thus GEMDOS, BIOS, XBIOS and GEM traps), unless the debugger 'takes over' at an exception (needs a table for all old exception vectors, and all current exception vectors point into the debugger). This you probably have not noticed, because you step at source level (could well be done without trace bit, using breakpoints; this however is restricted to code in RAM). An (perhaps acceptable and maybe undocumented) restriction of CSD could thus be that it does not let you single-step a trap (whether this is in fact true I don't know); I've however seen this with other (code) debuggers for the ST. I checked the Super() call (got curious of course 8-), but as far as I can see, it correctly preserves the trace bit in the status word. That is, when the TRAP #1 exception finishes the bit is what it was before the exception occured; the code within the trap cannot be traced (unless ..., see above). Some hints: a) try what you did using the XBIOS Supexec call, which performs a function in supervisor mode. If this also does not work, I would suspect CSD having trouble with supervisor mode for some odd reason. b) Have you used Super() correctly? Example: long ssp; ssp = Super(0L); /* save supervisor stack pointer & switch to s. mode */ /* supervisory stuff here , with ssp == usp */ Super(ssp); /* back to user mode, restore old supervisor stack ptr. */ An error you could have made easily is calling Super without argument... Hope this helps - Leo. P.S. A simple program to display the bomb info I posted to this group some months ago (does not show stacks); you can have it, unless of course you want to 'C for yourself' 8-).
apratt@atari.UUCP (Allan Pratt) (08/18/88)
In article <592@philmds.UUCP> leo@philmds.UUCP (Leo de Wit) writes: > Some remarks: > When a debugger single-steps through your code, a commonly used > technique is to push your program's current status word and program > counter onto the supervisor stack, setting the trace bit in that status > word and performing a RTE. When the instruction at your program's > program counter gets executed, a trace exception occurs - and the > debugger takes over control again because the trace vector has been set > up to point into the debugger. > The 68000 clears the trace bit in the status word whenever an exception > occurs (otherwise your debugger would get single-stepped, but only the > first instruction, recursively... 8-). This implies that you cannot > single-step exceptions (this includes traps, and thus GEMDOS, BIOS, > XBIOS and GEM traps), ... Having written a debugger, I can tell you that this is not the case. When the trace bit is on at the START of an instruction, the trace exception will happen at the END of the instruction. What this means is that if the T bit is on at the start of the TRAP instruction, the debugger will get the trace exception at the END of the TRAP instruction -- when the PC is at the first instruction of the trap handler. The SR at this point is clear (because the TRAP instruction cleared it), but the debugger is free to set it again. Unfortunately, this is not quite what you want: if you WANT to avoid tracing through the trap handler, you pay a price. Remember that the SR which the TRAP instruction pushed has the trace bit set, but the SR which the trace exception pushed has it clear. If the debugger doesn't set the T bit again, and rte's from the trace exception, the trap handler will execute at full speed. It will (presumably) RTE, and restore the SR with the T bit set. But since the T bit was clear at the START of the RTE instruction, you get no trace exception at the END of the RTE. Since T bit is set at the START of the first instruction after the TRAP (that is, the instruction the RTE returned to), you will get the trace exception at the end of THAT instruction. But by now your PC points to the SECOND instruction after the TRAP. This is not ideal. My debugger happens to have both modes: an "untrace" mode which sets the T bit every time (and therefore single-steps through trap handlers) and the normal mode, which treats trap instructions specially: it sets a breakpoint immediately after the trap instruction, and runs the trap instruction (and therefore the trap handler) at full speed, without the T bit set at all. ============================================ Opinions expressed above do not necessarily -- Allan Pratt, Atari Corp. reflect those of Atari Corp. or anyone else. ...ames!atari!apratt
leo@philmds.UUCP (Leo de Wit) (08/23/88)
In article <1122@atari.UUCP> apratt@atari.UUCP (Allan Pratt) writes: >In article <592@philmds.UUCP> leo@philmds.UUCP (Leo de Wit) writes: >> Some remarks: [some remarks deleted 8-]... >> The 68000 clears the trace bit in the status word whenever an exception >> occurs (otherwise your debugger would get single-stepped, but only the >> first instruction, recursively... 8-). This implies that you cannot >> single-step exceptions (this includes traps, and thus GEMDOS, BIOS, >> XBIOS and GEM traps), ... > >Having written a debugger, I can tell you that this is not the case. > >When the trace bit is on at the START of an instruction, the trace >exception will happen at the END of the instruction. What this means is >that if the T bit is on at the start of the TRAP instruction, the >debugger will get the trace exception at the END of the TRAP instruction >-- when the PC is at the first instruction of the trap handler. The SR >at this point is clear (because the TRAP instruction cleared it), but >the debugger is free to set it again. [rest deleted]... To show that I'm not making things up, I quote from 'Programming the 68000' by Steve Williams (edition by Sybex), page 357, Exception Processing (hope I'm not sued for copyrights, but then, this is for educational purposes only 8-): --------------------- start of quotation -------------------------------- Single-stepping an instruction involves setting the Trace bit in the status register. The most common method is to stack the Program Counter and status register, set the Trace bit in the stacked status register, and execute an RTE instruction. A trace exception will occur immediately following the execution of the target instruction. Some side effects of this technique are: o Since an exception clears the trace bit, an exception caused by the instruction being traced causes the debugger to lose control, unless the debugger receives control when exceptions occur. o TRAP instructions that call an operating-system function appear as a single instruction. o Tracing an RTE instruction causes the debugger to lose control because the RTE instruction reloads the status register. Tracing an instruction which reloads SR has the same effect. These instructions include MOVE to SR, ANDI to SR, and EORI to SR. o Tracing a MOVE from SR can cause the program to malfunction because the trace bit will be set in the copy of the status register that the program receives. If the program compares this copy without masking the trace bit, it could execute incorrectly. --------------------- end of quotation -------------------------------- I should say this contradicts what Allan said. I'm not saying who's right or wrong, but I'm getting curious at the *REAL* facts. Note also that I never said single-stepping trap handlers couldn't be done; however, after reading this quote it seems not trivial. If you don't take precautions (i.e. let the TRAP be vectored into the debugger) the trap handler code is executed untraced; the status word with the Trace bit set is reloaded from the stack when the RTE takes place, causing a Trace exception at that point (the program counter will point after the TRAP instruction). At least this is what I make of it! My own experience with a code debugger for the ST (sid.prg) is that it indeed performs a TRAP as if it were a single instruction (i.e. not single- stepping the code within the trap handler); why this was just so isn't clear now. Any 68K experts care to comment on this one; I'm especially interested in Allan's reply. Leo.
leo@philmds.UUCP (Leo de Wit) (08/25/88)
In article <610@philmds.UUCP> leo@philmds.UUCP (Leo de Wit) writes: |In article <1122@atari.UUCP> apratt@atari.UUCP (Allan Pratt) writes: [some stuff deleted]... ||When the trace bit is on at the START of an instruction, the trace ||exception will happen at the END of the instruction. What this means is ||that if the T bit is on at the start of the TRAP instruction, the ||debugger will get the trace exception at the END of the TRAP instruction ||-- when the PC is at the first instruction of the trap handler. The SR ||at this point is clear (because the TRAP instruction cleared it), but ||the debugger is free to set it again. | [rest deleted]... | |To show that I'm not making things up, I quote from 'Programming the 68000' |by Steve Williams (edition by Sybex), page 357, Exception Processing |(hope I'm not sued for copyrights, but then, this is for educational purposes |only 8-): [quotation deleted]... |I should say this contradicts what Allan said. I'm not saying who's right |or wrong, but I'm getting curious at the *REAL* facts. Being curious and all, I checked things by writing a primitive debugger; the *REAL* facts are that Allan was indeed right. The book though seems misleading at this point, if not to say incorrect: o Since an exception clears the trace bit, an exception caused by the instruction being traced causes the debugger to lose control, unless the debugger receives control when exceptions occur. The debugger can always *TAKE* control, just by setting the trace bit after the exception occured. The above statement seems to imply that exception happens --> debugger receives control OR --> debugger loses control which simply isn't true. Just like Allan said, the debugger receives control after the exception occured (the trace bit in the status word on the stack being cleared by the exception). When the debugger resumes the user program (by performing an RTE) it may be with or without this trace bit set again. In the first case the exception handler will be single-stepped, in the second case the debugger regains control when the exception handler RTE's, because the status word with trace bit set was pushed onto the supervisor stack when the exception occured. Which makes me wonder why Allan used a break point to 'go at full speed' through the exception handler; this neither seems necessary in this case, seeing the above, nor wanted (you cannot 'break point' ROM code). Leo.
apratt@atari.UUCP (Allan Pratt) (08/25/88)
In article <610@philmds.UUCP> leo@philmds.UUCP (Leo de Wit) writes: > --------------------- start of quotation -------------------------------- > > Single-stepping an instruction involves setting the Trace bit in the status > register. The most common method is to stack the Program Counter and > status register, set the Trace bit in the stacked status register, and execute > an RTE instruction. A trace exception will occur immediately following the > execution of the target instruction. Some side effects of this technique are: > > o Since an exception clears the trace bit, an exception caused by > the instruction being traced causes the debugger to lose control, > unless the debugger receives control when exceptions occur. > > o TRAP instructions that call an operating-system function appear > as a single instruction. > > o Tracing an RTE instruction causes the debugger to lose control > because the RTE instruction reloads the status register. Tracing an > instruction which reloads SR has the same effect. These instructions > include MOVE to SR, ANDI to SR, and EORI to SR. > > o Tracing a MOVE from SR can cause the program to malfunction because > the trace bit will be set in the copy of the status register that > the program receives. If the program compares this copy without > masking the trace bit, it could execute incorrectly. > > --------------------- end of quotation -------------------------------- > > My own experience with a code debugger for the ST (sid.prg) is that it > indeed performs a TRAP as if it were a single instruction (i.e. not single- > stepping the code within the trap handler); why this was just so isn't > clear now. First, your experience with sid.prg is misleading because sid, like my debugger, treats the trap instruction specifically so you DO see reasonable behavior. Second, your quote starts with the correct sentence: when the trace bit is set, a trace exception will occur immediately following the execution of the target instruction. This is exactly what I said. All the indented comments are in fact not correct. The first two have the same wrong interpretation. When the T bit is set at the start of the TRAP instruction, the exception will be taken at the end of the TRAP instruction, when the PC is in the OS. The SR stacked by the trap instruction will have the T bit set, but the SR stacked by the trace exception won't. The debugger DOES get control, but has to set the T bit explicitly if it wants to step through the trap handler. If it just RTEs from the trace exception, it will lose control (because, as I said, the SR from the trace exception has the T bit clear). The third indented comment says that RTE causes the debugger to lose control. This is also untrue. The T bit in the SR at the START of the RTE instruction is the one which will cause the trace exception at the END of the RTE instruction, even if the T bit in the SR which the RTE got off the stack is clear. The last one suffers from the same misconception all over again. In all four cases, the author misunderstands the effect of the T bit. He thinks that if the T bit is cleared during the execution of an instruction, you don't get the trace exception at the end of that instruction. This is just not true. I quote: "If the T bit is asserted (on) at the beginning of the execution of and instruction, a trace exception will be generated after the execution of that instruction has completed." M68000 8-/16-/32-Bit Microprocessors Programmer's Reference Manual, Fifth Edition, by Motorola, copyrights 1979 through 1986, page 4-12. ============================================ Opinions expressed above do not necessarily -- Allan Pratt, Atari Corp. reflect those of Atari Corp. or anyone else. ...ames!atari!apratt
apratt@atari.UUCP (Allan Pratt) (08/26/88)
In article <620@philmds.UUCP> leo@philmds.UUCP (Leo de Wit) writes: > [The debugger gets the trace exception at the end of the trap instruction, > with the stacked PC at the first instruction of the trap handler and > the stacked SR has the trace bit clear.] > > When the debugger resumes > the user program (by performing an RTE) it may be with or without this > trace bit set again. In the first case the exception handler will be > single-stepped, in the second case the debugger regains control when > the exception handler RTE's, because the status word with trace bit set > was pushed onto the supervisor stack when the exception occured. > > Which makes me wonder why Allan used a break point to 'go at full speed' > through the exception handler; this neither seems necessary in this case, > seeing the above, nor wanted (you cannot 'break point' ROM code). > > Leo. Once again you are imposing what you think should happen on reality, and it doesn't fit. Remember that the trace exception happens when the trace bit was ON at the START of the instruction. But in the RTE from the trap, the trace bit is getting set DURING the RTE instruction, so no trace exception happens after the RTE instruction. The trace bit is now set at the START of the instruction that the RTE returns to, so the trace exception happens AFTER THAT INSTRUCTION. The result: you don't see that instruction before it executes. But that's not what you expect from a debugger (and not what you get from sid): you expect to see every instruction before it executes. So you use a breakpoint to emulate the behavior you expect. The breakpoint it set on the instruction after the TRAP, so you see that instruction before it executes. ============================================ Opinions expressed above do not necessarily -- Allan Pratt, Atari Corp. reflect those of Atari Corp. or anyone else. ...ames!atari!apratt