Протестировано в Ubuntu 20.04.
1. Включить основные файлы
Во-первых, беги улимит -с
чтобы увидеть максимально допустимый размер основных файлов в вашей системе. В Ubuntu 20.04 для меня мой возвращается 0
, что означает, что основной файл не может быть создан.
улимит --help
показывает значение -с
:
-c максимальный размер создаваемых файлов ядра
Итак, установите разрешенный размер основного файла на неограниченный
, как показано ниже. Обратите внимание, что я думаю, что это применимо только к одному терминалу, в котором вы запускаете это, и я делаю нет думаю, что он сохраняется при перезагрузке, поэтому вам нужно запускать его каждый раз, когда вы хотите, чтобы файлы ядра были созданы, и в каждом терминале, в котором вы хотите, чтобы он работал:
# установить максимальный размер файла дампа ядра на неограниченный
ulimit -c неограниченно
# убедитесь, что теперь он установлен на «неограниченный»
улимит -с
Вот и все! В настоящее время, запустите вашу программу, и если она выйдет из строя и сделает «дамп ядра», она сбросит ядро как основной
файл в тот же каталог, в котором вы находились, когда вызывали исполняемый файл. Имя файла просто «ядро».
2. Просмотрите трассировку в gdb
Вы должны были построить свою программу на C или C++ с включенными символами отладки, чтобы увидеть полезную информацию в файле ядра. Без символов отладки вы можете видеть только адреса вызываемых функций, а не фактические имена или номера строк.
В gcc используйте -ggdb -O0
включить дебуг
символы, оптимизированные для gdb
г
НУ г
еб
уггер. Вы также можете использовать -г -О0
, -g3 -O0
и т. д., но -ggdb -O0
лучший. Нужен ли нам уровень оптимизации 0 (-О0
) за это? Да, да, мы делаем. Смотрите мой ответ здесь: Переполнение стека: в чем разница между -О0
вариант и -Ог
вариант?
Примеры команд сборки и запуска на C и C++: поэтому ваши полные команды сборки и запуска на C или C++ могут выглядеть так:
# Сборка и запуск команды C для "hello_world.c"
gcc -Wall -Wextra -Werror -ggdb -O0 -std=c11 -o hello_world hello_world.c \
&& ./Привет, мир
# C++ команда сборки и запуска для "hello_world.c"
g++ -Wall -Wextra -Werror -ggdb -O0 -std=c++17 -o hello_world hello_world.c \
&& ./Привет, мир
Откройте основной файл в gdb
как это:
Путь gdb/к/моему/исполняемому файлу/к/ядру
Предполагая, что вы только что побежали путь/к/моему/исполняемому файлу
, то основной
файл будет в том же каталоге, в котором вы находились только что, когда ядро было сброшено, поэтому вы можете просто запустить это:
gdb путь/к/моему/исполняемому ядру
В gdb
, просмотрите обратную трассировку (стек вызовов функций во время сбоя) с помощью:
бт
# или (точно такая же команда)
куда
# ИЛИ (для получения более подробной информации, такой как просмотр всех аргументов функций--
# спасибо Питеру Кордесу в комментариях ниже)
полный
# Справку и подробности по gdb см. в:
помогите БТ
# или же
помогите где
ВАЖНЫЙ: когда происходит создание дампа ядра, он НЕ перезаписывает автоматически любые ранее существовавшие основной
файл в вашем текущем каталоге с новым, поэтому вы должны вручную удалить Старый основной
файл с сердечник
ПЕРЕД созданием нового файла ядра при сбое вашей программы, чтобы всегда иметь самый последний файл ядра для анализа.
3. Попробуйте
- В терминале запустите
спать 30
чтобы запустить процесс, спящий на 30 секунд.
- Во время работы нажмите Ctrl + \ для принудительного дампа ядра. Теперь вы увидите
основной
файл в каталоге, в котором вы находитесь.
- Поскольку у нас нет для этого исполняемого файла с символами отладки, мы просто откроем файл ядра в gdb вместо исполняемого файла с символами + файл ядра. Итак, беги
gdb -c ядро
чтобы открыть основной файл, только что созданный принудительным сбоем.
- Вы увидите это. Обратите внимание, что он знает, какую команду вы вызвали (
спать 30
) когда произошел дамп ядра:
Ядро было сгенерировано с помощью `sleep 30'.
Программа завершается сигналом SIGQUIT, Quit.
# 0 0x00007f93ed32d334 в ?? ()
(ГДБ)
- Бег
бт
или же куда
чтобы увидеть обратную связь. Вы увидите это:
(гдб) бт
# 0 0x00007f93ed32d334 в ?? ()
#1 0x000000000000000a в ?? ()
#2 0x00007f93ed2960a5 в ?? ()
#3 0x0000000000000000 в ?? ()
(ГДБ)
- Это адреса функций, вызываемых в стеке вызовов. Если бы у вас были символы отладки, вы бы увидели гораздо больше информации, включая имена функций и номера строк, например (взято из моей программы C):
#10 0x00007fc1152b8ebf в __printf (format=<оптимизированный вывод>) в printf.c:33
#11 0x0000562bca17b3eb в fast_malloc (num_bytes=1024) в src/fast_malloc.c:225
#12 0x0000562bca17bb66 в malloc (num_bytes=1024) в src/fast_malloc.c:496
4. Забудьте о файлах ядра и просто запустите программу непосредственно в gdb!
Как говорит @Peter Cordes в комментариях ниже, вы также можете просто запустить программу непосредственно внутри gdb, позволив ей там рухнуть, поэтому вам не нужно открывать файл ядра постфактум! Он постановил:
Эти команды GDB не относятся к основным файлам, они работают каждый раз, когда вы останавливаетесь в точке останова. Если у вас есть воспроизводимый сбой, часто проще/лучше запустить вашу программу под GDB (например, gdb ./a.out
), поэтому GDB будет иметь процесс в памяти, а не в файле ядра. Основное преимущество в том, что вы можете где-то установить точку останова или наблюдения. перед вещь, которая разбилась, и один шаг, чтобы увидеть, что происходит. Или с помощью средств записи GDB вы сможете шагнуть назад и посмотрите, что привело к сбою, но это может быть ненадежным, медленным и интенсивно использующим память.
Как указано выше, вы должны были скомпилировать свою программу с отладочными символами и с уровнем оптимизации 0, используя -ggdb -O0
. См. полный пример команд сборки и запуска на C и C++ выше.
Теперь запустите программу в gdb:
# Открыть исполняемый файл в gdb
gdb путь/к/моему/исполняемому файлу
# Запустите его (если он все еще падает, вы увидите его крах)
р
# Просмотрите обратную трассировку (стек вызовов)
бт
# Выйти, когда закончите
д
И если вам когда-нибудь понадобится вручную записать обратную трассировку в файл журнала для последующего анализа, вы можете сделать это следующим образом (адаптировано из заметки в моем eRCaGuy_dotfiles репо здесь):
установить файл журнала gdb_log.txt
установить вход в систему
установить команды трассировки на
показать ведение журнала # доказать, что ведение журнала включено
румянец
установить красивую печать на
bt # просмотреть обратную трассировку
отключить выход из системы
show logging # доказать, что ведение журнала отключено
Выполнено! Теперь вы сохранили обратную трассировку gdb в файле "gdb_log.txt".
Использованная литература:
- [ответ, который мне нужен, находится в самом этом вопросе] https://stackoverflow.com/questions/2065912/core-dumped-but-core-file-is-not-in-the-current-directory
- https://stackoverflow.com/questions/5115613/core-dump-file-analysis
- https://stackoverflow.com/questions/8305866/how-do-i-analyze-a-programs-core-dump-file-with-gdb-when-it-has-command-line-pa/30524347#30524347
- [очень полезная информация, в т.ч. в Ctrl + \ трюк, чтобы заставить дамп ядра!] https://unix.stackexchange.com/questions/277331/segmentation-fault-core-dumped-to-where-what-is-it-and-why/409776#409776
- [упоминается в ответе выше] https://unix.stackexchange.com/questions/179998/где-искать-основной-файл-сгенерированный-при-краше-из-линукс-приложения/180004#180004
- [ответ в самом вопросе] Где найти дамп ядра в Ubuntu 16.04LTS?
- [мой ответ] Переполнение стека: в чем разница между
-О0
вариант и -Ог
вариант?
Дополнительное чтение
- [МНЕ ВСЕ ЕЩЕ НУЖНО ИЗУЧИТЬ И ПОПРОБОВАТЬ ЭТО] Как использовать
LD_PRELOAD
с gdb
: https://stackoverflow.com/questions/10448254/how-to-use-gdb-with-ld-preload