Книга: Linux программирование в примерах

15.4.2.5. Добавьте специальные ловушки для контрольных точек

15.4.2.5. Добавьте специальные ловушки для контрольных точек

Часто проблема может быть воспроизводимой, но лишь после того, как программа сначала обработает многие мегабайты вводимых данных. Или, хотя вы и знаете, какая функция вызывает сбой, он возникает лишь после вызова этой функции сотни или даже тысячи раз.

Это большая проблема, когда вы работаете в отладчике. Если вы установите контрольную точку на вызывающую сбой процедуру, вам придется набирать команду continue и нажимать ENTER сотни или тысячи раз, чтобы привести программу в состояние перед сбоем. Это по меньшей мере утомительно и способствует появлению ошибок! Это может оказаться даже таким трудным, что вы захотите отказаться от этого, даже не начав.

Решение заключается в добавлении специальных отладочных функций «ловушек» («hook»), которые ваша программа может вызвать при приближении к интересующему вас состоянию.

Например, предположим, что вы знаете, что функция check_salary() вызывает сбой, но лишь когда она вызвана 1427 раз. (Мы не смеемся над вами; в свое время нам пришлось наблюдать довольно странные вещи.)

Чтобы перехватить check_salary() до того, как она завершится неудачей, создайте специальную фиктивную функцию, которая ничего не делает и просто возвращается, затем сделайте так, чтобы check_salary() вызывала ее как раз перед 1427-м своим вызовом:

/* debug_dummy --- отладочная функция-ловушка */
void debug_dummy(void) { return; }
struct salary *check_salary(void) {
 /* ...здесь описания настоящих переменных... */
 static int count = 0; /* для отладки */
 if (++count == 1426)
  debug_dummy();
 /* ...оставшаяся часть кода... */
}

Теперь из GDB установите контрольную точку в debug_dummy(), а затем запустите программу обычным способом:

(gdb) break debug_dummy /* Установить контрольную точку для фиктивной функции */
Breakpoint 1 at 0x8055885: file whizprog.c, line 3137.
(gdb) run /* Запуск программы */

По достижении контрольной точки для debug_dummy() вы можете установить вторую контрольную точку для check_salary() и продолжить исполнение:

(gdb) run /* Запуск программы */
Starting program: /home/arnold/whizprog
Breakpoint 1, debug_dummy() at whizprog.c, line 3137
3137 void debug_dummy(void) { return; } /* Достижение контрольной точки */
(gdb) break check_salary
 /* Установить контрольную точку для интересующей функции */
Breakpoint 2 at 0x8057913: file whizprog.c, line 3140.
(gdb) cont

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

Вместо использования фиксированной константы ('++count == 1426') можно использовать глобальную переменную, которая устанавливается отладчиком в любое нужное вам значение. Это дает возможность избежать перекомпилирования программы

Для gawk мы пошли на один шаг дальше и внесли возможность отладочной ловушки в язык, так что функция ловушки могла быть вызвана из программы awk. При компилировании для отладки доступна специальная ничего не делающая функция stopme(). Эта функция, в свою очередь, вызывает функцию С с тем же названием. Это позволяет нам поместить вызовы stopme() в завершающуюся неудачей программу awk непосредственно перед сбойным участком. Например, если gawk выдает ошибочные результаты для программы awk в 1200-й вводимой записи, мы можем добавить в программу awk строку, подобную этой:

NR == 1198 { stopme() } # Остановиться для отладки, когда число записей == 1198
/* ...оставшаяся часть программы как ранее... */

Затем из GDB мы можем установить контрольную точку на функции С stopme() и запустить программу awk. Когда контрольная точка срабатывает, мы можем затем установить контрольные точки на другие части gawk, где, как мы ожидаем, находится действительная проблема.

Методика функции-ловушки полезна сама по себе. Однако, возможность переместить ее на уровень приложения умножает ее полезность, и она сохранила нам бесчисленное число часов отладки при отслеживании непонятных проблем.

Оглавление книги


Генерация: 1.234. Запросов К БД/Cache: 3 / 0
поделиться
Вверх Вниз