在x86(64位或32位)Linux上 - 例如:
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
...
}
在signal_handler中,我们怎么知道我们在main()的printf中被中断?
答案 0 :(得分:11)
将sigaction与sa_flags中设置的SA_SIGINFO一起使用。
原型代码:
#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;
}
运行它并按 Ctrl-C 。 (使用 Ctrl - \ 终止...)
这适用于x86_64。对于32位x86,请使用REG_EIP
代替REG_RIP
。
[编辑]
当然,如果你实际上是在库函数(如printf
)或系统调用(如write
)中,那么RIP / EIP寄存器可能指向某个有趣的地方...
您可能希望使用libunwind来抓取堆栈。
答案 1 :(得分:1)
根据您的操作系统/平台,它可能位于以下各个方面:
如果没有其他信息,我认为我们无法进一步追踪这些信息。添加C / C ++标记可能会产生更多响应和视图。
答案 2 :(得分:1)
在signal_handler中,我们怎么知道main()中的printf中断了? 你不能,至少不是从C,C ++或POSIX的角度来看。您的操作系统可能会提供特定于操作系统的调用,以便您在堆栈中查找。不过,这有点可疑。
使用基于定时器的信号,哪个指令触发信号就是硬币的折腾。
答案 3 :(得分:0)
解决方法的想法:如果只有少数几个地方可以触发信号处理程序,或者你只对它发生的更大块感兴趣,你可以将它保存在一个变量中。
entered = 1; // or entered = ENTER_PRINTF1;
printf(....);