Недавно по работе мне пришлось анализировать core-dump, сброшенный процессом httpd. Поиск нужных команд для gdb занял некоторое время. Для того, чтобы сэкономить время другим, напишу о своем опыте. Итак, мы открыли с помощью GDB core-dump:
gdb /path/to/binary --core /path/to/core_file |
Httpd – многопоточное приложение. Если сделать backtrace для основного потока, скорее всего ничего страшного не увидишь — он будет вертеться где-то в __kernel_vsyscal и не будет делать ничего достойного генерации core-dump-а Поэтому нам нужно сделать backtrace всех потоков с помощью команды:
thread apply all bt |
Для того, чтобы вывести это все в отдельный файл, можно воспользоваться командами:
set pagination off set logging file ./threads.txt set logging on thread apply all bt set logging off |
Если корок много или просто есть необходимость использовать shell, пригодится команда:
gdb /path/to/binary /path/to/core_file --batch --quiet -ex "thread apply all bt full" / -ex "quit" > output_file |
В файле, куда Вы перенаправили вывод трейсов, найти нужный поток можно по строке «sig_». В моем случае причина сброса корки оказалось в том, что через прокси была запрошена страница весом 42 Мегабайта: http://compamal.happy.nu/blog/sakai.php?itemid=540 Сейчас она весит уже 55 Мегабайт — спам-боты трудятся 🙂 В общем-то это не рекорд, в других корках были ссылки на страницы и побольше. Рекорд — 450 Мегабайт, но это страница уже недоступна. В общем, не открывайте на своем прокси анонимный доступ.
Переходим к разбору нужного потока:
thread 177 |
выбираем фрейм:
frame 5 |
Выводим локальные переменные:
info locals |
или аргументы функции:
info args |
В моем случае нужный аргумент (буфер длиной 42 Мегабайта) был объявлен как void* buffer Для того, чтобы вывести его в файл, можно воспользоваться командами:
set pagination off set logging file ./buffer.txt set print elements 0 set logging on p (char*) buffer set logging off |