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

放肆的年华 提交于 2019-12-09 09:46:53

问题


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


回答1:


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.




回答2:


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.




回答3:


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.




回答4:


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(....);


来源:https://stackoverflow.com/questions/6768426/in-a-signal-handler-how-to-know-where-the-program-is-interrupted

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!