В обработчике сигналов, как узнать, где программа прерывается? - PullRequest
11 голосов
/ 21 июля 2011

В 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, как мы можем узнать, что нас прерывают при printf в main ()?

Ответы [ 4 ]

11 голосов
/ 21 июля 2011

Используйте sigaction с SA_SIGINFO, установленным в sa_flags.

Код прототипа:

#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.

[edit]

Конечно, если вы на самом деле находитесь в библиотечной функции (например, printf) илисистемный вызов (например, write), регистр RIP / EIP может указывать на что-то смешное ...

Возможно, вы захотите использовать libunwind для сканирования стека.

1 голос
/ 21 июля 2011

В signal_handler, как мы можем узнать, что нас прерывают в printf в main ()?Вы не можете, по крайней мере, не с точки зрения C, C ++ или POSIX.Ваша операционная система может предоставлять специфичные для ОС вызовы, которые позволяют вам совать в стек.Хотя это более чем сомнительно.

С сигналами на основе таймера, инструкция которых вызвала сигнал, бросается монетой.

1 голос
/ 21 июля 2011

В зависимости от вашей ОС / платформы, это может быть в различных областях:

  • В текущем стеке задано количество глубоких регистров
  • В стеке прерываний
  • В рамках своего рода обратного вызова, связанного с вашей подпрограммой сигнала ...

Не имея дополнительной информации, я не думаю, что мы сможем отследить это намного дальше. Добавление тэга C / C ++ может привести к большему количеству откликов и просмотров.

0 голосов
/ 21 июля 2011

Идея обходного пути: если существует только небольшое количество мест, которые могут вызвать обработчик сигнала, или вас интересует только, какой больший блок произошел, вы можете сохранить его в переменной.

entered = 1; // or entered = ENTER_PRINTF1;
printf(....);
...