On x86 (either 64-bit or 32-bit) Linux --
for example:
void signal_handler(int) {
// want to know where the program is interrupted ...
}
int main() {
...
signal(SIGALRM, signal_handler);
alarm(5);
...
printf(...); <------- at this point, we trigger signal_handler
...
}
In signal_handler, how can we know we are interrupted at printf in main()?
Use sigaction with SA_SIGINFO set in sa_flags.
Prototype code:
#define _GNU_SOURCE 1 /* To pick up REG_RIP */
#include <stdio.h>
#include <signal.h>
#include <assert.h>
static void
handler(int signo, siginfo_t *info, void *context)
{
const ucontext_t *con = (ucontext_t *)context;
/* I know, never call printf from a signal handler. Meh. */
printf("IP: %lx\n", con->uc_mcontext.gregs[REG_RIP]);
}
int
main(int argc, char *argv[])
{
struct sigaction sa = { };
sa.sa_flags = SA_SIGINFO;
sa.sa_sigaction = handler;
assert(sigaction(SIGINT, &sa, NULL) == 0);
for (;;);
return 0;
}
Run it and hit Ctrl-C. (Use Ctrl-\ to terminate...)
This is for x86_64. For 32-bit x86, use REG_EIP
instead of REG_RIP
.
[edit]
Of course, if you are actually in a library function (like printf
) or a system call (like write
), the RIP/EIP register might point somewhere funny...
You might want to use libunwind to crawl the stack.
Depending on your OS / Platform, it could be in a variety of areas:
- On the current stack a set number of registers deep
- On an/the interrupt stack
- Within some sort of callback associated with your signal routine...
Without having additional info, I don't think we can track this much further. Adding a C/C++ tag to your might generate more responses and views.
In signal_handler, how can we know we are interrupted at printf in main()?
You can't, at least not from a C, C++, or POSIX perspective. Your operating system may provide OS-specific calls that let you poke at the stack. That's more than a bit dubious, though.
With timer-based signals, which instruction triggered the signal is a toss of the coin.
Workaround idea: if there are only a small number of places which can trigger a signal handler or you are only interested in which bigger block it happened you could maintain that in a variable.
entered = 1; // or entered = ENTER_PRINTF1;
printf(....);