[comp.sys.atari.st] MW_C C-Source Debuger question

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