NR == 1198 { stopme } # Остановиться для отладки, когда число записей == 1198
/* ...оставшаяся часть программы как ранее... */
Затем из GDB мы можем установить контрольную точку на функции С
stopme
и запустить программу
awk
. Когда контрольная точка срабатывает, мы можем затем установить контрольные точки на другие части
gawk
, где, как мы ожидаем, находится действительная проблема.
Методика функции-ловушки полезна сама по себе. Однако, возможность переместить ее на уровень приложения умножает ее полезность, и она сохранила нам бесчисленное число часов отладки при отслеживании непонятных проблем.
15.5. Отладочные инструменты
Помимо GDB и различных ловушек в исходном коде, которые вы используете для общей отладки, имеется ряд полезных пакетов, которые могут помочь обнаружить определенные разновидности
проблем. Поскольку управление динамической памятью является в крупномасштабных программах такой трудной задачей, многие инструменты фокусируются на этой области, часто действуя в качестве замещающих
malloc
и
free
элементов
Имеются коммерческие инструменты, которые делают множество (или все) из тех вещей, что и описываемые нами программы, но не все они доступны для GNU/Linux, а многие довольно дороги. Все пакеты, обсуждающиеся в данном разделе, являются свободно доступными.
15.5.1. Библиотека
dbug
— усовершенствованный
printf
Первым пакетом, который мы исследуем, является библиотека
dbug
. Она основана на идее условно компилируемого отладочного кода, которую мы представили ранее в данной главе, но идет намного дальше, предоставляя сравнительно сложную трассировку времени исполнения и условный вывод отладки. Она реализует многие из описанных нами советов, избавляя вас от хлопот по собственной их реализации.
Библиотека
dbug
, написанная Фредом Фишем (Fred Fish) в начале 1980-х, была с тех пор несколько усовершенствована. Теперь она явным образом является общим достоянием, поэтому ее можно использовать без всяких проблем как в свободном, так и частном программном обеспечении. Она доступна через архив FTP Фреда Фиша [175] как в виде сжатого файла tar, так и в виде архива ZIP. Документация хорошо резюмирует
dbug
:
dbug
является примером внутреннего отладчика. Поскольку она требует внутренней поддержки программы и ее использование не зависит от каких бы то ни было особых возможностей среды исполнения, она всегда доступна и будет выполняться в любом окружении, в котором будет выполняться сама программа. Вдобавок, поскольку это законченный пакет с особым интерфейсом пользователя, все программы, которые ее используют, будут иметь сходные возможности отладки. Это резко контрастирует с другими формами внутренней поддержки, где у каждого разработчика своя собственная, обычно менее квалифицированная, форма внутреннего отладчика...
Пакет
dbug
лишь незначительно снижает скорость выполнения программ, обычно значительно менее 10%, и немного увеличивает их размеры, обычно от 10 до 20%. Определив особый идентификатор препроцессора С, можно снизить оба этих показателя до нуля без необходимости изменений в исходном коде.
Следующий список является кратким изложением возможностей пакета
dbug
. Каждую возможность можно отдельно включать или отключать во время запуска программы, указав соответствующие аргументы командной строки.
• Трассировка исполнения, отображающая уровень потока управления полуграфическим способом с использованием отступов, обозначающих глубину вложения
• Вывод значений всех или любого набора ключевых внутренних переменных.
• Ограничение действий определенным набором указанных функций.
• Ограничение трассировки функций указанной глубиной вложения.
• Пометку каждой выводимой строки названием исходного файла и номером строки.
• Пометку каждой выводимой строки названием текущего процесса.
• Сохранение в стеке или восстановление состояния отладки для обеспечения исполнения со встроенными значениями по умолчанию для отладки.
• Перенаправление потока вывода отладки в стандартный вывод (
stdout
) или указанный файл. По умолчанию поток вывода направляется в стандартную ошибку (
stderr
). Механизм перенаправления полностью независим от обычного перенаправления командной строки, чтобы избежать конфликтов вывода.
175
ftp://ftp.ninemoons.corn/pub/dbug/
— Примеч. автора.
Пакет
dbug
требует от вас использования определенного порядка при написании своего кода. В частности, нужно использовать его макросы при возвращении из функции или вызове
setjmp
и
longjmp
. Нужно добавлять один вызов макроса в качестве первого исполняемого оператора каждой функции и вызвать несколько дополнительных макросов из
main
. Наконец, нужно добавить отладочную опцию командной строки, по соглашению, это
– #
, которая редко используется
в качестве действительной опции, если вообще используется. В обмен на дополнительную работу вы получаете все только что очерченные преимущества. Давайте взглянем на пример в руководстве:
1 #include <stdio.h>
2 #include "dbug.h"
3
4 int
5 main(argc, argv)
6 int argc;
7 char *argv[];
8 {
9 register int result, ix;
10 extern int factorial, atoi;
11
12 DBUG_ENTER("main");
13 DBUG_PROCESS(argv[0]);
14 DBUG_PUSH_ENV("DBUG");
15 for (ix = 1; ix < argc && argv[ix][0] == '-'; ix++) {
Эта программа иллюстрирует большинство важных моментов. Макрос
DBUG_ENTER
(строка 12) должен быть вызван после объявлений переменных и перед любым другим кодом. (Это потому, что он сам объявляет несколько частных переменных. [176] )
176
В C99, который допускает смешивание объявлений переменных с исполняемым кодом, это составляет меньшую проблему, но помните, что этот пакет был разработан для K&R С — Примеч. автора.
Макрос
DBUG_PROCESS
(строка 13) устанавливает имя программы, главным образом, для использования в выводимых библиотекой сообщениях. Этот макрос должен вызываться лишь однажды, из
main
.
Макрос
DBUG_PUSH_ENV
(строка 14) заставляет библиотеку проверить указанную переменную окружения (в данном случае
DBUG
) на предмет управляющей строки (Управляющие строки
dbug
вскоре будут рассмотрены.) Библиотека может, сохранив свое текущее состояние и использовав новое, создавать стек сохраненных состояний. Таким образом, этот макрос помещает в стек сохраненных состояний полученное от данной переменной окружения состояние. В данном примере использован случай, когда макрос создает первоначальное состояние. Если такой переменной окружения нет, ничего не происходит. (В качестве отступления,
DBUG
является довольно общей переменной, возможно,
GAWK_DBUG
было бы лучше [для
gawk
].)
Макрос
DBUG_PUSH
(строка 18) передает значение управляющей строки, полученной из опции командной строки
– #
. (Новый код должен использовать
getopt
или
getopt_long
вместо ручного анализа аргументов.) Таким образом обычно включается режим отладки, но использование переменной окружения предоставляет также дополнительную гибкость.
Макрос
DBUG_PRINT
(строка 23) осуществляет вывод. Второй аргумент использует методику, которую мы описали ранее (см. раздел 15.4.1.1 «Используйте отладочные макросы»), по включению в скобки всего списка аргументов
printf
, делая его простым аргументом, насколько это касается препроцессора С. Обратите внимание, что завершающий символ конца строки в форматирующей строке не указывается; библиотека
dbug
вставляет его за вас.
При печати
dbug
по умолчанию выводит все операторы
DBUG_PRINT
. Первый аргумент является строкой, которая может использоваться для ограничения вывода лишь теми макросами
DBUG_PRINT
, которые используют эту строку.
Наконец, макрос
DBUG_RETURN
(строка 28) используется вместо обычного оператора
return
для возврата значения. Для использования с функциями