Ключевые слова:debug, apache, gdb, (найти похожие документы)
From: Дмитрий Котеров <http://www.dklab.ru>
Date: Mon, 20 Mar 2005 18:21:07 +0000 (UTC)
Subject: Выявление причин падения apache используя gdb
Оригинал: http://www.dklab.ru/chicken/nablas/34.html
Что делать, когда падает Apache (или другой сервер) в Unix
Если ну совсем уж ничего не получается,
прочти, наконец, инструкцию!
Народная мудрость.
Лирическое отступление Набла была написана, т.к. по данному
конкретному вопросу в Интернете довольно мало практических
рекомендаций. Имеется лишь море теории и огромные залежи документации,
а практических советов почти нет. К сожалению, это частый случай в
мире Unix.
Что вы делаете, когда в Windows возникает окно <<Программа выполнила
недопустимую операцию и будет закрыта>>? Тихо материтесь и запускаете
ее опять. А что, если это -- программа <<электронный кошелек>> для
работы с [14]WebMoney, и она вылетает снова и снова, как раз после
того, как вам пришел крупный денежный перевод? Материтесь и
перезапускаете ее, пока ваш словарный запас мата не исчерпается.
Отдаляя, между прочим, шанс заполучить денежки. В перерывах можно
перезагружать компьютер до отказа Reset-а, а толку?..
Что же делать, если вдруг начал <<падать>> один из серверов в Unix и
<<обычные>> средства не помогают?..
Лирическое отступление Ехал <<новый русский>>, и вдруг у него
сломалась машина. Остановился он, смотрит, как баран на новые ворота.
Мимо проезжает второй <<кореш>>, останавливается.
-- Что, братан, машина сломалась?
-- Ага...
-- Э, друг, да тебе повезло, я в этом деле спец!
-- Правда?.. И что делать?
-- Ну, ты ногой по баллону постучи.
-- Уже стучал, не помогает.
-- Ну, а стекло ветровое протирал?
-- Протирал.
-- Ну, блин... Тогда я не знаю...
Между тем, есть реальный шанс все поправить, и, как ни странно, это не
так уж и сложно. Как всегда, шанс дан только тем, кто хорошо знает Си,
остальные могут даже и не беспокоиться -- впрочем, они вряд ли
заметят, что у них что-то упало (из серверов, естественно).
Для простоты предположим, что мы имеем дело с Apache (в дальнейшем --
просто сервер). Симптомы следующие: программа периодически <<падает>>,
а в ее основной директории (или еще где-то, ищите) остается файл core
с каким-то там дампом -- мусор, в общем. Так что поработаем-ка
мусорщиками.
Компиляция в отладочном режиме
Чайник Прежде, чем рвать на себе волосы, внимательно посмотрите, что
пишется в логах сервера. Убедитесь, что Apache действительно "падает"
и при этом создается core-файл. Вам следует точно определиться,
необходимо ли пользоваться советами, приведенными далее, или же
удастся без них обойтись. Незачем стрелять из пушки по воробьям.
Вначале надо убедиться, что сервер собран из исходников. (Если он был
установлен уже откомпилированным, то вам в морг, в морг.) Когда кто-то
хочет выжать максимальную надежность из той или иной программы в Unix,
он компилирует ее вручную. Во-первых, так доступно больше возможностей
по настройке. Во-вторых, всегда можно поправить то, что не нравится --
обычно разбираться в коде не так уж и сложно. Наконец, в-третьих, если
программа <<упадет>>, можно будет понять по исходникам, из-за чего это
произошло - читайте дальше.
Далее идет очень важный момент. Убедитесь, что вы собираете программу
со включенной отладочной информацией. Это несколько увеличивает размер
исполняемых файлов, зато позволяет определить, что произошло с
зависшим или упавшим сервером, не прибегая к помощи чукотского шамана.
Для включения отладочного режима существует ключ -g у gcc --
компилятора Си. Он обычно указывается в файлах Makefile, там, где
задаются флаги компилятора. Например, посмотрим на первые строчки
src/Makefile от Apache:
##
## Apache Makefile, automatically generated by
## Configure script. Hand-edited changes will be
## lost if the Configure script is re-run.
## Sources: - ./Makefile.config (via Configuration.apaci)
## - ./Makefile.tmpl
##
... я тут пропустил пару строк
##
## Inherited Makefile options from Configure script
## (Begin of automatically generated section)
##
SRCDIR=.
EXTRA_CFLAGS=-DRECORD_FORWARD `$(SRCDIR)/apaci`
EXTRA_LDFLAGS=
Видите переменную EXTRA_CFLAGS? Вы найдете ее и в большинстве других
make-файлов. Нетрудно догадаться, что в ней задаются дополнительные
флаги, учитывающиеся при компиляции.
Но подождите править! Прочтите же то, что написано сверху. А там
говорится, что при следующем запуске Configure все ваши изменения
потеряются. Честно говоря, разматывать все зависимости между
скриптами-конфигураторами совершенно не хочется, а потому
воспользуемся [15]Гуглом, запросом [16]apache debug gcc "-g" и первой
же найденной статьей на эту тему, слегка подкорректировав советы в
ней.
Вкратце, чтобы сконфигурировать Apache (да и большинство других
программ, в исходниках которых есть скрипт configure) в отладочном
режиме, воспользуйтесь командой:
(CFLAGS='-g'; export CFLAGS; ./configure параметры)
Чайник Обязательно используйте скобки (так, как написано выше),
иначе переменная CFLAGS <<прилипнет>> к текущему окружению, и любые
программы будут ее видеть даже тогда, когда вы явно ее не проставляете
(так работает команда export). Если же не использовать export, то в
bash скрипт configure почему-то переменную не видит.
Потом, как обычно, make и make install.
Работа с отладчиком GDB
Дальше начинается самое интересное. Будем считать, что у нас <<глючит>> Apache,
установленный в директорию /usr/local/apache -- при падении создается файл core
в этой директории.
Устанавливаем отладчик GNU Debugger (в простонародье -- GDB). Поищите в Гугле,
скачайте и установите самую новую версию, если ее у вас еще нет. Если у вас
Linux, можете взять отладчик в виде RPM-пакета, это даже проще.
Чайник: Подробная документация GDB на русском языке есть по адресу
http://www.opennet.dev/docs/RUS/gdb/gdb_toc.html.
Вначале останавливаем сервер (иначе core может затереться). Затем
переходим в директорию /usr/local/apache и создаем там файл (например,
gdb.cmd), в котором укажем директории с исходниками Apache. Иначе GDB
не сможет работать в режиме просмотра исходников. Пример файла
gdb.cmd:
directory /usr/src/apache/src
directory /usr/src/apache/src/modules
directory /usr/src/apache/src/modules/standard
directory /usr/src/apache/src/modules/extra
В общем, чем больше там директорий, тем лучше. Ну а дальше запускаем
команду:
gdb -x gdb.cmd ./bin/httpd ./core
Это заставляет GDB исследовать файл ./core, загрузив предварительно
исполняемый файл ./bin/httpd в память.
GDB автоматически останавливается в том месте, где произошла ошибка и
был создан файл core. Поэтому набираем bt, чтобы вывести на экран стек
вызовов функций. Таким образом, сразу видно, в какой подпрограмме
возникла проблема.
Чтобы показать исходный код программы в текущем месте, набираем list.
Печатается текущая строчка, обрамленная несколькими предыдущими и
следующими строками программы.
Если нас интересует значение какой-нибудь переменной (локальной или
глобальной) в программе, мы можем его вывести при помощи команды print
имя_переменной. Удобно то, что GDB позволяет печатать значения не
только простых переменных, но и структур, массивов и т. д. Можно даже
вычислить какое-нибудь выражение, составленное по правилам языка Си.
Наконец, можно <<путешествовать>> по переву вызовов функций, делая
текущей то одну, то другую. Для этого существуют, соответственно,
команды up (вверх по дереву до конечной функции) и down (вниз по
дереву в сторону вызывающей функции).
Для выхода из отладчика введите команду q, а для просмотра помощи по
командам -- help.
Определение причины <<зависания>> программы
Теперь, когда вы поняли, что не так все и сложно, буду краток. Если некоторый
сервер <<завис>>, вы можете посмотреть, в каком месте программы он в данный
момент <<крутится>>. Для этого используется команда:
gdb bin/httpd 1234
Здесь bin/httpd -- как обычно, путь к исполняемому файлу, а 1234 --
идентификатор процесса (PID), который <<завис>>. Дальше можно
пользоваться командами: next (выполнить следующую команду), step
(выполнить следующую команду и, возможно, войти внутрь функции), break
file:func (установить точку останова внутри функции func,
расположенной в файле file) и, наконец, c (продолжить выполнение до
следующей точки останова).
Чайник: Подробности, а также описание других полезных команд, читайте
в документации GDB или по адресу
http://www.opennet.dev/docs/RUS/gdb/gdb_toc.html.Краткая сводка полезных команд GDB
bt
Вывод стека вызовов на момент ошибки, очень удобно!
up
Сделать текущим предыдущий фрейм вызова функции.
down
Сделать текущим следующий фрейм.
list
Показать ИСХОДНЫЙ КОД в текущем месте.
print expr
Печать значения выражения expr. Выражение пишется НА СИ, можно
просматривать даже структуры целиком, использовать имена
переменных и т. д.
q
Выход из отладчика.
help
Вывод справки по категориям команд. Напоминаю, что подробная
документация есть по адресу
[19]http://www.opennet.dev/docs/RUS/gdb/gdb_toc.html.
next
Выполнить следующую команду.
step
Выполнить следующую команду и, возможно, войти внутрь функции.
break file:func
Установить точку останова внутри функции func, расположенной в
файле file. Если вызвана без параметров, устанавливает точку
останова в текущем месте.
c
Продолжить выполнение до следующей точки останова.
Распространенные ошибки
Если однажды GDB по команде list вместо строчки из программы выведет
какую-нибудь белиберду (обычно там идет речь про какой-то eval.c), не
отчаивайтесь. Возможные причины ошибки:
* Вы забыли какую-то из директорий с исходниками. Чтобы учесть их
все, воспользуйтесь, например, такой командой:
find /usr/src/apache -name Makefile
Я, например, написал для себя следующий скрипт запуска GDB -- он
сам определяет нужные директории:
# http://www.opennet.dev/docs/RUS/gdb/gdb_toc.html
BIN=bin/httpd
ROOT=/usr/src/apache
CONFIG=gdb.cnf.auto
find $ROOT -name Makefile \
-printf "directory %h\n" > $CONFIG
gdb -x $CONFIG $BIN core
rm -f $CONFIG
* Вы не откомпилировали тот или иной модуль в отладочном режиме.
Проверьте, использовался ли ключ -g при его компиляции --
исследуйте вывод команды make.
* Возможно, проблема в действительности в PHP (если он у вас
установлен в виде модуля), а вовсе даже и не в Apache. Так что вам
также придется откомпилировать в отладочном режиме и PHP.