Назад | Перейти на главную страницу

Можете ли вы заставить любую программу в Linux распечатать трассировку стека в случае отказа?

Если я запускаю программу из оболочки, и она перестает работать:

$ buggy_program
Segmentation fault

Однако он скажет мне, есть ли способ заставить программы печатать обратную трассировку, возможно, запустив что-то вроде этого:

$ print_backtrace_if_segfault buggy_program
Segfault in main.c:35
(rest of the backtrace)

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

Может быть способ получше, но он автоматизирует его.

Поместите следующее в ~/backtrace:

backtrace
quit

Поместите это в сценарий под названием seg_wrapper.sh в каталоге на вашем пути:

#!/bin/bash
ulimit -c unlimited
"$@"
if [[ $? -eq 139 ]]; then
    gdb -q $1 core -x ~/backtrace
fi

В ulimit команда делает так, чтобы ядро ​​выгружалось. "$@" - аргументы, передаваемые сценарию, то есть ваша программа и ее аргументы. $? содержит статус выхода, 139, кажется, является статусом выхода по умолчанию для моей машины для segfault.

Для gdb, -q означает тихо (нет вступительного сообщения), и -x говорит gdb выполнять команды в данном ему файле.

использование

Итак, чтобы использовать его, вы просто:

seg_wrapper.sh ./mycommand and its arguments 

Обновить

Вы также можете написать обработчик сигнала, который сделает это, см. эта ссылка.

Извини, что зашел сюда 2 года спустя ... наткнулся на что-то еще. Добавляем это для полноты картины.

1) Хотя я считаю принятый ответ отличным, для него требуется gdb. Знакомый мне метод использует libSegFault.so.

Если вы запустите свое приложение с

LD_PRELOAD = ... путь к ... / libSegFault.so myapp

Вы получите отчет с обратной трассировкой, загруженными библиотеками и т. Д.

2) Скрипт-оболочка catchsegv также доступен, который пытается использовать addr2line для преобразования адресов в имя файла + номер строки.

Это гораздо более легкие решения, чем файлы ядра или gdb (например, подходят для встроенных систем)

Вам нужен друг GDB

gdb <program> [core file]

После того, как вы загрузили свой corefile, команда backtrace (может быть сокращена до bt) предоставит вам текущий стек вызовов. Если вы запустите свою программу изнутри gdb, вы можете установить произвольные точки останова, проверить содержимое памяти и т. Д.

catchsegv

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

Хорошая запись существует Вот.

Вы можете включить его в свои собственные скрипты по своему усмотрению.

Ubuntu (как проект) использует для этого Apport. Вы можете посмотреть, как они это сделали.

https://wiki.ubuntu.com/Apport

Вот немного измененный вариант сценария от Кайла Брандта. Его улучшают следующими способами:

  • не требуют ручного взаимодействия, если трассировка стека длинная
  • некоторые дампы сохраняются с именем pattern core., соблюдайте этот параметр
  • не требуют явного командного файла для gdb (он создаст временный)
  • подождите фоновых заданий

Сценарий:

#!/bin/bash
gdbcommandfile=$(tempfile)
usepid=$(cat /proc/sys/kernel/core_uses_pid)
printf "set pagination off\nbacktrace\nquit\n" > $gdbcommandfile
ulimit -c unlimited
"$@"&
pid=$!
wait $!
if [[ $? -eq 139 ]]; then
    if [[ $usepid == 1 ]]; then 
        gdb -q $1 core.$pid -x $gdbcommandfile
    else
        gdb -q $1 core -x $gdbcommandfile
    fi
fi
rm $gdbcommandfile