ghidra
ghidra copied to clipboard
Emulator: Slow single step after pausing emulation
Describe the bug Attempting to single-step one instruction after pausing emulation that has run for a while takes a really long time and results in the "Emulating..." pop up dialog with progress.
To Reproduce Steps to reproduce the behavior:
- Compile the following with
-g3 -O0
int main() {
unsigned char v;
volatile unsigned char *p = (volatile unsigned char *)&v;
for (unsigned long long i = 1; i > 0; i++) {
*p = 0;
}
p = (volatile unsigned char *)&v;
for (unsigned long long i = 1; i > 0; i++) {
*p = 0;
}
}
- Import, open in code browser, run analysis, save and close.
- Open the file in the emulator.
- Go to main, start emulating the current program in a new trace starting at the cursor.
- Let it run for about 30 seconds (I waited until my laptop fans picked up).
- Click the interrupt/suspend/pause button (ctrl+i)
- After it has paused and you investigate why it is stuck, attempt to single step.
- Notice it re-emulating the trace all over again for no reason.
Expected behavior It should perform a single step and only emulate the current instruction with the current state.
Environment (please complete the following information):
- Ghidra Version: 11.0_DEV ~ 5b53b35968c87388be5a1c753b3f572aa9bd982c
Additional context I'm not sure if this is even technically a bug but it can be quite a bottleneck.
I'll have to check why, but you are correct, it should just pick up where it left off and perform the one step. One likely explanation is that the emulator gets interrupted in the middle of an instruction. (It checks the suspend flag every p-code op, in case there's an infinite loop in the sleigh spec.) The details get pedantic, but I don't think the emulation service realizes it can use that interrupted emulator, because of those trailing ops. So, it creates a fresh one on the original initial state and re-executes the schedule+1.
I suspect if you were to step a second time after the interrupt, it will do what you expect?
This fix won't be easy, but I think it's doable.
I'll have to check why, but you are correct, it should just pick up where it left off and perform the one step. One likely explanation is that the emulator gets interrupted in the middle of an instruction. (It checks the suspend flag every p-code op, in case there's an infinite loop in the sleigh spec.) The details get pedantic, but I don't think the emulation service realizes it can use that interrupted emulator, because of those trailing ops. So, it creates a fresh one on the original initial state and re-executes the schedule+1.
I suspect if you were to step a second time after the interrupt, it will do what you expect?
This fix won't be easy, but I think it's doable.
Yes stepping a second time will work as expected. I think if you were to click run after single stepping in that state it will do it again too but don't quote me on it.