backtrace_symbols не может распечатать саму функцию, которая вызвала сигнал

Я реализую простой регистратор сбоев для моего приложения C ++:

static void handler(int, siginfo_t * info, void *) {
void *array[1000];

switch (info->si_signo) {
case SIGILL:
Logger() << "Received SIGILL";
break;
case SIGSEGV:
Logger() << "Received SIGSEGV";
break;
case SIGBUS:
Logger() << "Received SIGBUS";
break;
case SIGSYS:
Logger() << "Received SIGSYS";
break;
default:
break;
}

// get void*'s for all entries on the stack
const size_t size = backtrace(array, 1000);

// print out all the frames
char ** symbols = backtrace_symbols(array, size);
for(size_t i = 0; i < size; ++i)
{
Logger() << symbols[i];
}

free(symbols);
exit(EXIT_FAILURE);
}

struct sigaction SignalAction;
SignalAction.sa_flags = SA_SIGINFO;
SignalAction.sa_sigaction = handler;
sigemptyset(&SignalAction.sa_mask);
sigaction(SIGSEGV, &SignalAction, NULL);
sigaction(SIGBUS, &SignalAction, NULL);
sigaction(SIGILL, &SignalAction, NULL);

Я еще не тестировал его в Linux, но в OS X конкретный элемент трассировки, который меня интересует, тот, который вызвал сигнал, не печать (запись № 2):

: " Received SIGSEGV": " 0   App                       0x0000000100253d15 _ZL7handleriP9__siginfoPv + 229": " 1   libsystem_platform.dylib  0x00007fff8ff0f5aa _sigtramp + 26": " 2   ???                       0x000000000000000c 0x0 + 12": " 3   App                       0x000000010000dfa7 _ZN11CMainWindow13initShortcutsEv + 231": " 4   App                       0x000000010000d059 _ZN11CMainWindowC2EP7QWidget + 1001": " 5   App                       0x00000001000091d9 main + 6217": " 6   App                       0x00000001000070a5 _start + 227": " 7   App                       0x0000000100006fc1 start + 33"

Почему это происходит, и могу ли я это исправить?

P. S. Это отладочная сборка. Там не было никакого реального segfault, он был смоделирован с raise(SIGSEGV), raise был вызван из метода, который, в свою очередь, был вызван из MainWindow::initShortcuts,

3

Решение

Запись № 2 имеет совершенно особый адрес. Это 0x000000000000000c, и вы должны знать, что есть таблица описания прерываний. В соответствии с http://en.wikipedia.org/wiki/Interrupt_Descriptor_Table это может быть ошибка стека.

Однако, как указал Кен, делать то, что ты делаешь, плохо. Это все равно что пытаться вспомнить номер автомобиля, который ударил тебя, когда ты разрывал аорту. Вы можете сделать это, но для чего?

Может быть, вместо того, чтобы сделать это, попробуйте научиться использовать Strace http://en.wikipedia.org/wiki/Strace.

3

Другие решения

Идея создания аварийного регистратора с обработчиком сигналов в корне ошибочна. Из раздела «ПРИМЕЧАНИЕ» страница руководства sigaction:

Следующие функции либо реентерабельны, либо не прерываются
сигналы и безопасны для асинхронного сигнала. Поэтому приложения могут вызывать
их, без ограничений, из функций улавливания сигналов:

[… Список безопасных функций асинхронного сигнала опущен…]

Все функции, отсутствующие в приведенных выше списках, считаются небезопасными
уважение к сигналам. То есть поведение таких функций
при вызове из обработчика сигнала не определено. В общем, хотя,
обработчики сигналов должны делать немного больше, чем устанавливать флаг; большинство других
действия не являются безопасными.

Ни один из backtrace(), backtrace_symbols(), free(), или же exit() безопасно вызывать в обработчике сигнала. Почти наверняка, вещи в вашем Logger или же operator<< тоже небезопасно.

Относительно того, почему вызывающая сигнал функция не находится в обратном следе, это, очевидно, связано с тем, как ядро ​​устанавливает контекст обработчика сигналов. Обратный след получается путем изучения стековых фреймов, созданных операторами вызова и прологами функций. Обработчик сигнала не вызывается как обычный вызов функции, поэтому нет особой причины ожидать, что цепочка кадров стека будет настроена правильно.

Фактически, обработчики сигналов могут работать в совершенно другом стеке, чем обычный код. Увидеть sigaltstack().

4

По вопросам рекламы [email protected]