Сведения о вопросе

Henry

08:26, 29th August, 2020

Теги

linux   unix   stack-trace   sigsegv    

Получение трассировок стека в системах Unix, автоматически

Просмотров: 474   Ответов: 4

Какие существуют методы автоматического получения стека trace в системах Unix? Я имею в виду не просто получение основного файла или Интерактивное подключение с помощью GDB, а наличие обработчика SIGSEGV, который сбрасывает обратную трассировку в текстовый файл.

Бонусные баллы за следующие дополнительные функции:

  • Сбор дополнительной информации во время аварии (например. конфигурационный файл).
  • Email информация о сбое bundle для разработчиков.
  • Возможность добавить это в общую библиотеку dlopen ed
  • Не требуется GUI



  Сведения об ответе

appple

02:03, 20th August, 2020

К ВАШЕМУ СВЕДЕНИЮ,

предложенное решение (использование backtrace_symbols в обработчике сигналов) опасно нарушено. НЕ ИСПОЛЬЗУЙТЕ ЕГО -

Да, backtrace и backtrace_symbols будут создавать backtrace и переводить его в символьные имена, однако:

  1. backtrace_symbols выделяет память, используя malloc, и вы используете free, чтобы освободить ее - если вы терпите крах из-за повреждения памяти, ваша malloc Арена, скорее всего, будет повреждена и вызовет двойную ошибку.

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

  3. Вы используете puts, который использует стандартный поток, который также защищен блокировкой. Если вы ошиблись в середине printf, вы снова окажетесь в тупике.

  4. На 32-битных платформах (например ваш обычный PC 2 года назад), то kernel будет помещать обратный адрес к внутренней функции glibc вместо вашей функции сбоя в вашем стеке, так что единственная наиболее важная часть информации, которая вас интересует - в какой функции произошла ошибка программы, На самом деле будет повреждена на этой платформе.

Таким образом, код в этом примере является наихудшим видом ошибки-он LOOKS как будто работает, но он действительно будет подводить вас неожиданными способами в производстве.

BTW, заинтересованы в том, чтобы сделать это правильно? проверить это.

Овации, Гилад.


  Сведения об ответе

ASER

16:13, 5th August, 2020

Если вы находитесь на системах с доступной функциональностью BSD backtrace (Linux, OSX 1.5, BSD, конечно), вы можете сделать это программно в своем обработчике сигналов.

Например (код backtrace , полученный из примера IBM ):

#include <execinfo.h>
#include <signal.h>
#include <stdio.h>
#include <stdlib.h>

void sig_handler(int sig)
{
    void * array[25];
    int nSize = backtrace(array, 25);
    char ** symbols = backtrace_symbols(array, nSize);

    for (int i = 0; i < nSize; i++)
    {
        puts(symbols[i]);;
    }

    free(symbols);

    signal(sig, &sig_handler);
}

void h()
{
    kill(0, SIGSEGV);
}

void g()
{
    h();
}

void f()
{
    g();
}

int main(int argc, char ** argv)
{
    signal(SIGSEGV, &sig_handler);
    f();
}

Выход:

0   a.out                               0x00001f2d sig_handler + 35
1   libSystem.B.dylib                   0x95f8f09b _sigtramp + 43
2   ???                                 0xffffffff 0x0 + 4294967295
3   a.out                               0x00001fb1 h + 26
4   a.out                               0x00001fbe g + 11
5   a.out                               0x00001fcb f + 11
6   a.out                               0x00001ff5 main + 40
7   a.out                               0x00001ede start + 54

Это не дает бонусных баллов за дополнительные функции (за исключением того, что не требует GUI), однако у него есть преимущество в том, что он очень прост и не требует никаких дополнительных библиотек или программ.


  Сведения об ответе

DO__IT

00:39, 27th August, 2020

Вот пример того, как получить дополнительную информацию с помощью деманглера. Как вы можете видеть, этот также записывает stacktrace в файл.

#include <iostream>
#include <sstream>
#include <string>
#include <fstream>
#include <cxxabi.h>

void sig_handler(int sig)
{
    std::stringstream stream;
    void * array[25];
    int nSize = backtrace(array, 25);
    char ** symbols = backtrace_symbols(array, nSize);
    for (unsigned int i = 0; i < size; i++) {
        int status;
        char *realname;
        std::string current = symbols[i];
        size_t start = current.find("(");
        size_t end = current.find("+");
        realname = NULL;
        if (start != std::string::npos && end != std::string::npos) {
            std::string symbol = current.substr(start+1, end-start-1);
            realname = abi::__cxa_demangle(symbol.c_str(), 0, 0, &status);
        }
        if (realname != NULL)
            stream << realname << std::endl;
        else
            stream << symbols[i] << std::endl;
        free(realname);
    }
    free(symbols);
    std::cerr << stream.str();
    std::ofstream file("/tmp/error.log");
    if (file.is_open()) {
        if (file.good())
            file << stream.str();
        file.close();
    }
    signal(sig, &sig_handler);
}


  Сведения об ответе

KOMP

08:43, 5th August, 2020

Решение Dereks, вероятно, самое лучшее, но вот альтернатива в любом случае:

Последние версии Linux kernel позволяют передавать дампы ядра в сценарий или программу. Вы можете написать сценарий, чтобы поймать дамп ядра, собрать любую дополнительную информацию, которая вам нужна,и отправить все обратно. Однако это глобальная настройка, поэтому она будет применяться к любой аварийной программе в системе. Для его настройки Также потребуются права суперпользователя. Его можно настроить через файл /proc/sys/kernel/core_pattern. Установите это на что-то вроде '| /home/myuser/bin/my-core-handler-script'.

Ubuntu человек также используют эту функцию.


Ответить на вопрос

Чтобы ответить на вопрос вам нужно войти в систему или зарегистрироваться