I know that:
When installing a SIGSEGV
signal handler with sigaction
and a sa_sigaction
(rather than sa_handler
), the signal handler receives a siginfo_t*
, of which the si_addr
is the address at which the fault occurred.
Using the ucontext_t
we can inspect the values of registers, for example the instruction pointer, albeit not in a platform-independent way (Linux signal handling. How to get address of interrupted instruction?).
My question: can we also know which register caused the fault? Given that we don't have memory-to-memory moves, this should be only one register (after all, there is also only a single si_addr
). Of course I could inspect all registers and search for si_addr
, but there may be more than one match.
I would be perfectly happy with solutions that are not platform-independent.
The load/store address might not be in any single register; it could the result of an addressing mode like [rdi + rax*4 + 100]
or something.
There is no easy solution to print what a full debugger would, other than running your program under a debugger to catch the fault in the first place, like a normal person. Or let it generate a coredump for you to analyze offline, if you need to debug crashes that happened on someone else's system.
The Linux kernel chooses to dump instruction bytes starting at the code address of the fault (or actually somewhat before it for context), and the contents of all registers. Disassembly to see the faulting instruction can be done after the fact, from the crashlog, along with seeing register contents, without needing to include a disassembler in the kernel itself. See What is "Code" in Linux Kernel crash messages? for an example of what Linux does, and of manually picking it apart instead of using decodecode
.