Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

In a signal handler, how to know where the program is interrupted?

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()?

like image 975
flyingbin Avatar asked Jul 20 '11 20:07

flyingbin


People also ask

Can signal handler be interrupted?

The signal handler can indeed be interrupted by another signal (assuming it isn't the same signal as the one which invoked the handler in the first place). your handler can still be interrupted by delivery of another kind of signal.

What is signal interrupt?

An interrupt is a signal emitted by a device attached to a computer or from a program within the computer. It requires the operating system (OS) to stop and figure out what to do next. An interrupt temporarily stops or terminates a service or a current process.

What do you know about signal handler of a process?

A signal handler is a function which is called by the target environment when the corresponding signal occurs. The target environment suspends execution of the program until the signal handler returns or calls longjmp() . Signal handlers can be set with signal() or sigaction() .


1 Answers

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.

like image 52
Nemo Avatar answered Oct 13 '22 09:10

Nemo