Sean Conner wrote:
It was thus
said that the Great Jerome H. Fine once stated:
I know of only one example of a debugger which
supports
a Program Counter History Log.
I am in the process of adding a Program Counter History Log
to the System Debugger in RT-11 on a PDP-11. I would
appreciate a few suggestions from anyone who has any
experience with a debugger program which supports
Program Counter History Logging.
I've somewhat played around with this concept with a 6809 emulator I wrote
[1]. One version of the emulator will print out the current instruction
being executed. I've found that it generally took a few hundred
instructions to isolate bugs, but the code in question was never that large
to begin with.
Actually, the SD: debugger for RT-11 already does that. The
user can request that 126 instructions execute in a single step
mode and the debugger will display each instruction and all
the registers as those instructions are executed. If a particular
portion looks interesting, the user can <CTRL/S> to stop the
process and <CTRL/Q> to restart. On a VT100, the key
called {NO]SCROLL can be used to toggle that.
However, the overhead is quite high (probably a few thousand
instructions for each instruction displayed) and I found that less
than 100 instructions is sufficient to capture just the address of
each instruction. It is actually quite complicated since interrupts
to the SD: debugger can table place for many reasons and the
pre-analysis when history logging is active is not at all simple.
For those who
have direct PDP-11 experience, the
following information might also be useful. At present,
there are two buffers which can be displayed:
(a) A buffer with 40 of the last interrupt entries to SD:
which are composed of 5 words each:
- Program Counter Address from the Stack
- Program Status Word from the Stack
- Word (instruction?) at that Address
What is "that Address"? The word pointed to by the PC? Or the stord
pointed to by the SP?
The word pointed to by the PC at the time the instruction would
have been executing. By the time the SD: debugger in RT-11
is in control as a result of the interrupt, the stack holds the address
of the instruction, so both answers are actually correct. Usually,
I think of the instruction as being at the address pointed to by
the PC, but after the interrupt, that address is pointed to by the
stack - although for a PDP-11 running a Mapped Operating system
with the user program executing in User Mode and the SD: debugger
executing in Kernel Mode, it takes a special PDP-11 instruction,
MFPI or Move From Previous Instruction, to access the User
Mode Instruction Space from Kernel Space. Fortunately, the
instruction:
MFPI @(SP)
will use the word on the stack as the pointer address and add
the word at that address in User Mode to the stack in Kernel
Mode. So it usually takes only a single instruction to retrieve
the instruction that was just about to be executed when the
interrupt took place.
Someone put a lot of thought into how programs could be
debugged under RT-11. As it happens, the operating system
also requires MFPI since a call to the operating system also
results in an interrupt directly into operating system code
which also places the address (in this case of the next word)
on the stack. The simple solution to capture that word is:
Mov (SP),-(SP) ;Copy the address on the stack
Sub #2,(SP) ;Get address of instruction causing
the interrupt
MFPI @(SP)+ ;Place instruction causing interrupt on
the stack
- Word
(instruction?) at the Previous Address
- Control Word which is used by SD: (PROSNG)
(b) A buffer with the last 1000 Addresses of the last
1000 instructions that have been executed
The current logic in the code to save each instruction
address in the 1000 word buffer ONCE and ONLY
once uses all five of the above values.
There seems no point in displaying all 1000 addresses
since only about 200 can stay on the screen and it takes
too long in any case. However, just how useful are the
past 1000 addresses as an aid in debugging?
It can be helpful, but only if the addresses are examined immediately
after the bug---even at 1MHz a thousand instructions go by quickly. Again,
with one of my emulators, even though it was only a few hundred instructions
to isolate the bug, I had to skip thousands upon thousands of other
instructions before the bug hit, and even then, if I was too slow, I had to
back up several thousand instructions (if the bug wasn't an infinite-loop
type bug).
That is the specific answer I was looking for. With a 64 word
buffer, only a very general are is possible. At that point, it often takes
MANY more attempts to isolate the bug, but at least even a very
small buffer provides a hint and a start.
By nature, I am a VERY conservative programmer. In almost
all cases, I attempt to add as little code as possible when I make
a change. That helps to pinpoint the area to look at when any
changes cause a problem. Notice the HELP - it does not work
all the time.
NOW finally,
here are my questions.
Are there any suggestions as to how many previous
instructions are needed to usually be helpful to have a
log for when a program has a problem? Also, would
it be useful to have the first word (two bytes) of the
instruction as well as the address in order to identify
the actual instruction or is the address almost always
sufficient?
As long as the instruction stream doesn't change [2], just the address
is needed, as you can use that to get the instruction out of memory.
That is what I thought. Even when overlays are used and
many possible different subroutines can be read into the same
memory, with the PDP-11, the mix of different instruction
lengths will also provide confirmation as to which group of
instructions was executing.
-spc
[1] A library really, in C. Easy to use, and makes absolutely no
assumptions about memory layout (or hardware, for that matter); it
also includes a disassembler (also a library). But it's not the
fastest emulator, but as far as I know, it is accurate, and it's
still faster than the actual devices on modern hardware (on my
2.5GHz machine it can run the 6809 at around 85MHz). If anyone is
interested, I can make the code available.
[2] No self-modifying code
THANK YOU for your suggestions. I feel that I am
on the right track.
At the moment, I also want to add the ability to choose
between 10 addresses per line in the history log (when
the screen is 80 columns wide) and 18 addresses per line
in the history log (when the screen is 132 columns wide).
I can use <CTRL/N> to set the screen to 80 columns
and remember the screen size. Alternatively, <CTRL/W>
can be used to set the screen to 132 columns. <CTRL/R>
seems a good choice to just refresh the screen as needed.
Many other RT-11 programs also use <CTRL/R> and
<CTRL/W> as equivalent to refresh the screen, so they
seem to be a good fit along with adding <CTRL/N> for
the NARROW screen.
Jerome Fine