Development:Debugging FEX with Signals
Signals and you
FEX uses signals in quite a few ways that may cause debugging to be a bit of a pain. This is necessary for correct operation so it is an evil we must live with.
Signals that FEX uses
- SIGBUS - The AArch64 JIT generates unaligned loadstore instructions then captures and backpatches these when they fault
- This is necessary for emulating x86-TSO on AArch64 and can't be dropped without massive performance loses
- SIGILL - All of the CPU backends generate this fault and is necessary for the emulator to return from a guest signal
- Going in to a signal happens frequently, gdb will usually ignore the entry when it is SIGALRM or SIGUSR*
- We could choose a different signal, but this one can be generated in one instruction which makes it nice to use
- Using a signal to punch back through to the guest return path is necessary since we need to save and restore guest registers when guest signals occur.
- SIG63 - We use this for various ancillary functions
- This signal currently tells a thread that it should stop running, to pause its execution, or to resume from its paused frame
- This is another necessary signal since if we want to safely shutdown the emulator and a thread is in a syscall, there is no way for it to leave without a signal.
- The stop signal specifically will have the CPU backend long jump from the signal handler to the exit stage of the ASM dispatcher for safe shutdown
- This slightly increases performance because then there aren't atomic checks per iteration of the execution loop for if we should stop executing
Debugging FEX
Read more here Development:Debugging_Crash
First thing you'll want to do is enable building FEX with JITSymbols. `-DENABLE_JITSYMBOLS=True` added to cmake.
This will give you some symbols when capturing FEX with `perf top`
Next is when debugging FEX under GDB is to ignore the signals that FEX will be generating. With gdb this is as follows
- handle SIGBUS SIGILL SIG63 noprint
If you're debugging under lldb then the syntax is a bit more hurtful and you must first run the application before passing these.
- pro hand -s no -n no SIGBUS SIGILL SIGRTMAX-1
At this point it becomes the typical problem of debugging JIT based applications, which is painful and usually involves throwing `printf` everywhere
Debugging the guest application
When FEX is started with the -G argument it will open a gdbstub socket listening on port 8086. This can be connected to with gdbserver, ida, ghidra, or binary ninja.
This is currently only useful for inspection, gdbstub doesn't yet send guest signals over through gdbstub!