Как автоматически генерировать трассировку стека при сбое моей программы - PullRequest
531 голосов
/ 17 сентября 2008

Я работаю в Linux с компилятором GCC. Когда моя программа на C ++ падает, я бы хотел, чтобы она автоматически генерировала трассировку стека.

Моя программа запускается многими разными пользователями, а также работает в Linux, Windows и Macintosh (все версии скомпилированы с использованием gcc).

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

Ответы [ 29 ]

9 голосов
/ 06 июля 2016

Забудьте об изменении ваших источников и сделайте несколько хаков с помощью функции backtrace () или макросов - это просто плохие решения.

Как правильно работающее решение, я бы посоветовал:

  1. Скомпилируйте вашу программу с флагом "-g" для встраивания отладочных символов в двоичный файл (не беспокойтесь, это не повлияет на вашу производительность).
  2. В linux выполните следующую команду: "ulimit -c unlimited" - чтобы разрешить системе создавать большие аварийные дампы.
  3. При сбое вашей программы в рабочем каталоге вы увидите файл «core».
  4. Запустите следующую команду, чтобы напечатать обратную трассировку на стандартный вывод: gdb -batch -ex "backtrace" ./your_program_exe ./core

Это напечатает правильную читабельную трассировку вашей программы в удобочитаемом виде (с именами исходных файлов и номерами строк). Более того, этот подход даст вам свободу автоматизировать вашу систему: иметь короткий сценарий, который проверяет, создал ли процесс дамп ядра, а затем отправляет обратные следы разработчикам по электронной почте или регистрирует их в какой-либо системе ведения журналов.

9 голосов
/ 17 сентября 2008

Некоторые версии libc содержат функции, которые имеют дело со следами стека; Вы можете использовать их:

http://www.gnu.org/software/libc/manual/html_node/Backtraces.html

Я помню, как давно использовал libunwind для получения трассировки стека, но это может не поддерживаться на вашей платформе.

8 голосов
/ 17 сентября 2008

победа: как насчет StackWalk64 http://msdn.microsoft.com/en-us/library/ms680650.aspx

8 голосов
/ 17 сентября 2008
ulimit -c unlimited

- системная переменная, которая позволит создать дамп ядра после сбоя вашего приложения. В этом случае неограниченное количество. Ищите файл с именем core в том же каталоге. Убедитесь, что вы скомпилировали свой код с включенной информацией отладки!

привет

8 голосов
/ 01 марта 2013

Вы можете использовать DeathHandler - небольшой класс C ++, который делает все для вас, надежно.

6 голосов
/ 17 сентября 2008

Посмотрите на:

Человек 3 Backtrace

И

#include <exeinfo.h>
int backtrace(void **buffer, int size);

Это расширения GNU.

6 голосов
/ 17 сентября 2008

См. Средство Stack Trace в ACE (ADAPTIVE Communication Environment). Он уже написан для всех основных платформ (и не только). Библиотека лицензирована в стиле BSD, поэтому вы можете даже скопировать / вставить код, если не хотите использовать ACE.

5 голосов
/ 17 сентября 2008

Я могу помочь с версией Linux: можно использовать функции backtrace, backtrace_symbols и backtrace_symbols_fd См. Соответствующие страницы руководства.

4 голосов
/ 20 марта 2014

Я обнаружил, что решение @tgamblin не является полным. Он не может справиться с помощью stackoverflow. Я думаю, потому что по умолчанию обработчик сигнала вызывается с тем же стеком и SIGSEGV брошен дважды. Для защиты вам необходимо зарегистрировать независимый стек для обработчика сигналов.

Вы можете проверить это с помощью кода ниже. По умолчанию обработчик не выполняется. С определенным макросом STACK_OVERFLOW все в порядке.

#include <iostream>
#include <execinfo.h>
#include <signal.h>
#include <stdlib.h>
#include <unistd.h>
#include <string>
#include <cassert>

using namespace std;

//#define STACK_OVERFLOW

#ifdef STACK_OVERFLOW
static char stack_body[64*1024];
static stack_t sigseg_stack;
#endif

static struct sigaction sigseg_handler;

void handler(int sig) {
  cerr << "sig seg fault handler" << endl;
  const int asize = 10;
  void *array[asize];
  size_t size;

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

  // print out all the frames to stderr
  cerr << "stack trace: " << endl;
  backtrace_symbols_fd(array, size, STDERR_FILENO);
  cerr << "resend SIGSEGV to get core dump" << endl;
  signal(sig, SIG_DFL);
  kill(getpid(), sig);
}

void foo() {
  foo();
}

int main(int argc, char **argv) {
#ifdef STACK_OVERFLOW
  sigseg_stack.ss_sp = stack_body;
  sigseg_stack.ss_flags = SS_ONSTACK;
  sigseg_stack.ss_size = sizeof(stack_body);
  assert(!sigaltstack(&sigseg_stack, nullptr));
  sigseg_handler.sa_flags = SA_ONSTACK;
#else
  sigseg_handler.sa_flags = SA_RESTART;  
#endif
  sigseg_handler.sa_handler = &handler;
  assert(!sigaction(SIGSEGV, &sigseg_handler, nullptr));
  cout << "sig action set" << endl;
  foo();
  return 0;
} 
4 голосов
/ 17 сентября 2008

* Никс: Вы можете перехватить SIGSEGV (обычно этот сигнал перед сбоем) и сохранить информацию в файле. (кроме файла ядра, который вы можете использовать для отладки, например, с помощью gdb).

победа: Проверьте это из MSDN.

Вы также можете просмотреть хром-код Google, чтобы увидеть, как он обрабатывает сбои. У него хороший механизм обработки исключений.

...