CTRACE(1)
НАЗВАНИЕ
ctrace - отладчик C-программ
СИНТАКСИС
ctrace [-f функция ...] [-v функция ...] [-o] [-x] [-u] [-е]
[-lчисло_операторов] [-s] [-tчисло_переменных] [-P] [-b]
[-pцепочка_символов] [-rфайл] [файл]
ОПИСАНИЕ
Команда ctrace позволяет отслеживать выполнение C-программ, от оператора к оператору. Это напоминает исполнение процедуры shell'а с опцией -x. Отладчик ctrace читает C-программу из файла (или со стандартного ввода,
если файл не задан), вставляет функции печати текста
каждого исполняемого оператора и значений всех используемых или модифицируемых переменных, и пишет измененную программу на стандартный вывод. Результат работы
команды ctrace следует поместить во временный файл, так
как команда cc(1) не позволяет использовать каналы. Затем временный файл нужно скомпилировать и выполнить.
Перед выполнением оператора отладчик выводит его на
терминал вместе с именами и значениями всех используемых переменных, затем оператор выполняется, после чего
выдаются имена и значения переменных, модифицированных
этим оператором. Отладчик обнаруживает циклы и выключает трассировку до тех пор, пока не происходит выход из
цикла или не выполняется другая последовательность действий внутри цикла. Через каждые 1000 итераций выводятся предупреждающие сообщения, чтобы помочь обнаружить
бесконечные циклы. Трассировочная печать идет на стандартный вывод, следовательно, ее можно направить в некоторый файл для последующей обработки с помощью редактора или команд bfs(1) или tail(1).
Обычно используемые опции:
- -f функция ...
- Отслеживать только указанные функции.
- -v функция ...
- Отслеживать все функции, кроме указанных.
Имеются стандартные и дополнительные форматы вывода
значений переменных. Длинные целые и указатели всегда
распечатываются как целые со знаком. Указатели на массивы символов, если это нужно по смыслу, распечатываются еще и как цепочки символов. Символьные, короткие целые и целые значения распечатываются как целые со знаком и, если нужно, как символы. Плавающие значения
двойной точности распечатываются в экспоненциальном
формате. Можно потребовать, чтобы значения распечатывались еще и в дополнительном формате, указав следующие
опции:
-o | Восьмеричный формат. |
-x | Шестнадцатеричный формат. |
-u | Беззнаковый формат. |
-е | Формат вещественных чисел. |
Следующие опции используются только в специальных случаях:
- -lчисло_операторов
- Контролировать заданное число последовательно выполняемых операторов на предмет цикла трассировки,
а не 20, как считается по умолчанию. Чтобы полностью трассировать циклы, используйте значение 0.
- -s
- Отменить ненужную трассировку простых операторов
присваивания и вызовов функций копирования цепочек
символов. Эта опция может скрыть ошибки, вызванные
использованием операции = вместо ==.
- -tчисло_переменных
- Отслеживать заданное число_переменных для каждого
оператора, а не 10, как по умолчанию (максимальным
значением n является 20). В разделе ДИАГНОСТИКА
об ясняется, когда нужно использовать эту опцию.
- -P
- Перед выполнением трассировщика запустить препроцессор языка C. Можно использовать также опции -D,
-I и -U препроцессора cpp(1).
Следующие опции используются для обеспечения трассировки программ, которые будут выполняться не в среде операционной системы UNIX:
- -b
- Использовать для трассировки только базовые функции, то есть функции, описанные в статьях ctype(3C), printf(3S) и string(3C). Эти функции есть
даже в кросскомпиляторах для микропроцессоров. Опция -b необходима, в частности, при выполнении
трассируемых программ в операционной системе, в
которой нет функций signal(2), fflush(3S),
longjmp(3C) или setjmp(3C).
- -pцепочка_символов
- Изменить подразумеваемое значение трассировочной
функции печати printf(. Например, указание
-p'fprintf(stderr,' приведет к тому, что отладочная печать пойдет в стандартный протокол.
- -rфайл
- Использовать файл вместо пакета функций трассировки runtime.c. Это позволяет полностью изменить
функцию печати, а не только ее название и первые
аргументы, как в случае опции -p.
ПРИМЕР
Пусть файл lc.c содержит следующую C-программу:
1 #include <stdio.h>
2 main() /* Подсчет числа вводимых строк */
3 {
4 int c,nl;
5
6 nl = 0;
7 while ((c=getchar()) != EOF)
8 if (c = '\n')
9 ++nl;
10 printf ("%d\n",nl);
11}
и Вы вводите такие команды и тестовые данные:
cc lc.c
a.out
1
CTRL+D
Программа будет откомпилирована и выполнена. Результатом работы программы будет число 2, но это неверный результат, так как тестовые данные содержат только одну
строку. Ошибка в этой программе банальная, но коварная.
Если Вы вызовете отладчик ctrace с помощью команд
ctrace lc.c > temp.c
cc temp.c
a.out
то результат будет таким:
2 main()
6 nl = 0;
/* nl == 0 */
7 while ((c=getchar()) != EOF)
Теперь программа ждет ввода. Если Вы вводите те же тестовые данные, что и ранее, получится следующее:
/* c == 49 or '1' */
8 if (c = '\n')
/* c == 10 or '\n' */
9 ++nl;
/* nl == 1 */
7 while ((c=getchar()) != EOF)
/* c == 10 or '\n' */
8 if (c = '\n')
/* c == 10 or '\n' */
9 ++nl;
/* nl == 2 */
/* repeating */
/* repeated < 1 time */
7 while ((c=getchar()) != EOF)
Если теперь ввести символ конца файла, получится окончательный результат:
/* c == -1 */
10 printf ("%d\n",nl);
/* nl == 2 */ 2
/* return */
Обратите внимание на печать значения переменной nl сразу после трассировки оператора printf. Также обратите
внимание на комментарий /* return */, добавленный отладчиком ctrace в конце трассировки. Он указывает на
неявный выход из функции по достижении закрывающей
скобки.
Трассировочная печать показывает, что переменной c
присваивается значение '1' в строке 7, а в строке 8 она
уже имеет значение '\n'. Раз Вы обратили внимание на
оператор if в строке 8, то Вы, скорее всего, догадаетесь, что использовали оператор присваивания = вместо
сравнения ==. Во время простого просмотра текста программы эту ошибку легко пропустить.
Управление трассировкой во время выполнения
Стандартный режим трассировки охватывает всю программу,
если только не заданы опции -f или -v для трассировки
избранных функций. Стандартное использование отладчика
ctrace не дает возможности пооператорного управления
трассировкой, не позволяет выключать и включать трассировку во время выполнения отлаживаемой программы.
Вставляя в программу вызовы функций ctroff( ) и
ctron( ), можно, соответственно, выключать или включать
трассировку во время выполнения. Тем самым, используя
операторы if языка C, можно реализовать сколь угодно
сложный способ управления трассировкой. На основании
того факта, что ctrace определяет переменную препроцессора CTRACE, реализуется условная вставка операторов
управления трассировкой, например
#ifdef CTRACE
if (c == '!" && i > 1000)
ctron ();
#endif
Если программа оттранслирована с опцией -g, функции
включения/выключения трассировки можно вызвать из отладчика
sdb(1). Например, чтобы отслеживать выполнение
всех строк главной программы, кроме интервала строк с
седьмой по десятую, введите следующие команды:
sdb a.out
main:7b ctroff()
main:11b ctron()
r
Допускается также выключение и включение трассировки
установкой значения переменной tr_ct_ в 0 или 1 соответственно. Такой способ целесообразен, если используется отладчик, который не предоставляет возможности
вызвать функции ctroff( ) и ctron( ) непосредственно.
ФАЙЛЫ
- /usr/lib/ctrace/runtime.c
- Трассировочное окружение времени выполнения.
СМ. ТАКЖЕ
bfs(1), tail(1).
signal(2), ctype(3C), fclose(3S), printf(3S),
setjmp(3C), string(3C) в Справочнике программиста.
ДИАГНОСТИКА
В этом разделе поясняются диагностические сообщения,
выдаваемые как трассировщиком ctrace, так и компилятором cc(1), поскольку трассиривочные действия часто приводит к каким-то предупреждающим сообщениям от компилятора cc(1). В редких случаях появляются и сообщения об
ошибках, но их можно избежать.
Диагностика отладчика ctrace
- warning: some variables are not traced in this statement
- В каждом операторе отслеживаются только 10 переменных, чтобы избежать ошибки C-компилятора "out
of tree space; simplify expression" (исчерпано
пространство для дерева, упростите выражение). Для
увеличения числа отслеживаемых переменных используйте опцию -t.
- warning: statement too long to trace
- Оператор имеет длину более 400 символов. Чтобы
уменьшить длину, используйте для выделения отступов символы табуляции, а не пробелы.
- cannot handle preprocessor code, use -P option
- Обычно это происходит, когда в середине C-оператора есть директивы препроцессора #ifdef/#endif или
в конце директивы препроцессора #define стоит символ точки с запятой.
- 'if...else if' sequence too long
- Упростите конструкцию, удалив ключевое слово else
из середины.
- possible syntax error, try -P option
- Попробуйте использовать опцию -P для обработки исходного файла с соответствующими опциями препроцессора -D, -I, или -U. Если диагностическое сообщение не исчезло, посмотрите разделы предупреждений ниже.
Диагностика компилятора cc
- warning: illegal combination of pointer and integer
warning: statement not reached
warning: sizeof returns 0
- Не обращайте внимания.
- compiler takes size of function
- См. выше сообщение отладчика ctrace "possible syntax error".
- yacc stack overflow
- См. выше сообщение отладчика ctrace "'if...else
if' sequence too long".
- out of tree space; simplify expression
- Используйте опцию -t для уменьшения, по сравнению
с подразумеваемым значением 10, количества отслеживаемых в одном операторе переменных. Не обращайте внимания на предупреждающее сообщение "ctrace:
too many variables to trace", которое Вы получите
теперь.
- redeclaration of signal
- Либо исправьте описание функции signal(2), либо
удалите его и включите в текст файл <signal.h>.
ПРЕДОСТЕРЕЖЕНИЯ
Вы получите сообщение от отладчика ctrace о синтаксической ошибке, если опустите точку с запятой после последнего элемента описания записи или об единения, непосредственно перед правой скобкой }. Некоторые C-компиляторы не требуют этой точки с запятой.
Определение функции с таким же именем, что и у системной функции, может привести к синтаксической ошибке,
если изменено количество аргументов. Используйте лучше
другое имя.
Отладчик ctrace предполагает, что BADMAG является макросом препроцессора и что EOF и NULL являются константами, определенными с помощью директивы #define. Описание любого из этих об ектов как переменной, например
int EOF;, вызовет синтаксическую ошибку.
СЮРПРИЗЫ
Отладчик ctrace не имеет информации о компонентах
структур данных таких, как записи, об единения и массивы. Он не в состоянии выбрать формат, чтобы распечатать
компоненты структуры данных, когда происходит присваивание значения всей структуре. Отладчик может вместо
структуры распечатать ее адрес или использовать неверный формат (например, 1.23456e-123 для записи с двумя
целыми компонентами).
Указатели всегда трактуются как указатели на цепочки
символов.
Отслеживание циклов трассировки производится отдельно
для каждого файла многофайловой программы. В результате
функция, вызываемая в цикле, может продолжать трассироваться, или же некоторая функция не будет трассироваться до вызова другой функции из того же файла.
Опция -l не работает; ctrace все равно использует подразумеваемое значение 20.