Emulator discards changed PC register value when stepping
Describe the bug I'd like to skip to a specific address, so I edit the PC register (aarch64). After this, the dynamic listing changes its location, and the new PC register value is visible in the threads panel. However, after I press "Step the integrated emulator a single instruction", it steps to the next instruction that'd be executed if I didn't change the PC register - IOW, it ignores my PC register change.
Maybe changing the PC register is not the correct way to make a given thread "jump" to arbitrary location, but then I couldn't find out how to do it..
To Reproduce Steps to reproduce the behavior:
- Open any aarch64 program in the emulator
- Right click any instruction, press "Emulate program in new trace"
- Populate memory, for instance via "load emulator from programs"
- Step a single instruction, observe PC now being X
- Change the PC register to point to a different location Y
- Step a single instruction, observing that instruction at X was executed, not at Y
Expected behavior In the step 6, the instruction at Y should be executed.
Environment (please complete the following information):
- OS: Linux x64
- Java Version: 21.0.4
- Ghidra Version: 11.1.2
- Ghidra Origin: github release
Note invalidating emulator cache does not help
Okay. I believe it's because the emulator keeps a copy of the counter, rather than reading it from the state every loop. It seems I need to treat patches affecting it as a special case. I think this will be an easy fix. In the meantime, a possible workaround is to use the Go To Time action. (Yes, I agree, that is not intuitive, but hey, it's a workaround....) After Step 5 in your process above, access the action by pressing Ctrl-G or in the menus: Debugger → Go To Time. At the very end of the expression, you should see something like {pc=Y}. Change that to {goto Y}.
Furthermore, if this is a section of code you want to skip every time, consider placing an injection breakpoint. Use K to place a SW_EXECUTE breakpoint at X. Right-click it and choose Set Injection (Emulator). Clear the default and enter goto Y; (mind the semicolon) and press OK. You'll need to invalidate the emulator cache for that to take effect.
@nsadeveloper789 thanks for your help and fast reply :)
I eventually figured out a more invasive way - patching the dynamic listing so that there's an unconditional branch, but I see these injection breakpoints are interesting, I didn't even know they exist.