Рейтинг:12

Где найти файлы дампа ядра и как просмотреть и проанализировать обратную трассировку (трассировку стека) в одном из них?

флаг cn

Когда я запускаю свою программу C в Ubuntu 20.04, я получаю эту ошибку времени выполнения:

Ошибка сегментации (дамп ядра)

Мне очень нужно найти и просмотреть основной файл, но нигде не могу его найти. Где он и как посмотреть в нем бэктрейс?

Рейтинг:17
флаг cn

Протестировано в 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. Попробуйте

  1. В терминале запустите спать 30 чтобы запустить процесс, спящий на 30 секунд.
  2. Во время работы нажмите Ctrl + \ для принудительного дампа ядра. Теперь вы увидите основной файл в каталоге, в котором вы находитесь.
  3. Поскольку у нас нет для этого исполняемого файла с символами отладки, мы просто откроем файл ядра в gdb вместо исполняемого файла с символами + файл ядра. Итак, беги gdb -c ядро чтобы открыть основной файл, только что созданный принудительным сбоем.
  4. Вы увидите это. Обратите внимание, что он знает, какую команду вы вызвали (спать 30) когда произошел дамп ядра:
    Ядро было сгенерировано с помощью `sleep 30'.
    Программа завершается сигналом SIGQUIT, Quit.
    # 0 0x00007f93ed32d334 в ?? ()
    (ГДБ) 
    
  5. Бег бт или же куда чтобы увидеть обратную связь. Вы увидите это:
    (гдб) бт
    # 0 0x00007f93ed32d334 в ?? ()
    #1 0x000000000000000a в ?? ()
    #2 0x00007f93ed2960a5 в ?? ()
    #3 0x0000000000000000 в ?? ()
    (ГДБ)
    
  6. Это адреса функций, вызываемых в стеке вызовов. Если бы у вас были символы отладки, вы бы увидели гораздо больше информации, включая имена функций и номера строк, например (взято из моей программы 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".

Использованная литература:

  1. [ответ, который мне нужен, находится в самом этом вопросе] https://stackoverflow.com/questions/2065912/core-dumped-but-core-file-is-not-in-the-current-directory
  2. https://stackoverflow.com/questions/5115613/core-dump-file-analysis
  3. https://stackoverflow.com/questions/8305866/how-do-i-analyze-a-programs-core-dump-file-with-gdb-when-it-has-command-line-pa/30524347#30524347
  4. [очень полезная информация, в т.ч. в Ctrl + \ трюк, чтобы заставить дамп ядра!] https://unix.stackexchange.com/questions/277331/segmentation-fault-core-dumped-to-where-what-is-it-and-why/409776#409776
  5. [упоминается в ответе выше] https://unix.stackexchange.com/questions/179998/где-искать-основной-файл-сгенерированный-при-краше-из-линукс-приложения/180004#180004
  6. [ответ в самом вопросе] Где найти дамп ядра в Ubuntu 16.04LTS?
  7. [мой ответ] Переполнение стека: в чем разница между -О0 вариант и -Ог вариант?

Дополнительное чтение

  1. [МНЕ ВСЕ ЕЩЕ НУЖНО ИЗУЧИТЬ И ПОПРОБОВАТЬ ЭТО] Как использовать LD_PRELOAD с gdb: https://stackoverflow.com/questions/10448254/how-to-use-gdb-with-ld-preload
Peter Cordes avatar
флаг fr
Если у вас есть символы отладки, `bt full` подойдет: показывает аргументы и прочее. Или даже `thread apply all bt full` для многопоточной программы. (Хотя это больше, чем вы обычно хотели бы просмотреть сразу, поэтому это полезно для отправки отчета об ошибке больше, чем для вашего собственного использования.)
Gabriel Staples avatar
флаг cn
@PeterCordes, спасибо. Я также добавил примечание о «bt full» в ответ. Я новичок в изучении дампов ядра. Написание этого ответа вчера было моим первым разом, когда я видел «основной» файл, и моим первым разом, когда я делал обратную трассировку для него.
Peter Cordes avatar
флаг fr
Эти команды GDB не относятся к основным файлам, они работают каждый раз, когда вы останавливаетесь в точке останова. Если у вас есть воспроизводимый сбой, часто проще / лучше запустить вашу программу под GDB (например, `gdb ./a.out`), чтобы GDB имел процесс в памяти, а не в файле ядра. Основное преимущество заключается в том, что вы можете установить точку останова или точку наблюдения где-то *до* того, что потерпело крах, и пошагово посмотреть, что происходит. Или с помощью средств записи GDB вы можете сделать шаг *назад* и посмотреть, что привело к сбою, но это может быть ненадежным, медленным и интенсивно использующим память.
Рейтинг:1
флаг cn

Нашел через поиск. Я использую Ubuntu Mate 21.10. Для тех, кто использует последнюю версию Ubuntu, аппорт будет генерировать дампы в /var/lib/apport/coredump.

Если вы не можете найти файл дампа ядра, кот /var/log/apport.log. Когда я это сделал, я увидел:

исполняемый файл не принадлежит пакету, игнорируя
вызывается для pid 5545, сигнал 11, предел ядра 0, режим дампа 1

Обратите внимание на ограничение ядра 0, это означает, что файл дампа ядра не будет создан. Итак, я выполнил команду, показанную в этом посте (ulimit -c неограниченно), и на этот раз apport.log показал это:

запись дампа ядра в core._my_prog.1000.e43b2f33-4708-438c-a7d7-05062f381382.5650.795448 (ограничение: -1)

Я не смог найти это в текущем каталоге или каталоге, содержащем исполняемый файл, поэтому я провел поиск по всей системе и нашел его в /var/lib/apport/coredump.

Ответить или комментировать

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