Чтение онлайн

ЖАНРЫ

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

Роббинс Арнольд

Шрифт:

i

Идентифицирует процесс, выводящий каждую отладочную или трассировочную строку номером ID для этого процесса.

L

Помечает каждую строку вывода отладчика номером строки исходного файла, в котором находится осуществляющий вывод макрос.

о[,файл]

Перенаправляет поток вывода отладчика в указанный файл. Потоком вывода по умолчанию является

stderr
. Пустой список аргументов перенаправляет вывод в
stdout
.

t[,N]

Включает трассировку потока управления функций. Максимальная глубина

вложения определяется
N
, по умолчанию используется 200.

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

dbug
.

DBUG_EXECUTE(строка, код)

Этот макрос похож на

DBUG_PRINT
: первый аргумент является строкой, выбранной с помощью опции
d
, а второй — код для исполнения:

DBUG_EXECUTE("abort", abort);

DBUG_FILE

Это значение типа

FILE*
для использования с процедурами
<stdio.h>
. Оно позволяет осуществлять собственный вывод в поток файла отладки.

DBUG_LONGJMP(jmp_buf env, int val)

Этот макрос заключает в оболочку вызов

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

DBUG_POP

Этот макрос выталкивает из стека один уровень сохраненного состояния отладки, созданный макросом

DBUG_PUSH
. Он довольно эзотерический; вы скорее всего не будете его использовать.

DBUG_SETJMP(jmp_buf env)

Этот макрос заключает в оболочку вызов

setjmp
, принимая те же самые аргументы. Он позволяет библиотеке
dbug
обрабатывать нелокальные переходы.

В другом воплощении, в первой начинающей компании, для которой мы работали [177] , мы использовали в своем продукте библиотеку

dbug
. Она была неоценимой при разработке, а опустив
– DDBUG
в конечной сборке, мы смогли построить готовую версию без других изменений исходного кода.

177

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

Чтобы извлечь максимальную выгоду от библиотеки

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

Мы нашли, что библиотека

dbug
является удачным дополнением к внешним отладчикам, таким, как GDB; она обеспечивает организованный и последовательный способ применения поддержки к коду С. Она также
довольно элегантно сочетает многие из методик, которые мы ранее в данной главе очертили отдельно. Особенно полезна особенность динамической трассировки вызовов функций, и она доказывает свою бесценность в качестве помощи в изучении поведения программы, если вы незнакомы с ней.

15.5.2. Отладчики выделения памяти

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

malloc
,
realloc
и
free
).

Этот факт подкреплен большим количеством инструментов, доступных для отладки динамической памяти. Имеется значительное перекрывание того, что предлагают данные утилиты. Например:

• Обнаружение утечек памяти: память, которая выделяется, а затем становится недоступной.

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

• Обнаружение неправильных освобождений: память, которая освобождается дважды, или функции

free
передаются указатели, которые не были получены с помощью
malloc
.

• Обнаружение использования уже освобожденной памяти: память, которая освобождена, используется через висячий указатель.

• Обнаружение выхода за границы выделенной памяти: получение доступа или сохранение в память за пределами выделенной границы.

• Предупреждение об использовании неинициализированной памяти. (Многие компиляторы могут выдавать такие предупреждения.)

• Динамическая трассировка функций: когда появляется ошибочный доступ к памяти, вы получаете трассировку от того места, где память используется, до того места, где она была выделена.

• Управление инструментами посредством использования переменных окружения.

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

Некоторые утилиты просто записывают эти события. Другие организуют жуткое завершение программы приложения (посредством

SIGSEGV
), чтобы на код-нарушитель можно было точно указать из отладчика. Вдобавок, большинство спроектированы для работы вместе с GDB.

Некоторые инструменты требуют изменения исходного кода, такого, как вызов специальных функций или использование особого заголовочного файла, дополнительных

#define
и статической библиотеки. Другие работают посредством использования специального механизма библиотек общего пользования Linux/Unix для прозрачной установки себя в качестве заместителя стандартных библиотечных версий
malloc
и
free
.

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

15.5.2.1. GNU/Linux

mtrace

Системы GNU/Linux, использующие GLIBC, предоставляют две функции для включения и отключения трассировки памяти во время исполнения.

#include <mcheck.h> /* GLIBC */

void mtrace(void);

void muntrace(void);

Поделиться с друзьями: