Категории
Самые читаемые
PochitayKnigi » Компьютеры и Интернет » Программное обеспечение » Linux программирование в примерах - Арнольд Роббинс

Linux программирование в примерах - Арнольд Роббинс

Читать онлайн Linux программирование в примерах - Арнольд Роббинс

Шрифт:

-
+

Интервал:

-
+

Закладка:

Сделать
1 ... 143 144 145 146 147 148 149 150 151 ... 165
Перейти на страницу:

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). Механизм перенаправления полностью независим от обычного перенаправления командной строки, чтобы избежать конфликтов вывода.

Пакет 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++) {

16   switch (argv[ix][1]) {

17   case '#':

18    DBUG_PUSH(&(argv[ix][2]));

19    break;

20   }

21  }

22  for (; ix < argc; ix++) {

23   DBUG_PRINT("args", ("argv[%d] = %s", ix, argv[ix]));

24   result = factorial(atoi(argv(ixj));

25   printf("%dn", result);

26   fflush(stdout);

27  }

28  DBUG_RETURN(0);

29 }

Эта программа иллюстрирует большинство важных моментов. Макрос DBUG_ENTER() (строка 12) должен быть вызван после объявлений переменных и перед любым другим кодом. (Это потому, что он сам объявляет несколько частных переменных.[176])

Макрос 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 для возврата значения. Для использования с функциями void имеется соответствующий макрос DBUG_VOID_RETURN.

Оставшаяся часть программы заполнена функцией factorial():

1  #include <stdio.h>

2  #include "dbug.h"

3

4  int factorial (value)

5  register int value;

6  {

7   DBUG_ENTER("factorial");

8   DBUG_PRINT("find", ("find %d factorial", value));

9   if (value > 1) {

10   value *= factorial(value — 1);

11  }

12  DBUG_PRINT("result", ("result is %d", value));

1 ... 143 144 145 146 147 148 149 150 151 ... 165
Перейти на страницу:
Тут вы можете бесплатно читать книгу Linux программирование в примерах - Арнольд Роббинс.
Комментарии