The Fuse debugger has a "finish" feature which is sort of like the "step out" feature of other debuggers. The idea is that it runs to the end of the current subroutine. Only in Fuse it's implemented by placing a temporary breakpoint at the address at SP, which really isn't ideal. If the subroutine has done anything with the stack the feature is going to fail.
I was thinking about reimplementing this a different way. One way would be to collect a stack of return addresses by hooking into the emulator's CALL, CALL cc and RST instructions. "Step out" can then just put a temporary breakpoint at the address at the head of this "internal" stack.
It then occurred to me that maybe it's possible to implement it simply by hooking into the emulator's RET and RET cc instructions. Set an internal flag when the user does a "step out" and check for that flag at return instructions. If found, execute the return then stop at the next instruction.
I prefer the first option because it allows a stack trace to be generated and presented. But the second way appears temptingly simple. Is there a reason the second way wouldn't work?
"Step out" in a debugger
"Step out" in a debugger
Derek Fountain, author of the ZX Spectrum C Programmer's Getting Started Guide and various open source games, hardware and other projects, including an IF1 and ZX Microdrive emulator.
Re: "Step out" in a debugger
Either way can be defeated by weird enough code, but if I were implementing it I'd go for "step out" being equivalent to "run until a RET occurs" - it's probably what most developers would expect to happen and I suspect will give the right behaviour 99% of the time.
- Einar Saukas
- Bugaboo
- Posts: 3097
- Joined: Wed Nov 15, 2017 2:48 pm
Re: "Step out" in a debugger
Agreed. However I suggest "run until the number of RETs exceeds the number of CALLs". For instance:
In this example, stepping out should happen upon reaching the second RET, not the first.
Code: Select all
subroutine:
...
RET
main:
LD B,8 <--- current position
loop:
CALL subroutine
DJNZ loop
RET