Single-stepping
(Oops, CC-ed to the wrong list first time!)
Hi John,
I've been helping Alan Modra out with kernel changes to support
single stepping for gdb. Paul Bame suggested I bounced our ideas off you in case you (or anyone else) had any comments. I havn't actually committed my changes yet.
The basic approach is to use the recovery counter to generate a trap every instruction. The scheme is complicated because a suspended process may or may not return to user space via an RFI.
If it was suspended as a result of an interrupt then we can simply set PSW bit R in the tasks saved registers and it will get loaded by the RFI. On every task switch I set the recovery counter to 0, just in case the new process is being single-stepped.
If a process is suspended during a syscall, then there is no RFI on the return path to userland, and we have to handle things differently. I have changed the syscall return path such that it loads the recovery counter with 3 before updating the PSW with a value from the tasks saved registers. If that PSW has the R bit set, then the count of 3 will generate a trap on the first instruction following the branch back to user space. Note that PSW wasn't previously restored on the syscall return path.
To avoid further complications of interrupts during the three instructions when the recovery counter is decrementing, whenever we set the R bit, we also clear the I bit to disable interrupts.
Nullified instructions are handled by the controlling process manually moving the childs IAOQ over the instruction without actually setting it running, because the recovery counter isn't decremented for nullified instructions.
I need to do some more testing before committing this, but would welcome any comments on the basic approach taken, areas I have mis-understood, or problems with it that might not yet have occurred to me.
Thanks,
Richard
Quoted 8 lines
I've been helping Alan Modra out with kernel changes to support
single stepping for gdb. Paul Bame suggested I bounced our ideas off you in case you (or anyone else) had any comments. I havn't actually committed my changes yet.The basic approach is to use the recovery counter to generate a trap every instruction. The scheme is complicated because a suspended process may or may not return to user space via an RFI.
I really don't know enough to comment on the implementation choice. Why did you decide on this approach as opposed to inserting breaks and enabling the taken branch branch trap (T)? It would appear that the recovery counter was intended to provide software recovery from hardware faults in fault tolerant systems. Possibly, Grant could comment on whether it is actually useful for this purpose.
Dave
Signature · 2 lines
J. David Anglin [email protected] National Research Council of Canada (613) 990-0752 (FAX: 952-6605)
In message <[email protected]>you write:
Quoted 9 lines
Quoted 8 lines
I've been helping Alan Modra out with kernel changes to support
single stepping for gdb. Paul Bame suggested I bounced our ideas off you in case you (or anyone else) had any comments. I havn't actually committed my changes yet.The basic approach is to use the recovery counter to generate a trap every instruction. The scheme is complicated because a suspended process may or may not return to user space via an RFI.
Quoted 7 lines
I really don't know enough to comment on the implementation choice. Why did you decide on this approach as opposed to inserting breaks and enabling the taken branch branch trap (T)? It would appear that the recove ry
counter was intended to provide software recovery from hardware faults in fault tolerant systems. Possibly, Grant could comment on whether it is actually useful for this purpose.
Err, we tried that at the UofU in our mach port to the PA -- there's a problem with that scheme, though I don't remember precisely what it was. I believe there were cases where the recovery counter doesn't trigger a trap, possibly due to nullified instructions.
You might look at the UofU BSD code, which I believe used breakpoints and branch taken traps instad.
jeff
Quoted 23 lines · [email protected] wrote:
In message <[email protected]>you write:
Quoted 9 lines
Quoted 8 lines
I've been helping Alan Modra out with kernel changes to support
single stepping for gdb. Paul Bame suggested I bounced our ideas off you in case you (or anyone else) had any comments. I havn't actually committed my changes yet.The basic approach is to use the recovery counter to generate a trap every instruction. The scheme is complicated because a suspended process may or may not return to user space via an RFI.
Quoted 7 lines
I really don't know enough to comment on the implementation choice. Why did you decide on this approach as opposed to inserting breaks and enabling the taken branch branch trap (T)? It would appear that the recove ry
counter was intended to provide software recovery from hardware faults in fault tolerant systems. Possibly, Grant could comment on whether it is actually useful for this purpose.Err, we tried that at the UofU in our mach port to the PA -- there's a problem with that scheme, though I don't remember precisely what it was. I believe there were cases where the recovery counter doesn't trigger a trap, possibly due to nullified instructions.
Quoted 5 lines
You might look at the UofU BSD code, which I believe used breakpoints and branch taken traps instad.
jeff
I implemented two different single step algorithms for a a _kernel_ debugger for hp-ux. The algorithm used could be chosen by a compile switch, because each method had cases that weren't handled well - for some debugging tasks one algorithm was superior to the other. Part of my problem with the recovery counter was that other services in the hp-ux kernel also used the recovery counter.
I liked the recovery counter method better than my second method (but had to deal with collisions with the other kernel services). My second method was to insert a breakpoint at the target of the single step. It's a pain to do that because of issues with delay slots, branching, and nullification.
I guess the point of all this rambling is to say that the recovery counter has been successfully used by a debugger for single stepping.
-Frank
Signature · 2 lines
Frank Rowand <[email protected]> MontaVista Software, Inc
Re:
Quoted 2 lines
I implemented two different single step algorithms for a a _kernel_ debugger for hp-ux. The algorithm used could be chosen by a compile switch, because
BTW, Frank, ask Lee Courtney at MontaVista about Debug/iX ... we've had kernel debugging and single stepping (except for the interrupt control stack and a few other corner cases) for 15+ years.
It's *very* powerful to be able to logon as root (or equivalent) and set breakpoints within the kernel, hit them, and then single step ... all on a standard release of the operating system.
Quoted 4 lines
I liked the recovery counter method better than my second method (but had to deal with collisions with the other kernel services). My second method was to insert a breakpoint at the target of the single step. It's a pain to do that because of issues with delay slots, branching, and nullification.
Worse yet...the breakpoint mechanism raises hell if you have more than
one CPU :) You realllly don't want that other CPU to hit the breakpoint!
Signature · 2 lines
Stan Sieler [email protected] www.allegro.com/sieler/wanted/index.html www.sieler.com
Re:
Quoted 2 lines
Quoted 2 lines
The basic approach is to use the recovery counter to generate a trap every instruction. The scheme is complicated because a
...
Quoted 2 lines
I really don't know enough to comment on the implementation choice. Why did you decide on this approach as opposed to inserting breaks and
MPE/iX (which runs on PA-RISC hardware), has successfully used the Recovery Counter to implement single step for many, many years.
BTW, in addition to single step, it's a great tool for counting the number of instructions a procedure (or code path) takes, assuming an adequately powerful debugger:
1) stop (perhaps via a breakpoint) at the start of the code you want to count.
2) set a breakpoint at the end of the code you want to count (e.g., if you're counting a procedure, set a breakpoint at the procedure exit)
3) instead of "continue", do: s 1000000
(i.e., tell Debug/iX to "singlestep" 1000000 instructions)
4) if you hit the breakpoint, enter:
= 1000000 - rctr
that's how many instructions your code took! (Not counting instructions executed by interrupt handlers, of course.)
5) if you *didn't* hit the breakpoint, then 1000000 wasn't enough instructions (and why are you trying to count so high?)
This works because MPE's debug "s" command sets the Recovery Counter to the number of instructions you wanted to step. Normally, that's one (for just "s"). If you said "s 3", it would set the Recovery Counter to 3. If you say "s 1000000", and then execute 123 instructions, and then hit a breakpoint, Debug captures the entire register state as of the breakpoint: including the Recovery Counter (which has 1000000 - 123 in it).
Tip: if you're looking at instruction-level debugging, look at Debug/iX to see how to do it right!
Quoted 2 lines
It would appear that the recovery
counter was intended to provide software recovery from hardware faults
The 1986 PA-RISC Instruction manual simply says "The Recovery Counter (CR 0) can be used to provide software recovery of hardware faults in fault tolerant systems". (I.e., "can", not "must" ... and there's no explanation of how one would use it for this.)
Signature · 2 lines
Stan Sieler [email protected] www.allegro.com/sieler/wanted/index.html www.sieler.com
Quoted 9 lines · John David Anglin
Quoted 8 lines
I've been helping Alan Modra out with kernel changes to support
single stepping for gdb. Paul Bame suggested I bounced our ideas off you in case you (or anyone else) had any comments. I havn't actually committed my changes yet.The basic approach is to use the recovery counter to generate a trap every instruction. The scheme is complicated because a suspended process may or may not return to user space via an RFI.
Quoted 6 lines
I really don't know enough to comment on the implementation choice. Why did you decide on this approach as opposed to inserting breaks and enabling the taken branch branch trap (T)? It would appear that the recovery counter was intended to provide software recovery from hardware faults in fault tolerant systems. Possibly, Grant could comment on whether it is actually useful for this purpose.
Alan Modra made those early decisions, but I gather that he went for the recovery counter because it at least appears to be rather more straightforward.
Richard